Added org.simantics.ui.workspace.tracker for tracking workspace size 22/1222/3
authorTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Tue, 14 Nov 2017 23:21:11 +0000 (01:21 +0200)
committerTuukka Lehtonen <tuukka.lehtonen@semantum.fi>
Tue, 14 Nov 2017 23:52:38 +0000 (02:52 +0300)
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

19 files changed:
bundles/org.simantics.ui.workspace.tracker/.classpath [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/.project [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/.settings/org.eclipse.jdt.core.prefs [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/META-INF/MANIFEST.MF [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/build.properties [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/fragment.e4xmi [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/plugin.xml [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/Activator.java [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/IWorkspaceSizeTrackerConstants.java [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/Messages.java [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/WorkspaceSizeTrackerContribution.java [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/WorkspaceSizeTrackerTrim.java [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/contributions/messages.properties [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/Messages.java [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/WorkspaceSizeTrackingPreferenceInitializer.java [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/WorkspaceSizeTrackingPreferencePage.java [new file with mode: 0644]
bundles/org.simantics.ui.workspace.tracker/src/org/simantics/ui/workspace/tracker/internal/preferences/messages.properties [new file with mode: 0644]
bundles/pom.xml
features/org.simantics.sdk.feature/feature.xml

diff --git a/bundles/org.simantics.ui.workspace.tracker/.classpath b/bundles/org.simantics.ui.workspace.tracker/.classpath
new file mode 100644 (file)
index 0000000..b862a29
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<classpath>\r
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>\r
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
+       <classpathentry kind="src" path="src"/>\r
+       <classpathentry kind="output" path="bin"/>\r
+</classpath>\r
diff --git a/bundles/org.simantics.ui.workspace.tracker/.project b/bundles/org.simantics.ui.workspace.tracker/.project
new file mode 100644 (file)
index 0000000..264aae7
--- /dev/null
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>\r
+<projectDescription>\r
+       <name>org.simantics.ui.workspace.tracker</name>\r
+       <comment></comment>\r
+       <projects>\r
+       </projects>\r
+       <buildSpec>\r
+               <buildCommand>\r
+                       <name>org.eclipse.jdt.core.javabuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.ManifestBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+               <buildCommand>\r
+                       <name>org.eclipse.pde.SchemaBuilder</name>\r
+                       <arguments>\r
+                       </arguments>\r
+               </buildCommand>\r
+       </buildSpec>\r
+       <natures>\r
+               <nature>org.eclipse.pde.PluginNature</nature>\r
+               <nature>org.eclipse.jdt.core.javanature</nature>\r
+       </natures>\r
+</projectDescription>\r
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 (file)
index 0000000..295926d
--- /dev/null
@@ -0,0 +1,7 @@
+eclipse.preferences.version=1\r
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled\r
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8\r
+org.eclipse.jdt.core.compiler.compliance=1.8\r
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error\r
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error\r
+org.eclipse.jdt.core.compiler.source=1.8\r
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 (file)
index 0000000..50af6b7
--- /dev/null
@@ -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 (file)
index 0000000..c8d752e
--- /dev/null
@@ -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 (file)
index 0000000..7b46ab4
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="ASCII"?>\r
+<fragment:ModelFragments xmi:version="2.0" xmlns:xmi="http://www.omg.org/XMI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:fragment="http://www.eclipse.org/ui/2010/UIModel/fragment" xmlns:menu="http://www.eclipse.org/ui/2010/UIModel/application/ui/menu" xmi:id="_BxaXACerEeWxCPrV0pAZQQ">\r
+  <fragments xsi:type="fragment:StringModelFragment" xmi:id="_wcLoQMX-Eea_bKDmo1phvA" featurename="trimContributions" parentElementId="xpath:/">\r
+    <elements xsi:type="menu:TrimContribution" xmi:id="_z1UuUMX-Eea_bKDmo1phvA" elementId="org.simantics.ui.workspace.tracker.trimcontribution.0" parentId="org.eclipse.ui.trim.status" positionInParent="after=additions">\r
+      <children xsi:type="menu:ToolControl" xmi:id="_Ch72IMfsEeeUz6Cs9kKeKg" elementId="org.simantics.ui.workspace.tracker.toolcontrol.0" contributionURI="bundleclass://org.simantics.ui.workspace.tracker/org.simantics.ui.workspace.tracker.internal.contributions.WorkspaceSizeTrackerContribution"/>\r
+    </elements>\r
+  </fragments>\r
+</fragment:ModelFragments>\r
diff --git a/bundles/org.simantics.ui.workspace.tracker/plugin.xml b/bundles/org.simantics.ui.workspace.tracker/plugin.xml
new file mode 100644 (file)
index 0000000..095eef1
--- /dev/null
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<?eclipse version="3.4"?>
+<plugin>
+
+   <extension
+         id="org.simantics.ui.workspace.tracker.fragment"
+         point="org.eclipse.e4.workbench.model">
+      <fragment
+            apply="initial"
+            uri="fragment.e4xmi">
+      </fragment>
+   </extension>
+   <extension
+         point="org.eclipse.ui.preferencePages">
+      <page
+            category="org.eclipse.ui.preferencePages.Workspace"
+            class="org.simantics.ui.workspace.tracker.internal.preferences.WorkspaceSizeTrackingPreferencePage"
+            id="org.simantics.ui.workspace.tracker.preferencePage"
+            name="Size Tracking">
+      </page>
+   </extension>
+   <extension
+         point="org.eclipse.core.runtime.preferences">
+      <initializer
+            class="org.simantics.ui.workspace.tracker.internal.preferences.WorkspaceSizeTrackingPreferenceInitializer">
+      </initializer>
+   </extension>
+
+</plugin>
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 (file)
index 0000000..23d593c
--- /dev/null
@@ -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<DirectorySizeService, DirectorySizeService> 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 <code>null</code> 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 (file)
index 0000000..d8fe6dc
--- /dev/null
@@ -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 (file)
index 0000000..36769f3
--- /dev/null
@@ -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 (file)
index 0000000..f393ab6
--- /dev/null
@@ -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 (file)
index 0000000..58dca58
--- /dev/null
@@ -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 (file)
index 0000000..d14059f
--- /dev/null
@@ -0,0 +1,28 @@
+###############################################################################\r
+# Copyright (c) 2017 Association for Decentralized Information Management in\r
+# Industry THTH ry.\r
+# All rights reserved. This program and the accompanying materials\r
+# are made available under the terms of the Eclipse Public License v1.0\r
+# which accompanies this distribution, and is available at\r
+# http://www.eclipse.org/legal/epl-v10.html\r
+#\r
+# Contributors:\r
+#     Semantum Oy - initial API and implementation\r
+###############################################################################\r
+\r
+# package: org.simantics.ui.workspace.tracker.internal.contributions\r
+\r
+#==============================================================\r
+# Workspace Size Tracker\r
+\r
+WorkspaceSizeTrackerTrim_close=&Close\r
+WorkspaceSizeTrackerTrim_status={0} / {1}\r
+WorkspaceSizeTrackerTrim_widthStr=MMMMMMMMMMMM\r
+WorkspaceSizeTrackerTrim_memoryToolTip=Workspace size: {0} {1} free/total space: {2}/{3} mark: {4}\r
+WorkspaceSizeTrackerTrim_meg={0}M\r
+WorkspaceSizeTrackerTrim_gig={0}.{1}G\r
+WorkspaceSizeTrackerTrim_noMark=<none>\r
+\r
+SetMarkAction_text=&Set Mark\r
+ClearMarkAction_text=&Clear Mark\r
+ShowMaxAction_text=Show &Max Size\r
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 (file)
index 0000000..34da9aa
--- /dev/null
@@ -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 (file)
index 0000000..27a620e
--- /dev/null
@@ -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 (file)
index 0000000..447bd54
--- /dev/null
@@ -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 (file)
index 0000000..0f1d01d
--- /dev/null
@@ -0,0 +1,5 @@
+WorkspaceSizeTrackingPreferencePage_Workspace_Size_Tracking_Settings=Workspace Size Tracking Settings\r
+WorkspaceSizeTrackingPreferencePage_Show_Monitor=Sho&w workspace size monitor in status bar\r
+WorkspaceSizeTrackingPreferencePage_Update_Interval=Monitor &update interval (ms)\r
+WorkspaceSizeTrackingPreferencePage_Highlight_Low_Space=Highlight low disk space\r
+WorkspaceSizeTrackingPreferencePage_Low_Space_Threshold=Low disk space threshold (MB)\r
index 04328c95be799d40b9c0645b65942ef21b5d78d3..6631fd69efb62686c54749abf575a75889f57789 100644 (file)
                <module>org.simantics.threadlog</module>
                <module>org.simantics.trend</module>
                <module>org.simantics.ui</module>
+               <module>org.simantics.ui.workspace.tracker</module>
                <module>org.simantics.user.ontology</module>
                <module>org.simantics.utils</module>
                <module>org.simantics.utils.datastructures</module>
index 7a6d287ff219ed5b4a0257dd8e94535226228f99..b022f19b233d094e1221375f6b147b386a9195ef 100644 (file)
          version="0.0.0"
          unpack="false"/>
 
+   <plugin
+         id="org.simantics.ui.workspace.tracker"
+         download-size="0"
+         install-size="0"
+         version="0.0.0"
+         unpack="false"/>
+
    <plugin
          id="org.simantics.backup.ontology"
          download-size="0"