/*
* Copyright (c) 2012, 2013 Hemanta Sapkota.
* 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:
* Hemanta Sapkota (laex.pearl@gmail.com)
*/
package com.laex.cg2d.screeneditor.views;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.StringUtils;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.draw2d.ColorConstants;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.viewers.ISelection;
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.swt.SWT;
import org.eclipse.swt.events.MouseAdapter;
import org.eclipse.swt.events.MouseEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.ISelectionListener;
import org.eclipse.ui.IWorkbenchPart;
import org.eclipse.ui.part.ViewPart;
import com.laex.cg2d.model.ILayerManager;
import com.laex.cg2d.model.SharedImages;
import com.laex.cg2d.model.model.Layer;
import com.laex.cg2d.model.model.Shape;
import com.laex.cg2d.model.model.ShapesDiagram;
import com.laex.cg2d.screeneditor.ScreenEditorUtil;
import com.laex.cg2d.screeneditor.editparts.tree.LayerTreeEP;
import com.laex.cg2d.screeneditor.model.ShapesDiagramAdapter;
/***
* LayersViewPart.
*
* @author hemantasapkota
*/
public class LayersViewPart extends ViewPart implements IAdaptable, ISelectionListener, IScreenDisposeListener {
/** The Constant ID. */
public static final String ID = "com.laex.cg2d.screeneditor.views.LayersViewPart"; //$NON-NLS-1$
/** The Constant VISIBLE_PROP. */
public static final String VISIBLE_PROP = "Visible";
/** The Constant LOCKED_PROP. */
public static final String LOCKED_PROP = "Locked";
/** The Constant NAME_PROP. */
public static final String NAME_PROP = "Name";
/** The descriptors. */
public static String[] descriptors;
static {
descriptors = new String[]
{ VISIBLE_PROP, LOCKED_PROP, NAME_PROP };
}
/**
* The Class TableLabelProvider.
*/
private class TableLabelProvider extends LabelProvider implements ITableLabelProvider {
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.viewers.ITableLabelProvider#getColumnImage(java.lang
* .Object, int)
*/
public Image getColumnImage(Object element, int columnIndex) {
return ((LayerItem) element).getImage(columnIndex);
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.viewers.ITableLabelProvider#getColumnText(java.lang
* .Object, int)
*/
public String getColumnText(Object element, int columnIndex) {
return ((LayerItem) element).getText(columnIndex);
}
}
/**
* The Class ContentProvider.
*/
private static class ContentProvider implements IStructuredContentProvider {
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.viewers.IStructuredContentProvider#getElements(java
* .lang.Object)
*/
public Object[] getElements(Object inputElement) {
List<LayerItem> lis = (List<LayerItem>) inputElement;
return lis.toArray();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.jface.viewers.IContentProvider#dispose()
*/
public void dispose() {
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.jface.viewers.IContentProvider#inputChanged(org.eclipse.jface
* .viewers.Viewer, java.lang.Object, java.lang.Object)
*/
public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
}
}
// Make LayerItem IAdaptable for handling ISelection.
/**
* The Class LayerItem.
*/
class LayerItem implements IAdaptable {
/** The id. */
int id;
/** The name. */
String name;
/** The visible. */
boolean visible;
/** The locked. */
boolean locked;
/** The reference layer. */
Layer referenceLayer;
/**
* Gets the text.
*
* @param index
* the index
* @return the text
*/
String getText(int index) {
switch (index) {
case 2:
return name;
}
return StringUtils.EMPTY;
}
/**
* Gets the image.
*
* @param index
* the index
* @return the image
*/
Image getImage(int index) {
switch (index) {
case 0:
return getEye(visible);
case 1:
return getLocked(locked);
}
return null;
}
/**
* Gets the eye.
*
* @param status
* the status
* @return the eye
*/
Image getEye(boolean status) {
if (status) {
return SharedImages.EYE_VISIBLE.createImage();
}
return SharedImages.EYE_INVISIBLE.createImage();
}
/**
* Gets the locked.
*
* @param status
* the status
* @return the locked
*/
Image getLocked(boolean status) {
if (status) {
return SharedImages.LOCKED.createImage();
}
return SharedImages.UNLOCKED.createImage();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.core.runtime.IAdaptable#getAdapter(java.lang.Class)
*/
@Override
public Object getAdapter(Class adapter) {
return null;
}
/**
* To layer.
*
* @return the layer
*/
public Layer toLayer() {
Layer l = new Layer(id, name, visible, locked);
l.setChildren(referenceLayer.getChildren());
return l;
}
}
// private Queue<LayerItem> layerItems = new LinkedList<LayerItem>();
/** The layer items. */
private List<LayerItem> layerItems = new ArrayList<LayerItem>();
/** The table. */
private Table table;
/** The table viewer. */
private TableViewer tableViewer;
/** The add action. */
private Action addAction;
/** The remove action. */
private Action removeAction;
/** The remove all action. */
private Action removeAllAction;
/** The lock action. */
private Action lockAction;
/** The visibility action. */
private Action visibilityAction;
/** The up action. */
private Action upAction;
/** The down action. */
private Action downAction;
/**
* Instantiates a new layers view part.
*/
public LayersViewPart() {
}
/**
* Disable state.
*/
private void disableState() {
layerItems.clear();
if (!tableViewer.getTable().isDisposed())
tableViewer.refresh();
addAction.setEnabled(false);
lockAction.setEnabled(false);
visibilityAction.setEnabled(false);
removeAction.setEnabled(false);
removeAllAction.setEnabled(false);
upAction.setEnabled(false);
downAction.setEnabled(false);
}
/**
* Enable state.
*/
private void enableState() {
addAction.setEnabled(true);
lockAction.setEnabled(true);
visibilityAction.setEnabled(true);
removeAction.setEnabled(true);
removeAllAction.setEnabled(true);
upAction.setEnabled(true);
downAction.setEnabled(true);
}
/**
* Create contents of the view part.
*
* @param parent
* the parent
*/
@Override
public void createPartControl(Composite parent) {
parent.setLayout(new FillLayout(SWT.HORIZONTAL));
// NOTE: It is important to set SWT.SINGLE for this table viewer. With
// SWT.MULTI enabled, the current
// selection gets reset. This causes inconvinience for the user.
tableViewer = new TableViewer(parent, SWT.BORDER | SWT.FULL_SELECTION | SWT.SINGLE);
table = tableViewer.getTable();
table.setHeaderVisible(true);
//
tableViewer.addSelectionChangedListener(new ISelectionChangedListener() {
@Override
public void selectionChanged(SelectionChangedEvent event) {
List<LayerItem> selected = selectedLayers();
if (selected.isEmpty()) {
return;
}
//
for (Layer l : ScreenEditorUtil.getScreenModel().getDiagram().getLayers()) {
if (l.isCurrent()) {
l.setCurrent(false);
}
}
// select default
if (selected.size() == 1) {
selected.get(0).referenceLayer.setCurrent(true);
}
}
});
//
table.addMouseListener(new MouseAdapter() {
@Override
public void mouseDoubleClick(MouseEvent e) {
changeLayerName();
}
});
addCustomSelectionRenderer(table);
{
TableViewerColumn tableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
TableColumn tblclmnVisible = tableViewerColumn.getColumn();
tblclmnVisible.setMoveable(true);
tblclmnVisible.setWidth(49);
tblclmnVisible.setText("Visible");
}
{
TableViewerColumn tableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
TableColumn tblclmnLock = tableViewerColumn.getColumn();
tblclmnLock.setMoveable(true);
tblclmnLock.setWidth(58);
tblclmnLock.setText("Locked");
}
{
TableViewerColumn tableViewerColumn = new TableViewerColumn(tableViewer, SWT.NONE);
TableColumn tblclmnName = tableViewerColumn.getColumn();
tblclmnName.setMoveable(true);
tblclmnName.setWidth(117);
tblclmnName.setText("Name");
}
tableViewer.setLabelProvider(new TableLabelProvider());
tableViewer.setContentProvider(new ContentProvider());
tableViewer.setColumnProperties(descriptors);
tableViewer.setInput(layerItems);
getSite().setSelectionProvider(tableViewer);
createActions();
initializeToolBar();
initializeMenu();
getSite().getWorkbenchWindow().getSelectionService().addSelectionListener(this);
}
/**
* Change layer name.
*/
protected void changeLayerName() {
List<LayerItem> selected = selectedLayers();
if (selected.isEmpty()) {
return;
}
LayerItem li = selected.get(0);
SimpleTextChangeDialog stcd = new SimpleTextChangeDialog(getSite().getShell(), li.name, "Layer ID: " + li.id);
int response = stcd.open();
if (response == SimpleTextChangeDialog.CANCEL) {
return;
}
li.name = stcd.getName();
ScreenEditorUtil.getScreenLayerManager().changeLayerProperties(Layer.create(li.id, li.name, li.visible, li.locked));
tableViewer.refresh();
}
/**
* Needed for having better visibility of the icons when selected.
*
* @param table2
* the table2
*/
private void addCustomSelectionRenderer(Table table2) {
table2.addListener(SWT.EraseItem, new Listener() {
@Override
public void handleEvent(Event event) {
event.detail &= ~SWT.HOT;
if ((event.detail & SWT.SELECTED) == 0)
return; // / item not selected
Table table = (Table) event.widget;
TableItem item = (TableItem) event.item;
int clientWidth = table.getClientArea().width;
GC gc = event.gc;
Color oldForeground = gc.getForeground();
Color oldBackground = gc.getBackground();
gc.setBackground(ColorConstants.lightGray);
gc.setForeground(ColorConstants.white);
gc.fillRectangle(0, event.y, clientWidth, event.height);
gc.setForeground(oldForeground);
gc.setBackground(oldBackground);
event.detail &= ~SWT.SELECTED;
}
});
}
/**
* Create the actions.
*/
private void createActions() {
// Create the actions
{
addAction = new Action("") {
@Override
public void run() {
LayerItem li = new LayerItem();
li.id = ScreenEditorUtil.getScreenLayerManager().getNewLayerId();
li.name = "Layer" + li.id;
li.locked = false;
li.visible = true;
int index = addLayer(li);
Layer layer = new Layer(li.id, li.name, li.visible, li.locked);
ScreenEditorUtil.getScreenLayerManager().addLayer(layer);
li.referenceLayer = layer;
getTableViewer().refresh();
getTableViewer().getTable().select(index);
}
private int addLayer(LayerItem li) {
if (layerItems.add(li)) {
return layerItems.indexOf(li);
}
return -1;
}
};
addAction.setDescription("Add a new Layer");
addAction.setImageDescriptor(SharedImages.ADD_ITEM_SMALL);
}
{
removeAction = new Action("") {
@Override
public void run() {
List<LayerItem> selected = selectedLayers();
if (selected.isEmpty()) {
return;
}
MessageBox mb = new MessageBox(getSite().getShell(), SWT.YES | SWT.NO);
mb.setMessage("Are you sure you want to remove the selected layers ?");
int resp = mb.open();
if (resp == SWT.NO) {
return;
}
ILayerManager mgr = ScreenEditorUtil.getScreenLayerManager();
for (LayerItem li : selected) {
mgr.removeLayer(li.referenceLayer);
layerItems.remove(li);
}
tableViewer.refresh();
table.select(layerItems.size() - 1);
}
};
removeAction.setDescription("Remove a selected layer");
removeAction.setImageDescriptor(SharedImages.REMOVE_ITEM_SMALL);
}
{
removeAllAction = new Action("") {
@Override
public void run() {
MessageBox mb = new MessageBox(getSite().getShell(), SWT.YES | SWT.NO);
mb.setMessage("Are you sure you want to remove all the layers ?");
int resp = mb.open();
if (resp == SWT.NO) {
return;
}
ILayerManager mgr = ScreenEditorUtil.getScreenLayerManager();
mgr.removeAllLayers();
layerItems.clear();
tableViewer.refresh();
int size = layerItems.size();
table.select(size >= 0 ? size - 1 : 0);
}
};
removeAllAction.setDescription("Remove all layers");
removeAllAction.setImageDescriptor(SharedImages.REMOVE_ALL_SMALL);
}
{
lockAction = new Action("") {
@Override
public void run() {
List<LayerItem> selected = selectedLayers();
ILayerManager layerMgr = ScreenEditorUtil.getScreenLayerManager();
for (LayerItem li : selected) {
li.locked = !li.locked;
layerMgr.changeLayerProperties(Layer.create(li.id, li.name, li.visible, li.locked));
}
tableViewer.refresh();
}
};
lockAction.setImageDescriptor(SharedImages.LOCKED);
}
{
visibilityAction = new Action("") {
@Override
public void run() {
List<LayerItem> selected = selectedLayers();
ILayerManager mgr = ScreenEditorUtil.getScreenLayerManager();
for (LayerItem li : selected) {
li.visible = !li.visible;
mgr.changeLayerProperties(Layer.create(li.id, li.name, li.visible, li.locked));
}
tableViewer.refresh();
}
};
visibilityAction.setImageDescriptor(SharedImages.EYE_VISIBLE);
}
{
upAction = new Action("") {
@Override
public void run() {
List<LayerItem> selLayers = selectedLayers();
if (selLayers.isEmpty())
return;
LayerItem li = selLayers.get(0);
int index = layerItems.indexOf(li);
if (index == 0)
return;
// case:
layerItems.remove(index);
layerItems.add(index - 1, li);
tableViewer.refresh();
// update the changes
changeLayerOrder();
}
};
upAction.setImageDescriptor(SharedImages.BUTTON_UP);
}
{
downAction = new Action("") {
@Override
public void run() {
List<LayerItem> selLayers = selectedLayers();
if (selLayers.isEmpty())
return;
LayerItem li = selLayers.get(0);
int index = layerItems.indexOf(li);
if (index == layerItems.size() - 1)
return;
layerItems.remove(index);
layerItems.add(index + 1, li);
tableViewer.refresh();
// update the changes
changeLayerOrder();
}
};
downAction.setImageDescriptor(SharedImages.BUTTON_DOWN);
}
}
/**
* Change layer order.
*/
private void changeLayerOrder() {
Layer[] larr = new Layer[layerItems.size()];
for (int i = 0; i < layerItems.size(); i++) {
larr[i] = layerItems.get(i).toLayer();
}
//
if (ScreenEditorUtil.isScreenEditorActive()) {
ScreenEditorUtil.getScreenLayerManager().changeLayerOrder(larr);
}
}
/**
* Initialize the toolbar.
*/
private void initializeToolBar() {
IToolBarManager toolbarManager = getViewSite().getActionBars().getToolBarManager();
toolbarManager.add(new Separator());
toolbarManager.add(visibilityAction);
toolbarManager.add(lockAction);
toolbarManager.add(addAction);
toolbarManager.add(removeAction);
toolbarManager.add(removeAllAction);
toolbarManager.add(upAction);
toolbarManager.add(downAction);
toolbarManager.update(true);
}
/**
* Initialize the menu.
*/
private void initializeMenu() {
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.part.WorkbenchPart#getAdapter(java.lang.Class)
*/
@Override
public Object getAdapter(Class adapter) {
if (adapter == Layer.class) {
ISelection isel = tableViewer.getSelection();
if (isel.isEmpty() || isel instanceof ITextSelection) {
return null;
}
IStructuredSelection structSel = (IStructuredSelection) isel;
LayerItem li = (LayerItem) structSel.getFirstElement();
return li.referenceLayer;
}
return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.part.WorkbenchPart#setFocus()
*/
@Override
public void setFocus() {
}
/**
* Gets the table viewer.
*
* @return the table viewer
*/
private TableViewer getTableViewer() {
return tableViewer;
}
/**
* Selected layers.
*
* @return the list
*/
private List<LayerItem> selectedLayers() {
IStructuredSelection selection = (IStructuredSelection) tableViewer.getSelection();
if (selection.isEmpty()) {
return new ArrayList<LayerItem>();
}
List<LayerItem> selected = selection.toList();
return selected;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.ui.ISelectionListener#selectionChanged(org.eclipse.ui.
* IWorkbenchPart, org.eclipse.jface.viewers.ISelection)
*/
@Override
public void selectionChanged(IWorkbenchPart part, ISelection selection) {
// Shape editor gets deactivated when switching between editors
if (!ScreenEditorUtil.isScreenEditorActive()) {
disableState();
return;
}
// Do nothing on empty selection or an incompatible tree selection.
boolean notStructuredSelection = !(selection instanceof IStructuredSelection);
if (selection.isEmpty() || notStructuredSelection) {
enableState();
return;
}
IStructuredSelection sel = (IStructuredSelection) selection;
if (!(sel.getFirstElement() instanceof IAdaptable)) {
enableState();
return;
}
Object firstElement = sel.getFirstElement();
if (firstElement instanceof LayerItem) {
enableState();
return; // do nothing
}
if (firstElement instanceof LayerTreeEP) {
enableState();
Layer l = (Layer) ((LayerTreeEP) firstElement).getModel();
showSelectionForLayerEditPart(l);
}
enableState();
/*
* If the selection is ShapesDiagramEditPart, we get the model and populate
* the layers. If the selection is not ShapesDiagramEditPart and is
* ShapesEditPart, we get the diagram model, populate the layers, and show
* selection for the selected shapes edit part.
*/
IAdaptable element = (IAdaptable) firstElement;
ShapesDiagram model = (ShapesDiagram) element.getAdapter(ShapesDiagram.class);
if (model == null) {
Shape shapeModel = (Shape) element.getAdapter(Shape.class);
// shapeModel null means this selection is definitely not
// ShapeEditPart but some other part in the system
if (shapeModel == null) {
return;
}
// if layers have not been populated yet, populate them and show
// selection for edit part
if (layerItems.isEmpty()) {
model = (ShapesDiagram) element.getAdapter(ShapesDiagramAdapter.class);
showSelectionForMainModel(model);
}
showSelectionForShapeEditPart(shapeModel);
return;
}
showSelectionForMainModel(model);
}
/**
* Show selection for shape edit part.
*
* @param shapeModel
* the shape model
*/
private void showSelectionForShapeEditPart(Shape shapeModel) {
Layer parentLayer = shapeModel.getParentLayer();
int index = 0;
for (LayerItem li : layerItems) {
if (li.referenceLayer == parentLayer) {
table.setSelection(index);
li.referenceLayer.setCurrent(true);
}
index++;
}
}
/**
* Show selection for layer edit part.
*
* @param layerModel
* the layer model
*/
private void showSelectionForLayerEditPart(Layer layerModel) {
int index = 0;
for (LayerItem li : layerItems) {
if (li.referenceLayer == layerModel) {
table.setSelection(index);
li.referenceLayer.setCurrent(true);
}
index++;
}
}
/**
* Show selection for main model.
*
* @param model
* the model
*/
private void showSelectionForMainModel(ShapesDiagram model) {
TableItem[] selections = table.getSelection();
layerItems.clear();
for (Layer l : model.getLayers()) {
LayerItem li = new LayerItem();
li.id = l.getId();
li.name = l.getName();
li.locked = l.isLocked();
li.visible = l.isVisible();
li.referenceLayer = l;
layerItems.add(li);
}
getTableViewer().refresh();
table.setSelection(selections);
}
/*
* (non-Javadoc)
*
* @see
* com.laex.cg2d.screeneditor.views.IScreenDisposeListener#screenDisposed()
*/
@Override
public void screenDisposed() {
disableState();
}
}