package org.xmind.ui.internal.dialogs; 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.dialogs.Dialog; import org.eclipse.jface.dialogs.IDialogConstants; 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.swt.SWT; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IEditorInput; import org.eclipse.ui.IWorkbenchActionConstants; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.internal.dialogs.ViewComparator; 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.internal.MindMapMessages; import org.xmind.ui.internal.views.Messages; import org.xmind.ui.mindmap.IMindMapImages; import org.xmind.ui.mindmap.MindMapUI; import org.xmind.ui.resources.FontUtils; public class BlackBoxDialog extends Dialog implements ICoreEventListener, ISelectionChangedListener { 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 static final int DELETE_BUTTON_ID = IDialogConstants.CLIENT_ID + 1; private TreeViewer viewer; private MenuManager contextMenu; private CoreEventRegister coreEventRegister = new CoreEventRegister(this); private IAction openAction, deleteAction; private Button openButton, deleteButton; private IStructuredSelection currentSelection; 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); if (mapName.contains(".")) //$NON-NLS-1$ mapName = mapName.substring(0, mapName.lastIndexOf('.')); 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 { public OpenReversionAction() { setEnabled(false); } @Override public void run() { handleOpen(currentSelection); } } private class DeleteBackupsAction extends Action { public DeleteBackupsAction() { setEnabled(false); } @Override public void run() { handleDelete(); } } private class VersionOpenListener implements IDoubleClickListener { public void doubleClick(DoubleClickEvent event) { handleOpen(event.getSelection()); } } private class BlackBoxComparator extends ViewComparator { @Override public int category(Object element) { if (element instanceof IBlackBoxMap) { return 0; } else if (element instanceof IBlackBoxVersion) { return 1; } return 2; } @Override public int compare(Viewer viewer, Object e1, Object e2) { if (e1 != null && e2 != null && e1 instanceof IBlackBoxVersion && e2 instanceof IBlackBoxVersion) { long time1 = Long .parseLong(((IBlackBoxVersion) e1).getTimestamp()); long time2 = Long .parseLong(((IBlackBoxVersion) e2).getTimestamp()); return time1 - time2 > 0 ? -1 : 1; } return super.compare(viewer, e1, e2); } } public BlackBoxDialog(Shell parentShell) { super(parentShell); setShellStyle(SWT.MODELESS | SWT.RESIZE | SWT.DIALOG_TRIM | SWT.MIN | SWT.MAX); setBlockOnOpen(false); } @Override public void configureShell(Shell shell) { super.configureShell(shell); shell.setText(MindMapMessages.BlackBoxDialog_title); } @Override public Control createDialogArea(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); GridLayout gridLayout = new GridLayout(1, false); gridLayout.marginWidth = 14; gridLayout.marginHeight = 0; gridLayout.verticalSpacing = 0; composite.setLayout(gridLayout); composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); createDescriptionArea(composite); createContentArea(composite); fillAndRegisterMenu(); registerCoreEvent(); return composite; } @Override protected Control createButtonBar(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); // create a layout with spacing and margins appropriate for the font // size. GridLayout layout = new GridLayout(); layout.numColumns = 0; // this is incremented by createButton layout.makeColumnsEqualWidth = true; layout.marginWidth = 13; layout.marginHeight = 23; layout.horizontalSpacing = 18; layout.verticalSpacing = 0; composite.setLayout(layout); GridData data = new GridData( GridData.HORIZONTAL_ALIGN_END | GridData.VERTICAL_ALIGN_CENTER); composite.setLayoutData(data); composite.setFont(parent.getFont()); // Add the buttons to the button bar. createButtonsForButtonBar(composite); return composite; } private void createContentArea(Composite parent) { Composite composite = new Composite(parent, SWT.BORDER); composite.setBackground( parent.getDisplay().getSystemColor(SWT.COLOR_WHITE)); composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); GridLayout gridLayout = new GridLayout(1, false); gridLayout.marginWidth = 0; gridLayout.marginHeight = 0; composite.setLayout(gridLayout); Control viewerControl = createViewer(composite); viewerControl .setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); } private void createDescriptionArea(Composite parent) { Composite composite = new Composite(parent, SWT.NONE); composite.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false)); composite.setBackground(parent.getBackground()); GridLayout middleLayerLayout = new GridLayout(1, false); middleLayerLayout.marginWidth = 0; middleLayerLayout.marginHeight = 18; composite.setLayout(middleLayerLayout); Label descriptionLabel = new Label(composite, SWT.WRAP); descriptionLabel .setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, true)); descriptionLabel.setBackground(composite.getBackground()); descriptionLabel.setText(Messages.BlackBoxView_Description_text); descriptionLabel.setFont( FontUtils.getNewHeight(JFaceResources.DEFAULT_FONT, -1)); } private Control createViewer(Composite parent) { viewer = new TreeViewer(parent, SWT.MULTI | SWT.V_SCROLL | SWT.FULL_SELECTION); viewer.getTree().setHeaderVisible(true); viewer.getTree().setLinesVisible(true); viewer.setContentProvider(new BlackBoxContentProvider()); viewer.setLabelProvider(new BlackBoxLabelProvide()); viewer.addSelectionChangedListener(this); 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(268); col1.setLabelProvider(new VersionsInfoLabelProvider()); viewer.setInput(BlackBox.getMaps()); viewer.setAutoExpandLevel(2); viewer.setComparator(new BlackBoxComparator()); viewer.addDoubleClickListener(new VersionOpenListener()); return viewer.getControl(); } private void fillAndRegisterMenu() { //TODO String is in View, extract to Dialog 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)); 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)); IMenuManager menu = new MenuManager(); menu.add(openAction); menu.add(deleteAction); menu.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS)); contextMenu = new MenuManager("#PopupMenu"); //$NON-NLS-1$ contextMenu.add(openAction); contextMenu.add(deleteAction); viewer.getControl() .setMenu(contextMenu.createContextMenu(viewer.getControl())); } private void registerCoreEvent() { coreEventRegister .setNextSourceFrom(BlackBoxManager.getInstance().getLibrary()); coreEventRegister.register(VERSION_ADD); coreEventRegister.register(VERSION_REMOVE); coreEventRegister.register(MAP_REMOVE); } @Override protected void initializeBounds() { getShell().setBounds(300, 150, 516, 500); super.initializeBounds(); } @Override protected void createButtonsForButtonBar(Composite parent) { openButton = createButton(parent, IDialogConstants.OPEN_ID, Messages.BlackBoxView_OpenVersion, false); openButton.setEnabled(false); deleteButton = createButton(parent, DELETE_BUTTON_ID, Messages.BlackBoxView_DeleteBackups, false); deleteButton.setEnabled(false); createButton(parent, IDialogConstants.CLOSE_ID, IDialogConstants.CLOSE_LABEL, true); } @Override protected void buttonPressed(int buttonId) { super.buttonPressed(buttonId); if (IDialogConstants.OPEN_ID == buttonId) handleOpen(currentSelection); else if (IDialogConstants.CLOSE_ID == buttonId) handleClose(); else if (DELETE_BUTTON_ID == buttonId) handleDelete(); } 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()); PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() .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(); } } private void handleDelete() { List<IBlackBoxMap> mapsToDelete = new ArrayList<IBlackBoxMap>(); List<IBlackBoxVersion> versionsToDelete = new ArrayList<IBlackBoxVersion>(); IStructuredSelection selection = (IStructuredSelection) viewer .getSelection(); Iterator it = 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); } } 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 void handleClose() { close(); } @Override public boolean close() { if (contextMenu != null) { contextMenu.dispose(); contextMenu = null; } coreEventRegister.unregisterAll(); return super.close(); } public void handleCoreEvent(CoreEvent event) { final String type = event.getType(); PlatformUI.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()); } } }); } public void selectionChanged(SelectionChangedEvent event) { openAction.setEnabled(false); openButton.setEnabled(false); deleteAction.setEnabled(false); deleteButton.setEnabled(false); if (!(event.getSelection() instanceof IStructuredSelection)) return; currentSelection = (IStructuredSelection) event.getSelection(); List<IBlackBoxVersion> selectVersions = new ArrayList<IBlackBoxVersion>(); List<IBlackBoxMap> selectMaps = new ArrayList<IBlackBoxMap>(); Iterator it = currentSelection.iterator(); while (it.hasNext()) { Object element = it.next(); if (element instanceof IBlackBoxVersion) { selectVersions.add((IBlackBoxVersion) element); } else if (element instanceof IBlackBoxMap) { selectMaps.add((IBlackBoxMap) element); } } if (1 == selectVersions.size() && selectMaps.isEmpty()) { openAction.setEnabled(true); openButton.setEnabled(true); } if (!selectMaps.isEmpty() || !selectVersions.isEmpty()) { deleteAction.setEnabled(true); deleteButton.setEnabled(true); } } 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); } }