/*
* *****************************************************************************
* * Copyright (c) 2006-2012 XMind Ltd. and others. This file is a part of XMind
* 3. XMind releases 3 and above are dual-licensed under the Eclipse Public
* License (EPL), which is available at
* http://www.eclipse.org/legal/epl-v10.html and the GNU Lesser General Public
* License (LGPL), which is available at http://www.gnu.org/licenses/lgpl.html
* See http://www.xmind.net/license.html for details. Contributors: XMind Ltd. -
* initial API and implementation
*******************************************************************************/
package org.xmind.ui.internal.dialogs;
import java.util.Arrays;
import java.util.Comparator;
import org.eclipse.e4.ui.workbench.modeling.ESelectionService;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.IDialogConstants;
import org.eclipse.jface.resource.FontDescriptor;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.jface.resource.JFaceResources;
import org.eclipse.jface.resource.LocalResourceManager;
import org.eclipse.jface.resource.ResourceManager;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerComparator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Font;
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.Menu;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.IWorkbenchPreferenceConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.forms.events.HyperlinkEvent;
import org.eclipse.ui.forms.events.IHyperlinkListener;
import org.eclipse.ui.forms.widgets.Hyperlink;
import org.eclipse.ui.internal.IWorkbenchHelpContextIds;
import org.eclipse.ui.internal.WorkbenchImages;
import org.eclipse.ui.internal.progress.DetailedProgressViewer;
import org.eclipse.ui.internal.progress.FinishedJobs;
import org.eclipse.ui.internal.progress.JobInfo;
import org.eclipse.ui.internal.progress.JobTreeElement;
import org.eclipse.ui.internal.progress.ProgressManager;
import org.eclipse.ui.internal.progress.ProgressMessages;
import org.eclipse.ui.internal.progress.ProgressViewerContentProvider;
import org.eclipse.ui.internal.util.PrefUtil;
import org.xmind.ui.internal.MindMapMessages;
import org.xmind.ui.internal.e4models.ModelPart;
import org.xmind.ui.mindmap.MindMapUI;
import org.xmind.ui.resources.ColorUtils;
import org.xmind.ui.resources.FontUtils;
public class ProgressDialogPart extends ModelPart {
@SuppressWarnings("unchecked")
private static class ProgressViewerComparator extends ViewerComparator {
@Override
@SuppressWarnings("rawtypes")
public int compare(Viewer testViewer, Object e1, Object e2) {
return ((Comparable) e1).compareTo(e2);
}
@Override
public void sort(final Viewer viewer, Object[] elements) {
/*
* https://bugs.eclipse.org/371354 This ordering is inherently
* unstable, since it relies on modifiable properties of the
* elements: E.g. the default implementation in JobTreeElement
* compares getDisplayString(), many of whose implementations use
* getPercentDone(). JavaSE 7+'s TimSort introduced a breaking
* change: It now throws a new IllegalArgumentException for bad
* comparators. Workaround is to retry a few times.
*/
for (int retries = 3; retries > 0; retries--) {
try {
Arrays.sort(elements, new Comparator<Object>() {
@Override
public int compare(Object a, Object b) {
return ProgressViewerComparator.this.compare(viewer,
a, b);
}
});
return; // success
} catch (IllegalArgumentException e) {
// retry
}
}
// One last try that will log and throw TimSort's IAE if it happens:
super.sort(viewer, elements);
}
}
private class ProgressViewer extends DetailedProgressViewer {
private Control nullContentArea;
public ProgressViewer(Composite parent, int style) {
super(parent, style);
}
@Override
public void add(Object[] elements) {
super.add(elements);
updateForShowingContent();
}
@Override
public void remove(Object[] elements) {
super.remove(elements);
updateForShowingContent();
}
@Override
protected void inputChanged(Object input, Object oldInput) {
super.inputChanged(input, oldInput);
updateForShowingContent();
}
@Override
protected void internalRefresh(Object element) {
super.internalRefresh(element);
updateForShowingContent();
}
private void updateForShowingContent() {
Control control = getControl();
if (control == null || control.isDisposed()) {
return;
}
if (getContentProvider() == null) {
return;
}
Object[] elements = ((IStructuredContentProvider) getContentProvider())
.getElements(getInput());
if (elements.length != 0) {
//show content viewer
if (nullContentArea != null) {
nullContentArea.setVisible(false);
((GridData) nullContentArea.getLayoutData()).exclude = true;
}
control.setVisible(true);
((GridData) control.getLayoutData()).exclude = false;
if (removeAllHyperlink != null
&& !removeAllHyperlink.isDisposed()) {
removeAllHyperlink.setEnabled(true);
}
} else {
//show null content area
control.setVisible(false);
((GridData) control.getLayoutData()).exclude = true;
if (nullContentArea == null) {
nullContentArea = createNullContentArea(
control.getParent());
}
nullContentArea.setVisible(true);
((GridData) nullContentArea.getLayoutData()).exclude = false;
if (removeAllHyperlink != null
&& !removeAllHyperlink.isDisposed()) {
removeAllHyperlink.setEnabled(false);
}
}
getControl().getParent().layout();
}
private Composite createNullContentArea(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setBackground(composite.getParent().getBackground());
final GridData layoutData = new GridData(GridData.FILL_BOTH);
composite.setLayoutData(layoutData);
GridLayout layout = new GridLayout(1, false);
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.verticalSpacing = 0;
composite.setLayout(layout);
createNullContent(composite);
return composite;
}
private void createNullContent(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setBackground(composite.getParent().getBackground());
composite.setLayoutData(
new GridData(SWT.CENTER, SWT.CENTER, true, true));
GridLayout layout = new GridLayout(1, false);
layout.marginWidth = 0;
layout.marginHeight = 0;
layout.verticalSpacing = 20;
composite.setLayout(layout);
Label label = new Label(composite, SWT.NONE);
label.setBackground(label.getParent().getBackground());
label.setLayoutData(
new GridData(SWT.CENTER, SWT.CENTER, false, false));
label.setImage((Image) resources.get(MindMapUI.getImages()
.get("progress_no_operations.png", true))); //$NON-NLS-1$
Composite composite2 = new Composite(composite, SWT.NONE);
composite2.setBackground(composite2.getParent().getBackground());
composite2.setLayoutData(
new GridData(SWT.CENTER, SWT.CENTER, false, false));
GridLayout layout2 = new GridLayout(1, false);
layout2.marginWidth = 0;
layout2.marginHeight = 0;
layout2.verticalSpacing = 0;
composite2.setLayout(layout2);
Label label2 = new Label(composite2, SWT.NONE);
label2.setBackground(label2.getParent().getBackground());
label2.setForeground(
resources.createColor(ColorUtils.toDescriptor("#aaaaaa"))); //$NON-NLS-1$
label2.setLayoutData(
new GridData(SWT.CENTER, SWT.CENTER, false, false));
label2.setText(MindMapMessages.ProgressDialog_NullContet_message);
label2.setFont(resources.createFont(
FontDescriptor.createFrom(FontUtils.relativeHeight(
label2.getFont().getFontData(), 1))));
}
}
public static final String CONTEXT_MENU_ID = "org.xmind.ui.ProgressDialog"; //$NON-NLS-1$
private ResourceManager resources;
private DetailedProgressViewer viewer;
private Control control;
private Hyperlink removeAllHyperlink;
private Action clearAllAction;
private Action cancelAction;
@Override
protected void createContent(Composite parent) {
resources = new LocalResourceManager(JFaceResources.getResources(),
parent);
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
composite.setBackground(
(Color) resources.get(ColorUtils.toDescriptor("#ffffff"))); //$NON-NLS-1$
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.verticalSpacing = 0;
layout.horizontalSpacing = 0;
composite.setLayout(layout);
createContentsSection(composite);
createBottomSection(composite);
this.control = composite;
}
private void createContentsSection(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
composite.setBackground(
(Color) resources.get(ColorUtils.toDescriptor("#d8d8d8"))); //$NON-NLS-1$
GridLayout layout = new GridLayout();
layout.marginHeight = 1;
layout.marginWidth = 1;
layout.verticalSpacing = 0;
composite.setLayout(layout);
Composite composite2 = new Composite(composite, SWT.NONE);
composite2.setLayoutData(new GridData(GridData.FILL_BOTH));
composite2.setBackground(parent.getBackground());
GridLayout layout2 = new GridLayout();
layout2.marginHeight = 0;
layout2.marginWidth = 0;
layout2.marginBottom = 0;
layout2.verticalSpacing = 0;
layout2.horizontalSpacing = 0;
composite2.setLayout(layout2);
createProgressViewerSection(composite2);
createShowOperationsCheck(composite2);
}
protected void createProgressViewerSection(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite.setLayoutData(new GridData(GridData.FILL_BOTH));
composite.setBackground(parent.getBackground());
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.marginBottom = 0;
layout.verticalSpacing = 0;
layout.horizontalSpacing = 0;
composite.setLayout(layout);
createProgressViewer(composite);
}
private void createProgressViewer(Composite parent) {
viewer = new ProgressViewer(parent, SWT.MULTI | SWT.H_SCROLL);
viewer.setComparator(new ProgressViewerComparator());
viewer.getControl()
.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
PlatformUI.getWorkbench().getHelpSystem().setHelp(parent,
IWorkbenchHelpContextIds.RESPONSIVE_UI);
initContentProvider();
createClearAllAction();
createCancelAction();
initContextMenu();
setSelectionProvider(viewer);
}
private void createShowOperationsCheck(Composite parent) {
Composite border = new Composite(parent, SWT.NONE);
border.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
border.setBackground(
(Color) resources.get(ColorUtils.toDescriptor("#d8d8d8"))); //$NON-NLS-1$
GridLayout layout = new GridLayout();
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.marginTop = 1;
layout.marginBottom = 0;
layout.verticalSpacing = 0;
layout.horizontalSpacing = 0;
border.setLayout(layout);
Composite composite = new Composite(border, SWT.NONE);
composite
.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
composite.setBackground(
(Color) resources.get(ColorUtils.toDescriptor("#ffffff"))); //$NON-NLS-1$
GridLayout layout2 = new GridLayout();
layout2.marginHeight = 8;
layout2.marginWidth = 0;
layout2.marginTop = 0;
layout2.marginBottom = 0;
layout2.verticalSpacing = 0;
layout2.horizontalSpacing = 0;
composite.setLayout(layout2);
Composite composite2 = new Composite(composite, SWT.NONE);
composite2
.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
composite2.setBackground(composite.getBackground());
GridLayout layout3 = new GridLayout(2, false);
layout3.marginHeight = 0;
layout3.marginWidth = 15;
layout3.verticalSpacing = 0;
layout3.horizontalSpacing = 0;
composite2.setLayout(layout3);
final Button showSystemCheck = new Button(composite2, SWT.CHECK);
showSystemCheck.setBackground(composite2.getBackground());
showSystemCheck
.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
showSystemCheck
.setText(MindMapMessages.ProgressDialog_ShowSystem_check);
showSystemCheck.setForeground(
(Color) resources.get(ColorUtils.toDescriptor("#000000"))); //$NON-NLS-1$
//set initial selection
boolean showSystemJobs = PrefUtil.getAPIPreferenceStore()
.getBoolean(IWorkbenchPreferenceConstants.SHOW_SYSTEM_JOBS);
showSystemCheck.setSelection(showSystemJobs);
showSystemCheck.addSelectionListener(new SelectionListener() {
@Override
public void widgetSelected(SelectionEvent e) {
boolean showSystem = showSystemCheck.getSelection();
PrefUtil.getAPIPreferenceStore().setValue(
IWorkbenchPreferenceConstants.SHOW_SYSTEM_JOBS,
showSystem);
viewer.refresh();
}
@Override
public void widgetDefaultSelected(SelectionEvent e) {
}
});
}
private void createBottomSection(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite
.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
composite.setBackground(
(Color) resources.get(ColorUtils.toDescriptor("#f3f3f3"))); //$NON-NLS-1$
GridLayout layout = new GridLayout(2, false);
layout.marginHeight = 14;
layout.marginWidth = 0;
layout.marginRight = 13;
layout.marginBottom = 1;
layout.verticalSpacing = 0;
layout.horizontalSpacing = 0;
composite.setLayout(layout);
createRemoveAllHyperlink(composite);
createButtonBar(composite);
}
private void createRemoveAllHyperlink(Composite parent) {
Composite composite = new Composite(parent, SWT.NONE);
composite
.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false));
composite.setBackground(parent.getBackground());
GridLayout layout = new GridLayout(1, false);
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.marginLeft = 35;
composite.setLayout(layout);
removeAllHyperlink = new Hyperlink(composite, SWT.NONE);
removeAllHyperlink.setBackground(composite.getBackground());
removeAllHyperlink
.setLayoutData(new GridData(SWT.LEFT, SWT.CENTER, true, false));
removeAllHyperlink
.setText(MindMapMessages.ProgressDialog_RemoveAll_hyperlink);
removeAllHyperlink.setUnderlined(false);
removeAllHyperlink.setForeground(
(Color) resources.get(ColorUtils.toDescriptor("#6484fc"))); //$NON-NLS-1$
removeAllHyperlink.setFont((Font) resources
.get(FontDescriptor.createFrom(FontUtils.relativeHeight(
removeAllHyperlink.getFont().getFontData(), -1))));
removeAllHyperlink.addHyperlinkListener(new IHyperlinkListener() {
public void linkExited(HyperlinkEvent e) {
}
public void linkEntered(HyperlinkEvent e) {
}
public void linkActivated(HyperlinkEvent e) {
clearAllAction.run();
}
});
//set hyperlink enabled
Object[] elements = ((IStructuredContentProvider) viewer
.getContentProvider()).getElements(viewer.getInput());
removeAllHyperlink.setEnabled(elements.length != 0);
}
private void createButtonBar(Composite parent) {
Composite buttonBar = new Composite(parent, SWT.NONE);
buttonBar.setLayoutData(
new GridData(SWT.RIGHT, SWT.CENTER, false, false));
buttonBar.setBackground(parent.getBackground());
GridLayout layout = new GridLayout();
layout.numColumns = 0;
layout.marginHeight = 0;
layout.marginWidth = 0;
layout.verticalSpacing = 0;
layout.horizontalSpacing = 6;
buttonBar.setLayout(layout);
createButton(buttonBar, IDialogConstants.CANCEL_ID,
IDialogConstants.CLOSE_LABEL, false);
}
private Button createButton(Composite parent, int id, String label,
boolean defaultButton) {
// increment the number of columns in the button bar
((GridLayout) parent.getLayout()).numColumns++;
Button button = new Button(parent, SWT.PUSH);
button.setBackground(parent.getBackground());
button.setText(label);
button.setFont(JFaceResources.getDialogFont());
button.setData(Integer.valueOf(id));
button.addSelectionListener(new SelectionAdapter() {
@Override
public void widgetSelected(SelectionEvent event) {
buttonPressed(((Integer) event.widget.getData()).intValue());
}
});
if (defaultButton) {
Shell shell = parent.getShell();
if (shell != null) {
shell.setDefaultButton(button);
}
}
setButtonLayoutData(button);
return button;
}
private void setButtonLayoutData(Button button) {
GridData data = new GridData(GridData.HORIZONTAL_ALIGN_FILL);
data.widthHint = 92;
button.setLayoutData(data);
}
private void buttonPressed(int buttonId) {
if (IDialogConstants.CANCEL_ID == buttonId) {
cancelPressed();
}
}
private void cancelPressed() {
close();
}
private void close() {
if (control != null && !control.isDisposed()) {
control.getShell().close();
}
}
@Override
public void setFocus() {
if (viewer != null) {
viewer.setFocus();
}
}
/**
* Sets the content provider for the viewer.
*/
private void initContentProvider() {
ProgressViewerContentProvider provider = new ProgressViewerContentProvider(
viewer, true, true);
viewer.setContentProvider(provider);
viewer.setInput(ProgressManager.getInstance());
}
/**
* Initialize the context menu for the receiver.
*/
private void initContextMenu() {
MenuManager menuMgr = new MenuManager("#PopupMenu"); //$NON-NLS-1$
Menu menu = menuMgr.createContextMenu(viewer.getControl());
menuMgr.add(cancelAction);
menuMgr.addMenuListener(new IMenuListener() {
@Override
public void menuAboutToShow(IMenuManager manager) {
JobInfo info = getSelectedInfo();
if (info == null) {
return;
}
}
});
menuMgr.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
viewer.getControl().setMenu(menu);
//todo: this may have bug.
registerContextMenu(viewer.getControl(), CONTEXT_MENU_ID);
}
/**
* Get the currently selected job info. Only return it if it is the only
* item selected and it is a JobInfo.
*
* @return JobInfo
*/
private JobInfo getSelectedInfo() {
IStructuredSelection selection = getSelection();
if (selection != null && selection.size() == 1) {
JobTreeElement element = (JobTreeElement) selection
.getFirstElement();
if (element instanceof JobInfo) {
return (JobInfo) element;
}
}
return null;
}
/**
* Return the selected objects. If any of the selections are not JobInfos or
* there is no selection then return null.
*
* @return JobInfo[] or <code>null</code>.
*/
private IStructuredSelection getSelection() {
ESelectionService selectionService = getAdapter(
ESelectionService.class);
if (selectionService != null) {
Object selection = selectionService.getSelection();
return selection instanceof IStructuredSelection
? (IStructuredSelection) selection : null;
}
return null;
}
/**
* Create the cancel action for the receiver.
*/
private void createCancelAction() {
cancelAction = new Action(ProgressMessages.ProgressView_CancelAction) {
@Override
public void run() {
viewer.cancelSelection();
}
};
}
/**
* Create the clear all action for the receiver.
*/
private void createClearAllAction() {
clearAllAction = new Action(
ProgressMessages.ProgressView_ClearAllAction) {
@Override
public void run() {
FinishedJobs.getInstance().clearAll();
}
};
clearAllAction.setToolTipText(
ProgressMessages.NewProgressView_RemoveAllJobsToolTip);
ImageDescriptor id = WorkbenchImages
.getWorkbenchImageDescriptor("/elcl16/progress_remall.png"); //$NON-NLS-1$
if (id != null) {
clearAllAction.setImageDescriptor(id);
}
id = WorkbenchImages
.getWorkbenchImageDescriptor("/dlcl16/progress_remall.png"); //$NON-NLS-1$
if (id != null) {
clearAllAction.setDisabledImageDescriptor(id);
}
}
@Override
public <T> T getAdapter(Class<T> adapter) {
if (adapter.isAssignableFrom(DetailedProgressViewer.class)) {
return adapter.cast(viewer);
}
return super.getAdapter(adapter);
}
}