From ad41b9af52c52b5ea1e9d8c6753f4e341ed40d67 Mon Sep 17 00:00:00 2001 From: Tuukka Lehtonen Date: Wed, 15 Nov 2017 01:21:11 +0200 Subject: [PATCH 1/1] Added org.simantics.ui.workspace.tracker for tracking workspace size Both org.simantics.filesystem.services and org.simantics.ui.workspace.tracker must be included in a product to get the trim contribution working. refs #7618 Change-Id: Iad7d7c9393ecb236700f6981c527b2e5e5f05e6b --- .../.classpath | 7 + .../.project | 28 ++ .../.settings/org.eclipse.jdt.core.prefs | 7 + .../META-INF/MANIFEST.MF | 25 ++ .../build.properties | 6 + .../fragment.e4xmi | 8 + .../plugin.xml | 29 ++ .../workspace/tracker/internal/Activator.java | 69 +++ .../IWorkspaceSizeTrackerConstants.java | 34 ++ .../internal/contributions/Messages.java | 32 ++ .../WorkspaceSizeTrackerContribution.java | 92 ++++ .../WorkspaceSizeTrackerTrim.java | 417 ++++++++++++++++++ .../contributions/messages.properties | 28 ++ .../internal/preferences/Messages.java | 23 + ...paceSizeTrackingPreferenceInitializer.java | 28 ++ .../WorkspaceSizeTrackingPreferencePage.java | 76 ++++ .../internal/preferences/messages.properties | 5 + bundles/pom.xml | 1 + .../org.simantics.sdk.feature/feature.xml | 7 + 19 files changed, 922 insertions(+) create mode 100644 bundles/org.simantics.ui.workspace.tracker/.classpath create mode 100644 bundles/org.simantics.ui.workspace.tracker/.project create mode 100644 bundles/org.simantics.ui.workspace.tracker/.settings/org.eclipse.jdt.core.prefs create mode 100644 bundles/org.simantics.ui.workspace.tracker/META-INF/MANIFEST.MF create mode 100644 bundles/org.simantics.ui.workspace.tracker/build.properties create mode 100644 bundles/org.simantics.ui.workspace.tracker/fragment.e4xmi create mode 100644 bundles/org.simantics.ui.workspace.tracker/plugin.xml create mode 100644 bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/Activator.java create mode 100644 bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/IWorkspaceSizeTrackerConstants.java create mode 100644 bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/Messages.java create mode 100644 bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/WorkspaceSizeTrackerContribution.java create mode 100644 bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/WorkspaceSizeTrackerTrim.java create mode 100644 bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/messages.properties create mode 100644 bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/Messages.java create mode 100644 bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/WorkspaceSizeTrackingPreferenceInitializer.java create mode 100644 bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/WorkspaceSizeTrackingPreferencePage.java create mode 100644 bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/messages.properties diff --git a/bundles/org.simantics.ui.workspace.tracker/.classpath b/bundles/org.simantics.ui.workspace.tracker/.classpath new file mode 100644 index 000000000..b862a296d --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/.classpath @@ -0,0 +1,7 @@ + + + + + + + diff --git a/bundles/org.simantics.ui.workspace.tracker/.project b/bundles/org.simantics.ui.workspace.tracker/.project new file mode 100644 index 000000000..264aae720 --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/.project @@ -0,0 +1,28 @@ + + + org.simantics.ui.workspace.tracker + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.pde.ManifestBuilder + + + + + org.eclipse.pde.SchemaBuilder + + + + + + org.eclipse.pde.PluginNature + org.eclipse.jdt.core.javanature + + diff --git a/bundles/org.simantics.ui.workspace.tracker/.settings/org.eclipse.jdt.core.prefs b/bundles/org.simantics.ui.workspace.tracker/.settings/org.eclipse.jdt.core.prefs new file mode 100644 index 000000000..295926d96 --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/.settings/org.eclipse.jdt.core.prefs @@ -0,0 +1,7 @@ +eclipse.preferences.version=1 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 +org.eclipse.jdt.core.compiler.compliance=1.8 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.source=1.8 diff --git a/bundles/org.simantics.ui.workspace.tracker/META-INF/MANIFEST.MF b/bundles/org.simantics.ui.workspace.tracker/META-INF/MANIFEST.MF new file mode 100644 index 000000000..50af6b722 --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/META-INF/MANIFEST.MF @@ -0,0 +1,25 @@ +Manifest-Version: 1.0 +Bundle-ManifestVersion: 2 +Bundle-Name: Workspace Size Monitoring +Bundle-SymbolicName: org.simantics.ui.workspace.tracker;singleton:=true +Bundle-Version: 1.0.0.qualifier +Bundle-Activator: org.simantics.ui.workspace.tracker.internal.Activator +Bundle-Vendor: Semantum Oy +Require-Bundle: javax.inject, + org.eclipse.osgi, + org.eclipse.jface, + org.eclipse.e4.ui.services, + org.eclipse.e4.core.di.annotations, + org.eclipse.core.runtime, + org.eclipse.e4.core.di, + org.simantics.filesystem.services, + org.slf4j.api, + org.eclipse.e4.ui.model.workbench, + org.eclipse.ui.workbench, + org.eclipse.ui, + org.eclipse.e4.core.contexts +Bundle-RequiredExecutionEnvironment: JavaSE-1.8 +Import-Package: javax.annotation;version="1.2.0", + javax.inject;version="1.0.0", + org.eclipse.e4.ui.workbench.modeling +Bundle-ActivationPolicy: lazy diff --git a/bundles/org.simantics.ui.workspace.tracker/build.properties b/bundles/org.simantics.ui.workspace.tracker/build.properties new file mode 100644 index 000000000..c8d752e60 --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/build.properties @@ -0,0 +1,6 @@ +source.. = src/ +output.. = bin/ +bin.includes = plugin.xml,\ + META-INF/,\ + .,\ + fragment.e4xmi diff --git a/bundles/org.simantics.ui.workspace.tracker/fragment.e4xmi b/bundles/org.simantics.ui.workspace.tracker/fragment.e4xmi new file mode 100644 index 000000000..7b46ab4f1 --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/fragment.e4xmi @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/bundles/org.simantics.ui.workspace.tracker/plugin.xml b/bundles/org.simantics.ui.workspace.tracker/plugin.xml new file mode 100644 index 000000000..095eef1a2 --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/plugin.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + diff --git a/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/Activator.java b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/Activator.java new file mode 100644 index 000000000..23d593c70 --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/Activator.java @@ -0,0 +1,69 @@ +package org.simantics.ui.workspace.tracker.internal; + +import org.eclipse.core.runtime.preferences.InstanceScope; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.ui.preferences.ScopedPreferenceStore; +import org.osgi.framework.BundleActivator; +import org.osgi.framework.BundleContext; +import org.osgi.util.tracker.ServiceTracker; +import org.simantics.filesystem.services.sizetracker.DirectorySizeService; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class Activator implements BundleActivator { + + private static Activator instance; + private static BundleContext context; + private ServiceTracker tracker; + private IPreferenceStore preferenceStore; + + static BundleContext getContext() { + return context; + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.BundleContext) + */ + public void start(BundleContext bundleContext) throws Exception { + Activator.instance = this; + Activator.context = bundleContext; + tracker = new ServiceTracker<>(bundleContext, DirectorySizeService.class, null); + tracker.open(); + } + + /* + * (non-Javadoc) + * @see org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext) + */ + public void stop(BundleContext bundleContext) throws Exception { + tracker.close(); + Activator.context = null; + Activator.instance = null; + } + + /** + * @return null if service is no longer available + */ + public DirectorySizeService getDirectorySizeService() { + return tracker.getService(); + } + + public BundleContext getBundleContext() { + return context; + } + + public IPreferenceStore getPreferenceStore() { + if (preferenceStore == null) { + preferenceStore = new ScopedPreferenceStore(InstanceScope.INSTANCE, context.getBundle().getSymbolicName()); + } + return preferenceStore; + } + + public static Activator getDefault() { + return instance; + } + +} diff --git a/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/IWorkspaceSizeTrackerConstants.java b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/IWorkspaceSizeTrackerConstants.java new file mode 100644 index 000000000..d8fe6dc8f --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/IWorkspaceSizeTrackerConstants.java @@ -0,0 +1,34 @@ +package org.simantics.ui.workspace.tracker.internal.contributions; + +/** + * Preference constants for the heap status. + * + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public interface IWorkspaceSizeTrackerConstants { + + String P_NODE = "org.simantics.ui.workspace.tracker"; + + /** + * Boolean preference key for whether or not to show the status bar workspace + * size monitor trim. + */ + String PREF_SHOW_MONITOR = "WorkspaceSizeTracker.showMonitor"; //$NON-NLS-1$ + + /** + * Preference key for the update interval (value in milliseconds). + */ + String PREF_UPDATE_INTERVAL = "WorkspaceSizeTracker.updateInterval"; //$NON-NLS-1$ + + /** + * Boolean preference key for whether to highlight to the user when low on disk space. + */ + String PREF_HIGHLIGHT_LOW_SPACE = "WorkspaceSizeTracker.highlightLowSpace"; //$NON-NLS-1$ + + /** + * Preference key for the low space threshold (value in megabytes). + */ + String PREF_LOW_SPACE_THRESHOLD = "WorkspaceSizeTracker.lowSpaceThreshold"; //$NON-NLS-1$ + +} diff --git a/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/Messages.java b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/Messages.java new file mode 100644 index 000000000..36769f376 --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/Messages.java @@ -0,0 +1,32 @@ +package org.simantics.ui.workspace.tracker.internal.contributions; + +import org.eclipse.osgi.util.NLS; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class Messages extends NLS { + + private static final String BUNDLE_NAME = "org.simantics.ui.workspace.tracker.internal.contributions.messages";//$NON-NLS-1$ + + //============================================================== + // Workspace size trim + + public static String WorkspaceSizeTrackerTrim_close; + public static String WorkspaceSizeTrackerTrim_status; + public static String WorkspaceSizeTrackerTrim_widthStr; + public static String WorkspaceSizeTrackerTrim_memoryToolTip; + public static String WorkspaceSizeTrackerTrim_meg; + public static String WorkspaceSizeTrackerTrim_gig; + public static String WorkspaceSizeTrackerTrim_noMark; + + public static String SetMarkAction_text; + public static String ClearMarkAction_text; + public static String ShowMaxAction_text; + + static { + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/WorkspaceSizeTrackerContribution.java b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/WorkspaceSizeTrackerContribution.java new file mode 100644 index 000000000..f393ab60d --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/WorkspaceSizeTrackerContribution.java @@ -0,0 +1,92 @@ +package org.simantics.ui.workspace.tracker.internal.contributions; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +import org.eclipse.core.runtime.IPath; +import org.eclipse.core.runtime.Platform; +import org.eclipse.e4.core.contexts.IEclipseContext; +import org.eclipse.e4.ui.model.application.MApplication; +import org.eclipse.e4.ui.model.application.ui.MUIElement; +import org.eclipse.e4.ui.model.application.ui.menu.MToolControl; +import org.eclipse.e4.ui.workbench.modeling.EModelService; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.PlatformUI; +import org.simantics.filesystem.services.sizetracker.DirectorySizeService; +import org.simantics.filesystem.services.sizetracker.SizeTracker; +import org.simantics.ui.workspace.tracker.internal.Activator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class WorkspaceSizeTrackerContribution { + + private Logger logger = LoggerFactory.getLogger(WorkspaceSizeTrackerContribution.class); + + private SizeTracker workspaceSizeTracker; + + @PostConstruct + void createControls(Composite parent, MToolControl toolControl) { + String trackSize = System.getProperty("org.simantics.filesystem.services.sizeTracker", null); + if (trackSize != null && trackSize.equalsIgnoreCase("false")) + return; + Path ws = getWorkspacePath(); + if (ws != null && !Files.isDirectory(ws)) + return; + DirectorySizeService dss = Activator.getDefault().getDirectorySizeService(); + if (dss == null) + return; + + try { + workspaceSizeTracker = dss.track(ws); + new WorkspaceSizeTrackerTrim(parent, toolControl, workspaceSizeTracker, Activator.getDefault().getPreferenceStore()); + } catch (IOException e) { + logger.error("Failed to start workspace size tracking for {}", ws, e); + } + } + + @PreDestroy + void dispose() { + try (SizeTracker t = workspaceSizeTracker) { + } catch (IOException e) { + logger.error("Failed to shutdown workspace size tracking for {}", workspaceSizeTracker, e); + } finally { + workspaceSizeTracker = null; + } + } + + private static Path getWorkspacePath() { + IPath ip = Platform.getLocation(); + return ip != null ? ip.toFile().toPath() : null; + } + + public static void showTracker(boolean show) { + IEclipseContext context = PlatformUI.getWorkbench().getService(IEclipseContext.class); + if (context == null) + return; + + EModelService modelService = context.get(EModelService.class); + MApplication app = context.get(MApplication.class); + if (modelService == null || app == null) + return; + + MUIElement element = modelService.find("org.simantics.ui.workspace.tracker.toolcontrol.0", app); + if (element != null && element.isToBeRendered() != show) { + element.setToBeRendered(show); + Object widget = element.getWidget(); + if (widget instanceof Control) { + ((Control) widget).getShell().layout(null, SWT.ALL | SWT.CHANGED | SWT.DEFER); + } + } + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/WorkspaceSizeTrackerTrim.java b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/WorkspaceSizeTrackerTrim.java new file mode 100644 index 000000000..58dca581a --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/WorkspaceSizeTrackerTrim.java @@ -0,0 +1,417 @@ +/******************************************************************************* + * Copyright (c) 2017 Association for Decentralized Information Management in + * Industry THTH ry. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Semantum Oy - initial API and implementation + *******************************************************************************/ +package org.simantics.ui.workspace.tracker.internal.contributions; + +import java.io.IOException; +import java.nio.file.FileStore; +import java.nio.file.Files; +import java.nio.file.Path; + +import org.eclipse.e4.ui.model.application.ui.menu.MToolControl; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.action.IMenuManager; +import org.eclipse.jface.action.MenuManager; +import org.eclipse.jface.preference.IPreferenceStore; +import org.eclipse.jface.util.IPropertyChangeListener; +import org.eclipse.osgi.util.NLS; +import org.eclipse.swt.SWT; +import org.eclipse.swt.graphics.Color; +import org.eclipse.swt.graphics.GC; +import org.eclipse.swt.graphics.Point; +import org.eclipse.swt.graphics.Rectangle; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.swt.widgets.Control; +import org.eclipse.swt.widgets.Display; +import org.eclipse.swt.widgets.Listener; +import org.eclipse.swt.widgets.Menu; +import org.eclipse.swt.widgets.Shell; +import org.simantics.filesystem.services.sizetracker.SizeTracker; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The Heap Status control, which shows the heap usage statistics in the window trim. + * + * @since 3.1 + */ +public class WorkspaceSizeTrackerTrim extends Composite { + + private Logger logger = LoggerFactory.getLogger(WorkspaceSizeTrackerTrim.class); + + private MToolControl toolControl; + private SizeTracker sizeTracker; + private IPreferenceStore prefStore; + + private Color bgCol, usedSpaceCol, lowSpaceCol, topLeftCol, bottomRightCol, sepCol, textCol; + @SuppressWarnings("unused") + private Color markCol; + + private int updateInterval; + + private String storeName; + private long totalSpace; + private long availableSpace; + private long usedSpace; + private long prevTotalSpace = -1L; + private long prevAvailableSpace = -1L; + private long prevUsedSpace = -1L; + + private boolean hasChanged; + private long mark = -1; + + /** + * How many MB of free disk space means we are low on disk space? + */ + private long lowSpaceThreshold = 500; + private boolean highlightLowSpace = true; + + private boolean updateTooltip = false; + + private final Runnable timer = new Runnable() { + @Override + public void run() { + if (!isDisposed()) { + safeUpdateStats(); + if (hasChanged) { + if (updateTooltip) { + updateToolTip(); + } + redraw(); + hasChanged = false; + } + getDisplay().timerExec(updateInterval, this); + } + } + }; + + private final IPropertyChangeListener prefListener = event -> { + if (IWorkspaceSizeTrackerConstants.PREF_UPDATE_INTERVAL.equals(event.getProperty())) { + setUpdateIntervalInMS(prefStore.getInt(IWorkspaceSizeTrackerConstants.PREF_UPDATE_INTERVAL)); + } else if (IWorkspaceSizeTrackerConstants.PREF_HIGHLIGHT_LOW_SPACE.equals(event.getProperty())) { + highlightLowSpace = prefStore.getBoolean(IWorkspaceSizeTrackerConstants.PREF_HIGHLIGHT_LOW_SPACE); + hasChanged = true; + } else if (IWorkspaceSizeTrackerConstants.PREF_LOW_SPACE_THRESHOLD.equals(event.getProperty())) { + lowSpaceThreshold = prefStore.getLong(IWorkspaceSizeTrackerConstants.PREF_LOW_SPACE_THRESHOLD); + hasChanged = true; + } else if (IWorkspaceSizeTrackerConstants.PREF_SHOW_MONITOR.equals(event.getProperty())) { + boolean show = prefStore.getBoolean(IWorkspaceSizeTrackerConstants.PREF_SHOW_MONITOR); + if (!show) + showTracker(false); + } + }; + + /** + * Creates a new heap status control with the given parent, and using + * the given preference store to obtain settings such as the refresh + * interval. + * @param toolControl + * + * @param parent the parent composite + * @param sizeTracker the workspace sizeTracker service + * @param prefStore the preference store + */ + public WorkspaceSizeTrackerTrim(Composite parent, MToolControl toolControl, SizeTracker sizeTracker, IPreferenceStore prefStore) { + super(parent, SWT.NONE); + this.toolControl = toolControl; + this.sizeTracker = sizeTracker; + + this.prefStore = prefStore; + prefStore.addPropertyChangeListener(prefListener); + + setUpdateIntervalInMS(prefStore.getInt(IWorkspaceSizeTrackerConstants.PREF_UPDATE_INTERVAL)); + + Display display = getDisplay(); + usedSpaceCol = display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); + lowSpaceCol = new Color(display, 255, 70, 70); // medium red + bgCol = display.getSystemColor(SWT.COLOR_WIDGET_BACKGROUND); + sepCol = topLeftCol = display.getSystemColor(SWT.COLOR_WIDGET_NORMAL_SHADOW); + bottomRightCol = display.getSystemColor(SWT.COLOR_WIDGET_HIGHLIGHT_SHADOW); + markCol = textCol = display.getSystemColor(SWT.COLOR_WIDGET_FOREGROUND); + + createContextMenu(); + + Listener listener = event -> { + switch (event.type) { + case SWT.Dispose: + doDispose(); + break; + case SWT.Paint: + if (event.widget == WorkspaceSizeTrackerTrim.this) { + paintComposite(event.gc); + } + break; + case SWT.MouseDown: + if (event.button == 1) { + if (event.widget == WorkspaceSizeTrackerTrim.this) { + setMark(); + } + } + break; + case SWT.MouseEnter: + WorkspaceSizeTrackerTrim.this.updateTooltip = true; + updateToolTip(); + break; + case SWT.MouseExit: + if (event.widget == WorkspaceSizeTrackerTrim.this) { + WorkspaceSizeTrackerTrim.this.updateTooltip = false; + } + break; + } + }; + addListener(SWT.Dispose, listener); + addListener(SWT.MouseDown, listener); + addListener(SWT.Paint, listener); + addListener(SWT.MouseEnter, listener); + addListener(SWT.MouseExit, listener); + + // make sure stats are updated before first paint + safeUpdateStats(); + + getDisplay().asyncExec(() -> { + if (!isDisposed()) { + getDisplay().timerExec(updateInterval, timer); + } + }); + } + + @Override + public void setBackground(Color color) { + bgCol = color; + } + + @Override + public void setForeground(Color color) { + if (color == null) { + markCol = textCol = getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND); + } else { + markCol = textCol = color; + } + } + + @Override + public Color getForeground() { + if (usedSpaceCol != null) { + return usedSpaceCol; + } + return getDisplay().getSystemColor(SWT.COLOR_INFO_BACKGROUND); + } + + private void setUpdateIntervalInMS(int interval) { + updateInterval = Math.max(100, interval); + } + + private void doDispose() { + prefStore.removePropertyChangeListener(prefListener); + if (lowSpaceCol != null) { + lowSpaceCol.dispose(); + } + } + + @Override + public Point computeSize(int wHint, int hHint, boolean changed) { + GC gc = new GC(this); + Point p = gc.textExtent(Messages.WorkspaceSizeTrackerTrim_widthStr); + int height = p.y + 4; + gc.dispose(); + return new Point(p.x, height); + } + + /** + * Creates the context menu + */ + private void createContextMenu() { + MenuManager menuMgr = new MenuManager(); + menuMgr.setRemoveAllWhenShown(true); + menuMgr.addMenuListener(menuMgr1 -> fillMenu(menuMgr1)); + Menu menu = menuMgr.createContextMenu(this); + setMenu(menu); + } + + private void fillMenu(IMenuManager menuMgr) { + menuMgr.add(new SetMarkAction()); + menuMgr.add(new ClearMarkAction()); + menuMgr.add(new CloseSizeTrackerTrimAction()); + } + + /** + * Sets the mark to the current usedMem level. + */ + private void setMark() { + safeUpdateStats(); // get up-to-date stats before taking the mark + mark = usedSpace; + hasChanged = true; + redraw(); + } + + /** + * Clears the mark. + */ + private void clearMark() { + mark = -1; + hasChanged = true; + redraw(); + } + + private void paintComposite(GC gc) { + paintCompositeMaxUnknown(gc); + } + + private void paintCompositeMaxUnknown(GC gc) { + Rectangle rect = getClientArea(); + int x = rect.x; + int y = rect.y; + int w = rect.width; + int h = rect.height; + int sw = w - 1; // status width + long storeUsedSpace = totalSpace - availableSpace; + int uw = (int) (sw * storeUsedSpace / totalSpace); // used space width + int ux = x + 1 + uw; // used space right edge + if (bgCol != null) { + gc.setBackground(bgCol); + } + gc.fillRectangle(rect); + + boolean lowOnSpace = false; + if (highlightLowSpace) { + lowOnSpace = (1024L*1024L*lowSpaceThreshold) >= availableSpace; + } + + gc.setForeground(sepCol); + gc.drawLine(ux, y, ux, y + h); + gc.setForeground(topLeftCol); + gc.drawLine(x, y, x+w, y); + gc.drawLine(x, y, x, y+h); + gc.setForeground(bottomRightCol); + gc.drawLine(x+w-1, y, x+w-1, y+h); + gc.drawLine(x, y+h-1, x+w, y+h-1); + + gc.setBackground(lowOnSpace ? lowSpaceCol : usedSpaceCol); + gc.fillRectangle(x + 1, y + 1, uw, h - 2); + + String s = NLS.bind(Messages.WorkspaceSizeTrackerTrim_status, convertToSizeString(usedSpace), convertToSizeString(availableSpace)); + Point p = gc.textExtent(s); + int sx = (rect.width - 15 - p.x) / 2 + rect.x + 1; + int sy = (rect.height - 2 - p.y) / 2 + rect.y + 1; + gc.setForeground(textCol); + gc.drawString(s, sx, sy, true); + } + + private void safeUpdateStats() { + try { + updateStats(); + } catch (IOException e) { + logger.error("Failed to update workspace size statistics.", e); + } + } + + private void updateStats() throws IOException { + Path path = sizeTracker.path(); + FileStore store = Files.getFileStore(path); + + storeName = store.toString(); + totalSpace = store.getTotalSpace(); + availableSpace = store.getUsableSpace(); + usedSpace = sizeTracker.size(); + + if (convertToMeg(prevTotalSpace) != convertToMeg(totalSpace)) { + prevTotalSpace = totalSpace; + this.hasChanged = true; + } + if (prevAvailableSpace != availableSpace) { + prevAvailableSpace = availableSpace; + this.hasChanged = true; + } + if (convertToMeg(prevUsedSpace) != convertToMeg(usedSpace)) { + prevUsedSpace = usedSpace; + this.hasChanged = true; + } + } + + private void updateToolTip() { + String usedStr = convertToSizeString(usedSpace); + String availableStr = convertToSizeString(availableSpace); + String totalStr = convertToSizeString(totalSpace); + String markStr = mark == -1 ? Messages.WorkspaceSizeTrackerTrim_noMark : convertToSizeString(mark); + String toolTip = NLS.bind(Messages.WorkspaceSizeTrackerTrim_memoryToolTip, new Object[] { usedStr, storeName, availableStr, totalStr, markStr }); + if (!toolTip.equals(getToolTipText())) { + setToolTipText(toolTip); + } + } + + /** + * Converts the given number of bytes to a printable number of megabytes (rounded up). + */ + private String convertToSizeString(long numBytes) { + long megs = convertToMeg(numBytes); + if (megs > 10000) { + double megsd = (double) megs; + long gigs = (long) Math.floor(megsd / 1024.0); + long decimals = (long) (megsd - gigs*1024); + decimals = (decimals + 5) / 10; + return NLS.bind(Messages.WorkspaceSizeTrackerTrim_gig, new Long(gigs), new Long(decimals)); + } else { + return NLS.bind(Messages.WorkspaceSizeTrackerTrim_meg, new Long(megs)); + } + } + + /** + * Converts the given number of bytes to the corresponding number of megabytes (rounded up). + */ + private long convertToMeg(long numBytes) { + return (numBytes + (512 * 1024)) / (1024 * 1024); + } + + class SetMarkAction extends Action { + SetMarkAction() { + super(Messages.SetMarkAction_text); + } + + @Override + public void run() { + setMark(); + } + } + + class ClearMarkAction extends Action { + ClearMarkAction() { + super(Messages.ClearMarkAction_text); + } + + @Override + public void run() { + clearMark(); + } + } + + class CloseSizeTrackerTrimAction extends Action{ + CloseSizeTrackerTrimAction(){ + super(Messages.WorkspaceSizeTrackerTrim_close); + } + + @Override + public void run(){ + showTracker(false); + } + } + + private void showTracker(boolean show) { + if (toolControl.isToBeRendered() != show) { + Object widget = toolControl.getWidget(); + Shell shell = widget instanceof Control ? ((Control) widget).getShell() : null; + toolControl.setToBeRendered(show); + if (shell != null) + shell.layout(null, SWT.ALL | SWT.CHANGED | SWT.DEFER); + prefStore.setValue(IWorkspaceSizeTrackerConstants.PREF_SHOW_MONITOR, show); + } + } + +} \ No newline at end of file diff --git a/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/messages.properties b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/messages.properties new file mode 100644 index 000000000..d14059f60 --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/messages.properties @@ -0,0 +1,28 @@ +############################################################################### +# Copyright (c) 2017 Association for Decentralized Information Management in +# Industry THTH ry. +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# +# Contributors: +# Semantum Oy - initial API and implementation +############################################################################### + +# package: org.simantics.ui.workspace.tracker.internal.contributions + +#============================================================== +# Workspace Size Tracker + +WorkspaceSizeTrackerTrim_close=&Close +WorkspaceSizeTrackerTrim_status={0} / {1} +WorkspaceSizeTrackerTrim_widthStr=MMMMMMMMMMMM +WorkspaceSizeTrackerTrim_memoryToolTip=Workspace size: {0} {1} free/total space: {2}/{3} mark: {4} +WorkspaceSizeTrackerTrim_meg={0}M +WorkspaceSizeTrackerTrim_gig={0}.{1}G +WorkspaceSizeTrackerTrim_noMark= + +SetMarkAction_text=&Set Mark +ClearMarkAction_text=&Clear Mark +ShowMaxAction_text=Show &Max Size diff --git a/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/Messages.java b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/Messages.java new file mode 100644 index 000000000..34da9aa22 --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/Messages.java @@ -0,0 +1,23 @@ +package org.simantics.ui.workspace.tracker.internal.preferences; + +import org.eclipse.osgi.util.NLS; + +/** + * @author Tuukka Lehtonen + */ +public class Messages extends NLS { + + private static final String BUNDLE_NAME = "org.simantics.ui.workspace.tracker.internal.preferences.messages";//$NON-NLS-1$ + + public static String WorkspaceSizeTrackingPreferencePage_Workspace_Size_Tracking_Settings; + public static String WorkspaceSizeTrackingPreferencePage_Show_Monitor; + public static String WorkspaceSizeTrackingPreferencePage_Update_Interval; + public static String WorkspaceSizeTrackingPreferencePage_Highlight_Low_Space; + public static String WorkspaceSizeTrackingPreferencePage_Low_Space_Threshold; + + static { + // load message values from bundle file + NLS.initializeMessages(BUNDLE_NAME, Messages.class); + } + +} diff --git a/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/WorkspaceSizeTrackingPreferenceInitializer.java b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/WorkspaceSizeTrackingPreferenceInitializer.java new file mode 100644 index 000000000..27a620e50 --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/WorkspaceSizeTrackingPreferenceInitializer.java @@ -0,0 +1,28 @@ +package org.simantics.ui.workspace.tracker.internal.preferences; + +import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer; +import org.eclipse.core.runtime.preferences.DefaultScope; +import org.eclipse.core.runtime.preferences.IScopeContext; +import org.osgi.service.prefs.Preferences; +import org.simantics.ui.workspace.tracker.internal.contributions.IWorkspaceSizeTrackerConstants; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class WorkspaceSizeTrackingPreferenceInitializer extends AbstractPreferenceInitializer { + + public WorkspaceSizeTrackingPreferenceInitializer() { + } + + @Override + public void initializeDefaultPreferences() { + IScopeContext context = DefaultScope.INSTANCE; + Preferences node = context.getNode(IWorkspaceSizeTrackerConstants.P_NODE); + node.putBoolean(IWorkspaceSizeTrackerConstants.PREF_SHOW_MONITOR, true); + node.putInt(IWorkspaceSizeTrackerConstants.PREF_UPDATE_INTERVAL, 1000); + node.putBoolean(IWorkspaceSizeTrackerConstants.PREF_HIGHLIGHT_LOW_SPACE, true); + node.putLong(IWorkspaceSizeTrackerConstants.PREF_LOW_SPACE_THRESHOLD, 500); + } + +} diff --git a/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/WorkspaceSizeTrackingPreferencePage.java b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/WorkspaceSizeTrackingPreferencePage.java new file mode 100644 index 000000000..447bd543b --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/WorkspaceSizeTrackingPreferencePage.java @@ -0,0 +1,76 @@ +package org.simantics.ui.workspace.tracker.internal.preferences; + +import org.eclipse.jface.preference.BooleanFieldEditor; +import org.eclipse.jface.preference.FieldEditorPreferencePage; +import org.eclipse.jface.preference.IntegerFieldEditor; +import org.eclipse.swt.SWT; +import org.eclipse.swt.widgets.Composite; +import org.eclipse.ui.IWorkbench; +import org.eclipse.ui.IWorkbenchPreferencePage; +import org.simantics.ui.workspace.tracker.internal.Activator; +import org.simantics.ui.workspace.tracker.internal.contributions.IWorkspaceSizeTrackerConstants; +import org.simantics.ui.workspace.tracker.internal.contributions.WorkspaceSizeTrackerContribution; + +/** + * @author Tuukka Lehtonen + * @since 1.31.0 + */ +public class WorkspaceSizeTrackingPreferencePage extends FieldEditorPreferencePage implements IWorkbenchPreferencePage { + + private BooleanFieldEditor fShowSizeMonitor; + private IntegerFieldEditor fUpdateInterval; + private BooleanFieldEditor fHighlightLowSpace; + private IntegerFieldEditor fLowSpaceThreshold; + + /** + * Create the console page. + */ + public WorkspaceSizeTrackingPreferencePage() { + super(GRID); + setDescription(Messages.WorkspaceSizeTrackingPreferencePage_Workspace_Size_Tracking_Settings); + setPreferenceStore(Activator.getDefault().getPreferenceStore()); + } + + /* (non-Javadoc) + * @see org.eclipse.jface.preference.PreferencePage#createControl(Composite) + */ + @Override + public void createControl(Composite parent) { + super.createControl(parent); + } + + /** + * Create all field editors for this page + */ + @Override + public void createFieldEditors() { + fShowSizeMonitor = new BooleanFieldEditor(IWorkspaceSizeTrackerConstants.PREF_SHOW_MONITOR, Messages.WorkspaceSizeTrackingPreferencePage_Show_Monitor, SWT.NONE, getFieldEditorParent()); + addField(fShowSizeMonitor); + fUpdateInterval = new IntegerFieldEditor(IWorkspaceSizeTrackerConstants.PREF_UPDATE_INTERVAL, Messages.WorkspaceSizeTrackingPreferencePage_Update_Interval, getFieldEditorParent()); + fUpdateInterval.setValidRange(100, 10000); + addField(fUpdateInterval); + fHighlightLowSpace = new BooleanFieldEditor(IWorkspaceSizeTrackerConstants.PREF_HIGHLIGHT_LOW_SPACE, Messages.WorkspaceSizeTrackingPreferencePage_Highlight_Low_Space, SWT.NONE, getFieldEditorParent()); + addField(fHighlightLowSpace); + fLowSpaceThreshold = new IntegerFieldEditor(IWorkspaceSizeTrackerConstants.PREF_LOW_SPACE_THRESHOLD, Messages.WorkspaceSizeTrackingPreferencePage_Low_Space_Threshold, getFieldEditorParent()); + fLowSpaceThreshold.setValidRange(100, 500000); + addField(fLowSpaceThreshold); + } + + /* (non-Javadoc) + * @see org.eclipse.ui.IWorkbenchPreferencePage#init(org.eclipse.ui.IWorkbench) + */ + @Override + public void init(IWorkbench workbench) { + } + + /* (non-Javadoc) + * @see org.eclipse.jface.preference.FieldEditorPreferencePage#performOk() + */ + @Override + public boolean performOk() { + boolean show = fShowSizeMonitor.getBooleanValue(); + WorkspaceSizeTrackerContribution.showTracker(show); + return super.performOk(); + } + +} diff --git a/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/messages.properties b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/messages.properties new file mode 100644 index 000000000..0f1d01d51 --- /dev/null +++ b/bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/messages.properties @@ -0,0 +1,5 @@ +WorkspaceSizeTrackingPreferencePage_Workspace_Size_Tracking_Settings=Workspace Size Tracking Settings +WorkspaceSizeTrackingPreferencePage_Show_Monitor=Sho&w workspace size monitor in status bar +WorkspaceSizeTrackingPreferencePage_Update_Interval=Monitor &update interval (ms) +WorkspaceSizeTrackingPreferencePage_Highlight_Low_Space=Highlight low disk space +WorkspaceSizeTrackingPreferencePage_Low_Space_Threshold=Low disk space threshold (MB) diff --git a/bundles/pom.xml b/bundles/pom.xml index 04328c95b..6631fd69e 100644 --- a/bundles/pom.xml +++ b/bundles/pom.xml @@ -220,6 +220,7 @@ org.simantics.threadlog org.simantics.trend org.simantics.ui + org.simantics.ui.workspace.tracker org.simantics.user.ontology org.simantics.utils org.simantics.utils.datastructures diff --git a/features/org.simantics.sdk.feature/feature.xml b/features/org.simantics.sdk.feature/feature.xml index 7a6d287ff..b022f19b2 100644 --- a/features/org.simantics.sdk.feature/feature.xml +++ b/features/org.simantics.sdk.feature/feature.xml @@ -221,6 +221,13 @@ version="0.0.0" unpack="false"/> + +