package org.xmind.ui.internal.views;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.viewers.ColumnLabelProvider;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.jface.viewers.TreeViewerColumn;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerSorter;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.IEditorInput;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PartInitException;
import org.eclipse.ui.part.ViewPart;
import org.xmind.core.Core;
import org.xmind.core.CoreException;
import org.xmind.core.IWorkbook;
import org.xmind.core.event.CoreEvent;
import org.xmind.core.event.CoreEventRegister;
import org.xmind.core.event.ICoreEventListener;
import org.xmind.core.event.ICoreEventSource2;
import org.xmind.ui.blackbox.BlackBox;
import org.xmind.ui.blackbox.BlackBoxManager;
import org.xmind.ui.blackbox.IBlackBoxMap;
import org.xmind.ui.blackbox.IBlackBoxVersion;
import org.xmind.ui.mindmap.IMindMapImages;
import org.xmind.ui.mindmap.MindMapUI;
import org.xmind.ui.resources.FontUtils;
import org.xmind.ui.viewers.SWTUtils;
public class BlackBoxView extends ViewPart implements ICoreEventListener {
private static final String MAP_REMOVE = "mapRemove"; //$NON-NLS-1$
private static final String VERSION_REMOVE = "versionRemove"; //$NON-NLS-1$
private static final String VERSION_ADD = "versionAdd"; //$NON-NLS-1$
private TreeViewer viewer;
private MenuManager contextMenu;
private CoreEventRegister coreEventRegister = new CoreEventRegister(this);
private List<IAction> actions = new ArrayList<IAction>();
public BlackBoxView() {
}
private static class BlackBoxContentProvider
implements ITreeContentProvider {
public void dispose() {
}
public void inputChanged(Viewer viewer, Object oldInput,
Object newInput) {
}
public Object[] getElements(Object inputElement) {
return (IBlackBoxMap[]) inputElement;
}
public Object[] getChildren(Object parentElement) {
if (parentElement instanceof IBlackBoxMap) {
return ((IBlackBoxMap) parentElement).getVersions().toArray();
}
return null;
}
public Object getParent(Object element) {
if (element instanceof IBlackBoxVersion) {
return ((IBlackBoxVersion) element).getMap();
}
return null;
}
public boolean hasChildren(Object element) {
if (element instanceof IBlackBoxMap) {
return !((IBlackBoxMap) element).getVersions().isEmpty();
}
return false;
}
}
private static class BlackBoxLabelProvide extends LabelProvider {
public String getText(Object element) {
if (element instanceof IBlackBoxMap) {
String filePath = ((IBlackBoxMap) element).getSource();
int index = filePath.lastIndexOf(File.separatorChar);
String fileName = index <= 0 ? filePath
: filePath.substring(index + 1);
index = fileName.lastIndexOf('.');
String fileNoExtension = index <= 0 ? fileName
: fileName.substring(0, index);
return fileNoExtension;
} else if (element instanceof IBlackBoxVersion) {
return ((IBlackBoxVersion) element).getTimestamp();
}
return null;
}
}
private class VersionsLabelProvider extends ColumnLabelProvider {
@Override
public String getText(Object element) {
if (element instanceof IBlackBoxMap) {
String path = ((IBlackBoxMap) element).getSource();
int index = path.lastIndexOf(File.separatorChar);
String mapName = index <= 0 ? path : path.substring(index + 1);
return mapName;
} else if (element instanceof IBlackBoxVersion) {
Long timestamp = Long
.valueOf(((IBlackBoxVersion) element).getTimestamp());
return String.format("%tF %tT", timestamp, timestamp); //$NON-NLS-1$
}
return null;
}
@Override
public Image getImage(Object element) {
if (element instanceof IBlackBoxMap) {
ImageDescriptor image = MindMapUI.getImages()
.get(IMindMapImages.XMIND_FILE_ICON);
if (image != null)
return image.createImage();
}
return null;
}
}
private class VersionsInfoLabelProvider extends ColumnLabelProvider {
@Override
public String getText(Object element) {
if (element instanceof IBlackBoxMap) {
return ((IBlackBoxMap) element).getSource();
} else if (element instanceof IBlackBoxVersion) {
float fileSize = ((float) ((IBlackBoxVersion) element).getFile()
.length()) / 1024;
String fss = String.valueOf(fileSize);
int index = fss.indexOf('.');
if (index < 0)
return fss + "KB"; //$NON-NLS-1$
else
return fss.substring(0, index + 2) + "KB"; //$NON-NLS-1$
}
return null;
}
}
private class OpenReversionAction extends Action
implements ISelectionChangedListener {
private File reversionFile;
private IBlackBoxMap map = null;
public OpenReversionAction() {
setEnabled(false);
}
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
this.reversionFile = null;
if (selection instanceof IStructuredSelection) {
IStructuredSelection ss = (IStructuredSelection) selection;
if (ss.size() == 1) {
Object element = ss.getFirstElement();
if (element instanceof IBlackBoxVersion) {
this.reversionFile = ((IBlackBoxVersion) element)
.getFile();
this.map = ((IBlackBoxVersion) element).getMap();
}
}
}
setEnabled(this.reversionFile != null);
}
@Override
public void run() {
if (reversionFile == null || !reversionFile.exists() || map == null)
return;
handleOpen(reversionFile, map);
}
}
private class DeleteBackupsAction extends Action
implements ISelectionChangedListener {
private List<IBlackBoxMap> mapsToDelete = new ArrayList<IBlackBoxMap>();
private List<IBlackBoxVersion> versionsToDelete = new ArrayList<IBlackBoxVersion>();
public DeleteBackupsAction() {
setEnabled(false);
}
public void selectionChanged(SelectionChangedEvent event) {
ISelection selection = event.getSelection();
mapsToDelete.clear();
versionsToDelete.clear();
if (!selection.isEmpty()
&& selection instanceof IStructuredSelection) {
Iterator it = ((IStructuredSelection) selection).iterator();
while (it.hasNext()) {
Object element = it.next();
if (element instanceof IBlackBoxVersion) {
versionsToDelete.add((IBlackBoxVersion) element);
} else if (element instanceof IBlackBoxMap) {
mapsToDelete.add((IBlackBoxMap) element);
}
}
}
setEnabled(!(mapsToDelete.isEmpty() && versionsToDelete.isEmpty()));
}
@Override
public void run() {
if (versionsToDelete.isEmpty() && mapsToDelete.isEmpty())
return;
if (!versionsToDelete.isEmpty()) {
for (IBlackBoxVersion version : versionsToDelete) {
IBlackBoxMap map = version.getMap();
BlackBox.removeVersion(map, version.getTimestamp());
}
}
if (!mapsToDelete.isEmpty()) {
for (IBlackBoxMap blackBoxMap : mapsToDelete) {
BlackBox.removeMap(blackBoxMap);
}
}
}
}
private class VersionOpenListener implements IDoubleClickListener {
public void doubleClick(DoubleClickEvent event) {
handleOpen(event.getSelection());
}
}
private class BlackBoxSorter extends ViewerSorter {
@Override
public int category(Object element) {
if (element instanceof IBlackBoxMap) {
return 0;
} else if (element instanceof IBlackBoxVersion) {
return 1;
}
return 2;
}
}
@Override
public void createPartControl(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
GridLayout gridLayout = new GridLayout(1, false);
gridLayout.marginWidth = 0;
gridLayout.marginHeight = 0;
gridLayout.verticalSpacing = 5;
gridLayout.horizontalSpacing = 0;
composite.setLayout(gridLayout);
Label top = new Label(composite, SWT.WRAP);
top.setText(Messages.BlackBoxView_Description_text);
top.setFont(FontUtils.getNewHeight(JFaceResources.DEFAULT_FONT, -1));
top.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, false));
Control viewerControl = createViewer(composite);
viewerControl
.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
fillAndRegisterMenu();
registerCoreEvent();
}
private void registerCoreEvent() {
coreEventRegister
.setNextSourceFrom(BlackBoxManager.getInstance().getLibrary());
coreEventRegister.register(VERSION_ADD);
coreEventRegister.register(VERSION_REMOVE);
coreEventRegister.register(MAP_REMOVE);
}
private Control createViewer(Composite parent) {
viewer = new TreeViewer(parent,
SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL | SWT.FULL_SELECTION);
viewer.getTree().setHeaderVisible(true);
viewer.getTree().setLinesVisible(true);
viewer.setContentProvider(new BlackBoxContentProvider());
viewer.setLabelProvider(new BlackBoxLabelProvide());
TreeViewerColumn col0 = new TreeViewerColumn(viewer, SWT.LEFT);
col0.getColumn().setText(Messages.BlackBoxView_Versions);
col0.getColumn().setWidth(200);
col0.setLabelProvider(new VersionsLabelProvider());
TreeViewerColumn col1 = new TreeViewerColumn(viewer, SWT.LEFT);
col1.getColumn().setText(Messages.BlackBoxView_Info);
col1.getColumn().setWidth(300);
col1.setLabelProvider(new VersionsInfoLabelProvider());
viewer.setInput(BlackBox.getMaps());
getSite().setSelectionProvider(viewer);
viewer.setAutoExpandLevel(2);
viewer.setSorter(new BlackBoxSorter());
viewer.addDoubleClickListener(new VersionOpenListener());
viewer.getTree().addKeyListener(new KeyListener() {
public void keyReleased(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
if (SWTUtils.matchKey(e.stateMask, e.keyCode, 0, SWT.SPACE)) {
handleOpen(viewer.getSelection());
}
}
});
return viewer.getControl();
}
private void fillAndRegisterMenu() {
OpenReversionAction openAction = new OpenReversionAction();
openAction.setText(Messages.BlackBoxView_OpenVersion);
openAction.setToolTipText(Messages.BlackBoxView_OpenVersion);
openAction.setImageDescriptor(
MindMapUI.getImages().get(IMindMapImages.OPEN, true));
openAction.setDisabledImageDescriptor(
MindMapUI.getImages().get(IMindMapImages.OPEN, false));
addAction(openAction);
DeleteBackupsAction deleteAction = new DeleteBackupsAction();
deleteAction.setText(Messages.BlackBoxView_DeleteBackups);
deleteAction.setToolTipText(Messages.BlackBoxView_DeleteBackups);
deleteAction.setImageDescriptor(
MindMapUI.getImages().get(IMindMapImages.DELETE, true));
deleteAction.setDisabledImageDescriptor(
MindMapUI.getImages().get(IMindMapImages.DELETE, false));
addAction(deleteAction);
// IToolBarManager toolbar = getViewSite().getActionBars()
// .getToolBarManager();
// toolbar.add(openAction);
// toolbar.add(deleteAction);
// toolbar.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
IMenuManager menu = getViewSite().getActionBars().getMenuManager();
menu.add(openAction);
menu.add(deleteAction);
menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
getViewSite().getActionBars().updateActionBars();
contextMenu = new MenuManager("#PopupMenu"); //$NON-NLS-1$
contextMenu.add(openAction);
contextMenu.add(deleteAction);
viewer.getControl()
.setMenu(contextMenu.createContextMenu(viewer.getControl()));
getSite().registerContextMenu(contextMenu, viewer);
}
private void addAction(IAction action) {
actions.add(action);
if (action.getId() != null) {
getViewSite().getActionBars().setGlobalActionHandler(action.getId(),
action);
}
if (action instanceof ISelectionChangedListener) {
getViewSite().getSelectionProvider().addSelectionChangedListener(
(ISelectionChangedListener) action);
}
}
public void setDamagedFile(File damagedFile) {
if (damagedFile == null)
return;
String source = damagedFile.getAbsolutePath();
IBlackBoxMap map = BlackBox.findMapBySource(source);
if (map != null)
viewer.setSelection(new StructuredSelection(map), true);
}
@Override
public void setFocus() {
if (viewer != null && !viewer.getControl().isDisposed()) {
viewer.getControl().setFocus();
}
}
public void dispose() {
if (contextMenu != null) {
contextMenu.dispose();
contextMenu = null;
}
for (IAction action : actions) {
if (action instanceof ISelectionChangedListener) {
getSite().getSelectionProvider().removeSelectionChangedListener(
(ISelectionChangedListener) action);
}
}
actions.clear();
coreEventRegister.unregisterAll();
super.dispose();
}
private void handleOpen(ISelection selection) {
File reversionFile = null;
IBlackBoxMap map = null;
if (selection instanceof IStructuredSelection) {
IStructuredSelection ss = (IStructuredSelection) selection;
if (ss.size() == 1) {
Object element = ss.getFirstElement();
if (element instanceof IBlackBoxVersion) {
reversionFile = ((IBlackBoxVersion) element).getFile();
map = ((IBlackBoxVersion) element).getMap();
} else if (element instanceof IBlackBoxMap) {
if (viewer.getExpandedState(element))
viewer.collapseToLevel(element, 2);
else
viewer.expandToLevel(element, 2);
}
}
}
if (reversionFile == null || !reversionFile.exists() || map == null)
return;
handleOpen(reversionFile, map);
}
private void handleOpen(File reversionFile, IBlackBoxMap map) {
try {
IWorkbook workbook = Core.getWorkbookBuilder()
.loadFromFile(reversionFile);
IEditorInput input = MindMapUI.getEditorInputFactory()
.createEditorInputForPreLoadedWorkbook(workbook,
new File(map.getSource()).getName());
getSite().getPage().openEditor(input, MindMapUI.MINDMAP_EDITOR_ID);
if (workbook instanceof ICoreEventSource2) {
((ICoreEventSource2) workbook).registerOnceCoreEventListener(
Core.WorkbookPreSaveOnce, ICoreEventListener.NULL);
}
} catch (IOException e1) {
e1.printStackTrace();
} catch (CoreException e1) {
e1.printStackTrace();
} catch (PartInitException e) {
e.printStackTrace();
}
}
public void handleCoreEvent(CoreEvent event) {
final String type = event.getType();
getSite().getWorkbenchWindow().getWorkbench().getDisplay()
.asyncExec(new Runnable() {
public void run() {
if (VERSION_REMOVE.equals(type)) {
viewer.refresh(true);
} else if (VERSION_ADD.equals(type)
|| MAP_REMOVE.equals(type)) {
viewer.setInput(BlackBox.getMaps());
}
}
});
}
}