/**
* Copyright 2010 The University of North Carolina at Chapel Hill
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package staging.plugin.views;
import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.nio.file.FileStore;
import java.nio.file.Files;
import java.nio.file.Paths;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.ColumnViewerToolTipSupport;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.jface.viewers.TableViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.jface.window.ToolTip;
import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.DirectoryDialog;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ViewPart;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import staging.plugin.StagingPlugin;
import edu.unc.lib.staging.SharedStagingArea;
import edu.unc.lib.staging.StagingArea;
import edu.unc.lib.staging.StagingException;
/**
* This sample class demonstrates how to plug-in a new workbench view. The view
* shows data obtained from the model. The sample creates a dummy model on the
* fly, but a real implementation would connect to the model available either in
* this or another plug-in (e.g. the workspace). The view is connected to the
* model using a content provider.
* <p>
* The view uses a label provider to define how model objects should be
* presented in the view. Each view can present the same model objects using
* different labels and icons, if needed. Alternatively, a single label provider
* can be shared between views in order to ensure that objects of the same type
* are presented in the same way everywhere.
* <p>
*/
public class StagingAreasView extends ViewPart {
private static final Logger log = LoggerFactory.getLogger(StagingAreasView.class);
/**
* The ID of the view as specified by the extension.
*/
public static final String ID = "staging.plugin.views.StagingAreasView";
private TableViewer viewer;
private static final int NAME_COL = 0;
private static final int STATUS_COL = 1;
private static final int BASE_URI_COL = 2;
private static final int WRITABLE_COL = 3;
private Action actionReloadConfiguration;
private Action actionConnect;
private ImageDescriptor imageDescrRefresh = StagingPlugin.imageDescriptorFromPlugin(StagingPlugin.PLUGIN_ID, "icons/refresh.gif");
private Image imageConnected = PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_ELCL_SYNCED).createImage();
private Image imageDisconnected = PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_ELCL_SYNCED_DISABLED).createImage();
/*
* The content provider class is responsible for providing objects to the
* view. It can wrap existing objects in adapters or simply return objects
* as-is. These objects may be sensitive to the current input of the view,
* or ignore it and always show the same content (like Task List, for
* example).
*/
class ViewContentProvider implements IStructuredContentProvider {
public void inputChanged(Viewer v, Object oldInput, Object newInput) {
}
public void dispose() {
}
public Object[] getElements(Object parent) {
return StagingPlugin.getDefault().getStages().getAllAreas()
.values().toArray();
}
}
class ViewLabelProvider extends LabelProvider implements
ITableLabelProvider {
public String getColumnText(Object obj, int index) {
StagingArea stage = (StagingArea) obj;
switch (index) {
case NAME_COL:
return stage.getName();
case BASE_URI_COL:
return stage.getURI().toString();
case STATUS_COL:
return stage.isConnected() ? "connected" : "";
case WRITABLE_COL:
return stage.isReadOnly() ? "no" : "yes";
}
return "";
}
public Image getColumnImage(Object obj, int index) {
return getImage(obj);
}
public Image getImage(Object obj) {
return PlatformUI.getWorkbench().getSharedImages()
.getImage(ISharedImages.IMG_OBJ_ELEMENT);
}
}
class NameSorter extends ViewerSorter {
@Override
public int compare(Viewer viewer, Object e1, Object e2) {
String s1 = ((SharedStagingArea)e1).getName();
String s2 = ((SharedStagingArea)e2).getName();
return super.compare(viewer, s1, s2);
}
}
/**
* The constructor.
*/
public StagingAreasView() {
}
/**
* This is a callback that will allow us to create the viewer and initialize
* it.
*/
public void createPartControl(Composite parent) {
viewer = new TableViewer(parent, SWT.SINGLE | SWT.H_SCROLL
| SWT.V_SCROLL);
ViewLabelProvider labelProvider = new ViewLabelProvider();
createColumns(parent, labelProvider);
viewer.setContentProvider(new ViewContentProvider());
//viewer.setLabelProvider(labelProvider);
viewer.setSorter(new NameSorter());
viewer.setInput(getViewSite());
viewer.getTable().setLinesVisible(true);
viewer.getTable().setHeaderVisible(true);
ColumnViewerToolTipSupport.enableFor(viewer, ToolTip.NO_RECREATE);
// Create the help context id for the viewer's control
PlatformUI.getWorkbench().getHelpSystem()
.setHelp(viewer.getControl(), "staging.plugin.viewer");
makeActions();
hookContextMenu();
hookDoubleClickAction();
contributeToActionBars();
viewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
log.debug("Selection changed:"+viewer.getSelection().isEmpty());
IStructuredSelection sel = (IStructuredSelection)viewer.getSelection();
actionConnect.setEnabled(sel.getFirstElement() != null);
}
});
}
private void createColumns(Composite parent, ViewLabelProvider labelProvider) {
TableViewerColumn nameCol = createTableViewerColumn("Name", 200, 0);
nameCol.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object element) {
return ((StagingArea)element).getName();
}
});
TableViewerColumn statusCol = createTableViewerColumn("Status", 100, 1);
statusCol.setLabelProvider(new ColumnLabelProvider() {
@Override
public Image getImage(Object element) {
boolean conn = ((StagingArea)element).isConnected();
if(conn) {
return imageConnected;
} else {
return imageDisconnected;
}
}
@Override
public String getText(Object element) {
return ((StagingArea)element).getStatus();
}
@Override
public String getToolTipText(Object element) {
return getAreaTooltip(element);
}
});
TableViewerColumn spaceCol = createTableViewerColumn("Space", 50, 2);
spaceCol.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object element) {
StagingArea a = (StagingArea)element;
String result = "";
if(a.isConnected() && a.getScheme() != null) {
URI storage = a.getConnectedStorageURI();
try {
FileStore fs = Files.getFileStore(Paths.get(storage));
result = humanReadableByteCount(fs.getUnallocatedSpace(), true);
} catch (IOException e) {
}
}
return result;
}
@Override
public Color getForeground(Object element) {
Color result = super.getForeground(element);
StagingArea a = (StagingArea)element;
if(a.isConnected() && a.getScheme() != null) {
URI storage = a.getConnectedStorageURI();
try {
FileStore fs = Files.getFileStore(Paths.get(storage));
long bytes = fs.getUnallocatedSpace();
if(bytes < 10 * 1024 * 1024) { // 10 GB is red
return Display.getCurrent().getSystemColor(SWT.COLOR_DARK_RED);
} else if(bytes < 100 * 1024 * 1024) { // 100GB is yellow
return Display.getCurrent().getSystemColor(SWT.COLOR_DARK_YELLOW);
}
} catch (IOException e) {
}
}
return result;
}
@Override
public String getToolTipText(Object element) {
return getAreaTooltip(element);
}
});
TableViewerColumn uriCol = createTableViewerColumn("URI", 300, 3);
uriCol.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object element) {
return ((StagingArea)element).getURI().toString();
}
@Override
public String getToolTipText(Object element) {
return getAreaTooltip(element);
}
});
TableViewerColumn writableCol = createTableViewerColumn("Writable", 150, 4);
writableCol.setLabelProvider(new ColumnLabelProvider() {
@Override
public String getText(Object element) {
return ((StagingArea)element).isReadOnly() ? "no" : "yes";
}
@Override
public String getToolTipText(Object element) {
return getAreaTooltip(element);
}
});
}
private String getAreaTooltip(Object element) {
StagingArea area = (StagingArea)element;
StringBuilder sb = new StringBuilder();
sb.append(area.getName()).append("\n");
sb.append(area.getURI()).append("\n");
sb.append(area.getStatus()).append("\n");
if(area.isConnected() && area.getConnectedStorageURI() != null) {
sb.append("\nmapped to ").append(area.getConnectedStorageURI().getPath()).append("\n");
}
sb.append( area.isReadOnly() ? "Read Only: can capture existing files" : "Writable: can stage any files" );
return sb.toString();
}
public void refreshView() {
if(this.viewer != null) {
viewer.refresh();
}
}
private TableViewerColumn createTableViewerColumn(String title, int bound,
final int colNumber) {
final TableViewerColumn viewerColumn = new TableViewerColumn(viewer,
SWT.NONE);
final TableColumn column = viewerColumn.getColumn();
column.setText(title);
column.setWidth(bound);
column.setResizable(true);
column.setMoveable(true);
return viewerColumn;
}
private void hookContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu");
menuMgr.setRemoveAllWhenShown(true);
menuMgr.addMenuListener(new IMenuListener() {
public void menuAboutToShow(IMenuManager manager) {
StagingAreasView.this.fillContextMenu(manager);
}
});
Menu menu = menuMgr.createContextMenu(viewer.getControl());
viewer.getControl().setMenu(menu);
getSite().registerContextMenu(menuMgr, viewer);
}
private void contributeToActionBars() {
IActionBars bars = getViewSite().getActionBars();
fillLocalPullDown(bars.getMenuManager());
fillLocalToolBar(bars.getToolBarManager());
}
private void fillLocalPullDown(IMenuManager manager) {
manager.add(actionReloadConfiguration);
}
private void fillContextMenu(IMenuManager manager) {
// Other plug-ins can contribute there actions here
//manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
}
private void fillLocalToolBar(IToolBarManager manager) {
manager.add(actionReloadConfiguration);
//manager.add(actionConnect);
}
private void makeActions() {
actionReloadConfiguration = new Action() {
public void run() {
try {
StagingPlugin.getDefault().loadStages();
showMessage("Repository staging configuration reloaded.");
} catch (Exception e) {
showMessage("Problem reloading repository staging configuration: "
+ e.getMessage());
}
}
};
actionReloadConfiguration.setText("Reload configuration");
actionReloadConfiguration
.setToolTipText("Update staging areas for your repositories.");
actionReloadConfiguration.setImageDescriptor(imageDescrRefresh);
actionConnect = new Action() {
public void run() {
IStructuredSelection sel = (IStructuredSelection) viewer.getSelection();
if(sel.isEmpty()) return;
SharedStagingArea stage = (SharedStagingArea)sel.getFirstElement();
StagingPlugin.getDefault().getStages().connect(stage.getURI());
if (!stage.isConnected()
&& stage.getUriPattern().isLocallyMapped()) {
DirectoryDialog d = new DirectoryDialog(viewer.getTable()
.getShell(), SWT.OPEN);
String path = d.open();
if (path != null) {
File f = new File(path);
try {
URI url = f.toURI();
StagingPlugin.getDefault().getStages()
.setStorageMapping(stage.getURI(), url);
} catch (StagingException ignored) {
}
StagingPlugin.getDefault().saveConfig();
StagingPlugin.getDefault().getStages()
.connect(stage.getURI());
}
}
}
@Override
public boolean isEnabled() {
IStructuredSelection sel = (IStructuredSelection)viewer.getSelection();
return sel.getFirstElement() != null;
}
};
actionConnect.setText("Connect");
actionConnect.setToolTipText("Connect this staging area.");
actionConnect.setImageDescriptor(PlatformUI.getWorkbench().getSharedImages().getImageDescriptor(ISharedImages.IMG_ELCL_SYNCED));
}
private void hookDoubleClickAction() {
viewer.addDoubleClickListener(new IDoubleClickListener() {
public void doubleClick(DoubleClickEvent event) {
actionConnect.run();
}
});
}
private void showMessage(String message) {
MessageDialog.openInformation(viewer.getControl().getShell(),
"Staging Areas", message);
}
/**
* Passing the focus request to the viewer's control.
*/
public void setFocus() {
viewer.getControl().setFocus();
}
public static String humanReadableByteCount(long bytes, boolean si) {
int unit = si ? 1000 : 1024;
if (bytes < unit) return bytes + " B";
int exp = (int) (Math.log(bytes) / Math.log(unit));
String pre = (si ? "kMGTPE" : "KMGTPE").charAt(exp-1) + (si ? "" : "i");
return String.format("%.1f %sB", bytes / Math.pow(unit, exp), pre);
}
}