/*
* ARX: Powerful Data Anonymization
* Copyright 2012 - 2017 Fabian Prasser, Florian Kohlmayer and contributors
*
* 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 org.deidentifier.arx.gui.view.impl.explore;
import org.deidentifier.arx.ARXLattice.ARXNode;
import org.deidentifier.arx.gui.Controller;
import org.deidentifier.arx.gui.model.Model;
import org.deidentifier.arx.gui.model.ModelEvent;
import org.deidentifier.arx.gui.model.ModelEvent.ModelPart;
import org.deidentifier.arx.gui.resources.Resources;
import org.deidentifier.arx.gui.view.SWTUtil;
import org.deidentifier.arx.gui.view.def.IView;
import org.deidentifier.arx.gui.view.impl.common.ClipboardHandlerTable;
import org.deidentifier.arx.gui.view.impl.common.ComponentTitledFolder;
import org.deidentifier.arx.gui.view.impl.common.ComponentTitledFolderButtonBar;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.swt.widgets.MenuItem;
import org.eclipse.swt.widgets.TableItem;
import cern.colt.Arrays;
import de.linearbits.swt.table.DynamicTable;
import de.linearbits.swt.table.DynamicTableColumn;
/**
* This class displays the clipboard.
*
* @author Fabian Prasser
*/
public class ViewClipboard implements IView {
/** Identifier for key in the nodes' attribute maps. */
public static final int NODE_COMMENT = 111;
/** Component. */
private final DynamicTable table;
/** Component. */
private final Composite root;
/** Component. */
private final Menu menu;
/** Component. */
private TableItem selectedItem = null;
/** Model. */
private Model model;
/** Controller. */
private final Controller controller;
/**
* Creates a new instance.
*
* @param parent
* @param controller
*/
public ViewClipboard(final Composite parent, final Controller controller) {
Image imageDown = controller.getResources().getManagedImage("arrow_down.png"); //$NON-NLS-1$
Image imageUp = controller.getResources().getManagedImage("arrow_up.png");//$NON-NLS-1$
Image imageSort = controller.getResources().getManagedImage("table_sort.png");//$NON-NLS-1$
Image imageRemove = controller.getResources().getManagedImage("delete.png");//$NON-NLS-1$
// Listen
controller.addListener(ModelPart.CLIPBOARD, this);
controller.addListener(ModelPart.MODEL, this);
controller.addListener(ModelPart.SELECTED_NODE, this);
this.controller = controller;
ComponentTitledFolderButtonBar bar = new ComponentTitledFolderButtonBar("id-23"); //$NON-NLS-1$
bar.add(Resources.getMessage("ViewClipboard.0"), imageRemove, new Runnable(){ //$NON-NLS-1$
public void run() {
actionRemove();
}
});
bar.add(Resources.getMessage("ViewClipboard.1"), imageUp, new Runnable(){ //$NON-NLS-1$
public void run() {
actionUp();
}
});
bar.add(Resources.getMessage("ViewClipboard.2"), imageDown, new Runnable(){ //$NON-NLS-1$
public void run() {
actionDown();
}
});
bar.add(Resources.getMessage("ViewClipboard.3"), imageSort, new Runnable(){ //$NON-NLS-1$
public void run() {
actionSort();
}
});
// Create group
ComponentTitledFolder border = new ComponentTitledFolder(parent, controller, bar, null); //$NON-NLS-1$
GridData data = SWTUtil.createFillGridData();
data.heightHint = 70;
border.setLayoutData(data);
// Create root
root = border.createItem(Resources.getMessage("NodeClipboardView.0"), null); //$NON-NLS-1$
root.setLayout(new FillLayout());
border.setSelection(0);
border.setEnabled(true);
// Create table
table = SWTUtil.createTableDynamic(root, SWT.BORDER | SWT.SINGLE | SWT.V_SCROLL | SWT.H_SCROLL | SWT.FULL_SELECTION);
table.setHeaderVisible(true);
table.setLinesVisible(true);
// First column
final DynamicTableColumn c = new DynamicTableColumn(table, SWT.LEFT);
c.setText(Resources.getMessage("NodeClipboardView.6")); //$NON-NLS-1$
c.setWidth("20%", "100px"); //$NON-NLS-1$ //$NON-NLS-2$
// Second column
final DynamicTableColumn c2 = new DynamicTableColumn(table, SWT.LEFT);
c2.setText(Resources.getMessage("NodeClipboardView.7")); //$NON-NLS-1$
c2.setWidth("80%", "100px"); //$NON-NLS-1$ //$NON-NLS-2$
// Pack
c.pack();
c2.pack();
// Tool tip
SWTUtil.createGenericTooltip(table);
// Selected node
table.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(final SelectionEvent arg0) {
final TableItem[] s = table.getSelection();
if (s.length > 0) {
final ARXNode node = (ARXNode) s[0].getData();
selectedItem = s[0];
model.setSelectedNode(node);
controller.update(new ModelEvent(ViewClipboard.this, ModelPart.SELECTED_NODE, node));
}
}
});
// Menu
this.menu = createMenu(parent);
// Add menu to table
table.addListener(SWT.MouseDown, new Listener() {
@Override
public void handleEvent(final Event event) {
if (event.button == 3) {
final TableItem i = getItemAt(event.x, event.y);
if (i != null) {
final ARXNode node = (ARXNode) i.getData();
model.setSelectedNode(node);
controller.update(new ModelEvent(ViewClipboard.this, ModelPart.SELECTED_NODE, node));
selectedItem = i;
Point point = table.toDisplay(event.x, event.y);
Rectangle bounds = i.getBounds();
bounds.x = table.toDisplay(bounds.x, bounds.y).x;
bounds.y = table.toDisplay(bounds.x, bounds.y).y;
menu.setLocation(point);
menu.setVisible(true);
}
}
}
});
}
@Override
public void dispose() {
controller.removeListener(this);
}
@Override
public void reset() {
table.setRedraw(false);
removeAllItems();
table.setRedraw(true);
table.redraw();
SWTUtil.disable(root);
}
@Override
public void update(final ModelEvent event) {
if (event.part == ModelPart.MODEL) {
model = (Model) event.data;
} else if (event.part == ModelPart.SELECTED_NODE) {
final ARXNode selected = (ARXNode) event.data;
// No result available
if (selected == null) {
reset();
} else {
final String trans = Arrays.toString(selected.getTransformation());
for (final TableItem i : table.getItems()) {
if (i.getText(0).equals(trans)) {
table.setSelection(i);
this.selectedItem = i;
}
}
SWTUtil.enable(root);
}
} else if (event.part == ModelPart.CLIPBOARD) {
table.setRedraw(false);
removeAllItems();
addAllItemsFromModel();
table.setRedraw(true);
table.redraw();
SWTUtil.enable(root);
if (table.getItemCount()!=0) {
this.selectedItem = table.getItem(0);
table.select(0);
} else {
this.selectedItem = null;
}
}
}
/**
* Action.
*/
private void actionApplyTransformation() {
if (selectedItem != null) {
controller.actionApplySelectedTransformation();
controller.update(new ModelEvent(this, ModelPart.SELECTED_NODE, model.getSelectedNode()));
}
}
/**
* Action.
*/
private void actionCopy() {
if (table != null) {
new ClipboardHandlerTable(this.table).copy();
}
}
/**
* Action.
*/
private void actionDown() {
if (selectedItem != null) {
int index = getItemIndex(selectedItem);
if (index != -1 && index<table.getItemCount()-1) {
table.setRedraw(false);
ARXNode node = (ARXNode)selectedItem.getData();
removeItem(selectedItem);
addItem(node, index+1);
table.setRedraw(true);
table.redraw();
model.getClipboard().moveEntryDown(node);
table.select(index+1);
this.selectedItem = table.getItem(index+1);
}
}
}
/**
* Action.
*/
private void actionEditComment() {
if (selectedItem != null) {
ARXNode node = (ARXNode)selectedItem.getData();
final String label = Arrays.toString(node.getTransformation());
final String value = controller.actionShowInputDialog(controller.getResources().getShell(),
Resources.getMessage("NodeClipboardView.4"), //$NON-NLS-1$
Resources.getMessage("NodeClipboardView.5") + label, //$NON-NLS-1$
selectedItem.getText(1));
if (value != null) {
selectedItem.setText(1, value);
node.getAttributes().put(NODE_COMMENT, value);
}
}
}
/**
* Action.
*/
private void actionRemove() {
if (selectedItem != null) {
int index = getItemIndex(selectedItem);
ARXNode node = (ARXNode)selectedItem.getData();
model.getClipboard().removeFromClipboard(node);
table.setRedraw(false);
removeItem(selectedItem);
table.setRedraw(true);
table.redraw();
controller.update(new ModelEvent(ViewClipboard.this, ModelPart.CLIPBOARD, null));
if (table.getItemCount()==0){
this.selectedItem = null;
index = -1;
} else if (index >= table.getItemCount()) {
index = table.getItemCount()-1;
}
if (index != -1) {
this.selectedItem = table.getItem(index);
table.select(index);
}
}
}
/**
* Action.
*/
private void actionSort() {
if (selectedItem != null) {
int index = table.getSelectionIndex();
table.setRedraw(false);
removeAllItems();
model.getClipboard().sort();
addAllItemsFromModel();
table.setRedraw(true);
if (index!=-1) {
table.select(index);
this.selectedItem = table.getItem(index);
} else {
this.selectedItem = null;
}
}
}
/**
* Action.
*/
private void actionUp() {
if (selectedItem != null) {
int index = getItemIndex(selectedItem);
if (index > 0) {
table.setRedraw(false);
ARXNode node = (ARXNode)selectedItem.getData();
removeItem(selectedItem);
addItem(node, index-1);
table.setRedraw(true);
table.redraw();
model.getClipboard().moveEntryUp(node);
table.select(index-1);
this.selectedItem = table.getItem(index-1);
}
}
}
/**
* Adds all items from the model.
*/
private void addAllItemsFromModel() {
// Add all to table
for (final ARXNode node : model.getClipboard().getClipboardEntries()) {
addItem(node, table.getItemCount());
}
}
/**
* Adds an item.
*
* @param node
* @param index
* @return
*/
private TableItem addItem(ARXNode node, int index) {
final TableItem item = new TableItem(table, SWT.NONE, index);
item.setText(0, Arrays.toString(node.getTransformation()));
if (node.getAttributes().get(NODE_COMMENT) != null) {
item.setText(1, (String) node.getAttributes().get(NODE_COMMENT));
} else {
item.setText(1, ""); //$NON-NLS-1$
}
item.setData(node);
return item;
}
/**
* This method creates the context menu.
*
* @param parent
* @return
*/
private Menu createMenu(Composite parent) {
final Menu menu = new Menu(parent.getShell());
MenuItem item0 = new MenuItem(menu, SWT.NONE);
item0.setText(Resources.getMessage("NodeClipboardView.11")); //$NON-NLS-1$
item0.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent arg0) {
actionCopy();
}
});
new MenuItem(menu, SWT.SEPARATOR);
MenuItem item1 = new MenuItem(menu, SWT.NONE);
item1.setText(Resources.getMessage("NodeClipboardView.1")); //$NON-NLS-1$
item1.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent arg0) {
actionEditComment();
}
});
MenuItem item2 = new MenuItem(menu, SWT.NONE);
item2.setText(Resources.getMessage("NodeClipboardView.2")); //$NON-NLS-1$
item2.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent arg0) {
actionRemove();
}
});
MenuItem item3 = new MenuItem(menu, SWT.NONE);
item3.setText(Resources.getMessage("NodeClipboardView.3")); //$NON-NLS-1$
item3.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent arg0) {
actionApplyTransformation();
}
});
new MenuItem(menu, SWT.SEPARATOR);
MenuItem item4 = new MenuItem(menu, SWT.NONE);
item4.setText(Resources.getMessage("NodeClipboardView.8")); //$NON-NLS-1$
item4.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent arg0) {
actionUp();
}
});
MenuItem item5 = new MenuItem(menu, SWT.NONE);
item5.setText(Resources.getMessage("NodeClipboardView.9")); //$NON-NLS-1$
item5.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent arg0) {
actionDown();
}
});
MenuItem item6 = new MenuItem(menu, SWT.NONE);
item6.setText(Resources.getMessage("NodeClipboardView.10")); //$NON-NLS-1$
item6.addSelectionListener(new SelectionAdapter() {
public void widgetSelected(final SelectionEvent arg0) {
actionSort();
}
});
return menu;
}
/**
* Returns the item at the given location.
*
* @param x
* @param y
* @return
*/
private TableItem getItemAt(int x, int y) {
Point pt = new Point(x, y);
int index = table.getTopIndex();
while (index < table.getItemCount()) {
final TableItem item = table.getItem(index);
for (int i = 0; i < table.getColumnCount(); i++) {
final Rectangle rect = item.getBounds(i);
if (rect.contains(pt)) { return item; }
}
index++;
}
return null;
}
/**
* Returns the index of the given item.
*
* @param item
* @return
*/
private int getItemIndex(TableItem item) {
int index = -1;
for (int i = 0; i < table.getItemCount(); i++) {
if (table.getItem(i) == item) {
index = i;
break;
}
}
return index;
}
/**
* Removes all items.
*/
private void removeAllItems() {
for (final TableItem i : table.getItems()) {
i.dispose();
}
table.removeAll();
}
/**
* Removes the item.
*
* @param item
* @return
*/
private int removeItem(final TableItem item) {
int index = getItemIndex(item);
if (index == -1) { return -1; }
table.remove(index);
return index;
}
}