Lines 1-5
Link Here
|
1 |
/******************************************************************************* |
1 |
/******************************************************************************* |
2 |
* Copyright (c) 2000, 2011 IBM Corporation and others. |
2 |
* Copyright (c) 2000, 2012 IBM Corporation and others. |
3 |
* All rights reserved. This program and the accompanying materials |
3 |
* All rights reserved. This program and the accompanying materials |
4 |
* are made available under the terms of the Eclipse Public License v1.0 |
4 |
* are made available under the terms of the Eclipse Public License v1.0 |
5 |
* which accompanies this distribution, and is available at |
5 |
* which accompanies this distribution, and is available at |
Lines 8-21
Link Here
|
8 |
* Contributors: |
8 |
* Contributors: |
9 |
* IBM Corporation - initial API and implementation |
9 |
* IBM Corporation - initial API and implementation |
10 |
* Peter Friese <peter.friese@gentleware.com> - bug 194529, bug 196867 |
10 |
* Peter Friese <peter.friese@gentleware.com> - bug 194529, bug 196867 |
|
|
11 |
* Sascha Becher <s.becher@qualitype.com> - bug 360894 |
11 |
*******************************************************************************/ |
12 |
*******************************************************************************/ |
12 |
package org.eclipse.pde.internal.ui.editor.plugin; |
13 |
package org.eclipse.pde.internal.ui.editor.plugin; |
13 |
|
14 |
|
14 |
import java.util.*; |
15 |
import java.util.*; |
15 |
import org.eclipse.core.resources.IProject; |
16 |
import org.eclipse.core.resources.IProject; |
16 |
import org.eclipse.core.runtime.*; |
17 |
import org.eclipse.core.runtime.*; |
|
|
18 |
import org.eclipse.core.runtime.Path; |
19 |
import org.eclipse.core.runtime.jobs.IJobChangeEvent; |
20 |
import org.eclipse.core.runtime.jobs.JobChangeAdapter; |
17 |
import org.eclipse.jface.action.*; |
21 |
import org.eclipse.jface.action.*; |
18 |
import org.eclipse.jface.dialogs.IMessageProvider; |
22 |
import org.eclipse.jface.dialogs.IMessageProvider; |
|
|
23 |
import org.eclipse.jface.resource.JFaceResources; |
19 |
import org.eclipse.jface.util.IPropertyChangeListener; |
24 |
import org.eclipse.jface.util.IPropertyChangeListener; |
20 |
import org.eclipse.jface.util.PropertyChangeEvent; |
25 |
import org.eclipse.jface.util.PropertyChangeEvent; |
21 |
import org.eclipse.jface.viewers.*; |
26 |
import org.eclipse.jface.viewers.*; |
Lines 30-83
Link Here
|
30 |
import org.eclipse.pde.internal.core.schema.SchemaRegistry; |
35 |
import org.eclipse.pde.internal.core.schema.SchemaRegistry; |
31 |
import org.eclipse.pde.internal.core.text.IDocumentElementNode; |
36 |
import org.eclipse.pde.internal.core.text.IDocumentElementNode; |
32 |
import org.eclipse.pde.internal.core.text.plugin.PluginBaseNode; |
37 |
import org.eclipse.pde.internal.core.text.plugin.PluginBaseNode; |
|
|
38 |
import org.eclipse.pde.internal.core.text.plugin.PluginExtensionNode; |
33 |
import org.eclipse.pde.internal.ui.*; |
39 |
import org.eclipse.pde.internal.ui.*; |
34 |
import org.eclipse.pde.internal.ui.editor.*; |
40 |
import org.eclipse.pde.internal.ui.editor.*; |
35 |
import org.eclipse.pde.internal.ui.editor.actions.CollapseAction; |
41 |
import org.eclipse.pde.internal.ui.editor.actions.*; |
36 |
import org.eclipse.pde.internal.ui.editor.actions.SortAction; |
|
|
37 |
import org.eclipse.pde.internal.ui.editor.contentassist.XMLElementProposalComputer; |
42 |
import org.eclipse.pde.internal.ui.editor.contentassist.XMLElementProposalComputer; |
38 |
import org.eclipse.pde.internal.ui.elements.DefaultContentProvider; |
43 |
import org.eclipse.pde.internal.ui.elements.DefaultContentProvider; |
39 |
import org.eclipse.pde.internal.ui.parts.TreePart; |
44 |
import org.eclipse.pde.internal.ui.parts.TreePart; |
|
|
45 |
import org.eclipse.pde.internal.ui.search.ExtensionsPatternFilter; |
40 |
import org.eclipse.pde.internal.ui.search.PluginSearchActionGroup; |
46 |
import org.eclipse.pde.internal.ui.search.PluginSearchActionGroup; |
41 |
import org.eclipse.pde.internal.ui.util.SWTUtil; |
47 |
import org.eclipse.pde.internal.ui.util.*; |
42 |
import org.eclipse.pde.internal.ui.wizards.extension.ExtensionEditorWizard; |
48 |
import org.eclipse.pde.internal.ui.wizards.extension.ExtensionEditorWizard; |
43 |
import org.eclipse.pde.internal.ui.wizards.extension.NewExtensionWizard; |
49 |
import org.eclipse.pde.internal.ui.wizards.extension.NewExtensionWizard; |
44 |
import org.eclipse.pde.ui.IExtensionEditorWizard; |
50 |
import org.eclipse.pde.ui.IExtensionEditorWizard; |
45 |
import org.eclipse.swt.SWT; |
51 |
import org.eclipse.swt.SWT; |
46 |
import org.eclipse.swt.custom.BusyIndicator; |
52 |
import org.eclipse.swt.custom.BusyIndicator; |
|
|
53 |
import org.eclipse.swt.dnd.Clipboard; |
47 |
import org.eclipse.swt.events.*; |
54 |
import org.eclipse.swt.events.*; |
48 |
import org.eclipse.swt.graphics.Cursor; |
55 |
import org.eclipse.swt.graphics.*; |
49 |
import org.eclipse.swt.graphics.Image; |
|
|
50 |
import org.eclipse.swt.internal.BidiUtil; |
56 |
import org.eclipse.swt.internal.BidiUtil; |
51 |
import org.eclipse.swt.widgets.*; |
57 |
import org.eclipse.swt.widgets.*; |
52 |
import org.eclipse.ui.actions.ActionContext; |
58 |
import org.eclipse.ui.actions.ActionContext; |
53 |
import org.eclipse.ui.actions.ActionFactory; |
59 |
import org.eclipse.ui.actions.ActionFactory; |
54 |
import org.eclipse.ui.dialogs.PatternFilter; |
|
|
55 |
import org.eclipse.ui.forms.widgets.FormToolkit; |
60 |
import org.eclipse.ui.forms.widgets.FormToolkit; |
56 |
import org.eclipse.ui.forms.widgets.Section; |
61 |
import org.eclipse.ui.forms.widgets.Section; |
|
|
62 |
import org.eclipse.ui.progress.WorkbenchJob; |
57 |
|
63 |
|
58 |
public class ExtensionsSection extends TreeSection implements IModelChangedListener, IPropertyChangeListener { |
64 |
public class ExtensionsSection extends TreeSection implements IModelChangedListener, IPropertyChangeListener { |
|
|
65 |
private static final int REFRESHJOB_DELAY_TIME = 1200; // milliseconds to wait |
66 |
private static final int ACCELERATED_SCROLLING = 15; // lines to skip |
59 |
private static final int BUTTON_MOVE_DOWN = 4; |
67 |
private static final int BUTTON_MOVE_DOWN = 4; |
60 |
private static final int BUTTON_MOVE_UP = 3; |
68 |
private static final int BUTTON_MOVE_UP = 3; |
61 |
private static final int BUTTON_EDIT = 2; |
69 |
private static final int BUTTON_EDIT = 2; |
62 |
private static final int BUTTON_REMOVE = 1; |
70 |
private static final int BUTTON_REMOVE = 1; |
|
|
71 |
private static final int BUTTON_ADD = 0; |
63 |
private TreeViewer fExtensionTree; |
72 |
private TreeViewer fExtensionTree; |
64 |
private Image fExtensionImage; |
73 |
private Image fExtensionImage; |
65 |
private Image fGenericElementImage; |
74 |
private Image fGenericElementImage; |
66 |
private FormFilteredTree fFilteredTree; |
75 |
private FormFilteredTree fFilteredTree; |
|
|
76 |
private ExtensionsPatternFilter fPatternFilter; |
67 |
private SchemaRegistry fSchemaRegistry; |
77 |
private SchemaRegistry fSchemaRegistry; |
68 |
private Hashtable fEditorWizards; |
78 |
private Hashtable fEditorWizards; |
69 |
private SortAction fSortAction; |
79 |
private SortAction fSortAction; |
70 |
private CollapseAction fCollapseAction; |
80 |
private CollapseAction fCollapseAction; |
|
|
81 |
private ToggleExpandStateAction fExpandAction; |
82 |
private FilterRelatedExtensionsAction fFilterRelatedAction; |
83 |
private SearchExtensionsAction fSearchAction; |
84 |
private boolean fBypassFilterDelay = false; |
71 |
|
85 |
|
72 |
private static final int BUTTON_ADD = 0; |
86 |
/** |
73 |
|
87 |
* <code>label, name, class, id, commandId, property, activityId, attribute, value</code> |
74 |
private static final String[] COMMON_LABEL_PROPERTIES = {"label", //$NON-NLS-1$ |
88 |
* <br> |
75 |
"name", //$NON-NLS-1$ |
89 |
* While adding elements to the array at the end is possible without concern, changing |
76 |
"id", //$NON-NLS-1$ |
90 |
* previous elements requires to refactor occurences with indexed access to the array. |
77 |
"commandId", //$NON-NLS-1$ |
91 |
*/ |
78 |
"activityId"}; //$NON-NLS-1$ |
92 |
// TODO common label properties might be configured through preferences |
|
|
93 |
public static final String[] COMMON_LABEL_ATTRIBUTES = {"label", //$NON-NLS-1$ |
94 |
"name", "locationURI", "class", "id", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
95 |
"commandId", "property", "activityId", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
96 |
"attribute", "value"}; //$NON-NLS-1$ //$NON-NLS-2$ |
79 |
|
97 |
|
80 |
private static final String[] VALID_IMAGE_TYPES = {"png", "bmp", "ico", "gif", "jpg", "tiff"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ |
98 |
private static final String[] VALID_IMAGE_TYPES = {"png", "bmp", "ico", "gif", "jpg", "tiff"}; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$ |
|
|
99 |
private static final String MENU_NEW_ID = "NewMenu"; //$NON-NLS-1$ |
81 |
|
100 |
|
82 |
class ExtensionContentProvider extends DefaultContentProvider implements ITreeContentProvider { |
101 |
class ExtensionContentProvider extends DefaultContentProvider implements ITreeContentProvider { |
83 |
public Object[] getChildren(Object parent) { |
102 |
public Object[] getChildren(Object parent) { |
Lines 112-124
Link Here
|
112 |
} |
131 |
} |
113 |
} |
132 |
} |
114 |
|
133 |
|
115 |
class ExtensionLabelProvider extends LabelProvider { |
134 |
class ExtensionLabelProvider extends LabelProvider implements IFontProvider { |
116 |
public String getText(Object obj) { |
135 |
public String getText(Object obj) { |
117 |
return resolveObjectName(obj); |
136 |
return resolveObjectName(obj); |
118 |
} |
137 |
} |
119 |
|
138 |
|
120 |
public Image getImage(Object obj) { |
139 |
public Image getImage(Object obj) { |
121 |
return resolveObjectImage(obj); |
140 |
return resolveObjectImage(obj); |
|
|
141 |
} |
142 |
|
143 |
public Font getFont(Object element) { |
144 |
if (fFilteredTree.isFiltered() && fPatternFilter.getMatchingLeafs().contains(element)) { |
145 |
return JFaceResources.getFontRegistry().getBold(JFaceResources.DIALOG_FONT); |
146 |
} |
147 |
return null; |
122 |
} |
148 |
} |
123 |
} |
149 |
} |
124 |
|
150 |
|
Lines 221-229
Link Here
|
221 |
section.setText(PDEUIMessages.ManifestEditor_DetailExtension_title); |
247 |
section.setText(PDEUIMessages.ManifestEditor_DetailExtension_title); |
222 |
initialize((IPluginModelBase) getPage().getModel()); |
248 |
initialize((IPluginModelBase) getPage().getModel()); |
223 |
createSectionToolbar(section, toolkit); |
249 |
createSectionToolbar(section, toolkit); |
|
|
250 |
// accelerated tree scrolling enabled |
251 |
fFilteredTree.addMouseWheelListener(new AcceleratedTreeScrolling(fExtensionTree.getTree(), ACCELERATED_SCROLLING)); |
224 |
// Create the adapted listener for the filter entry field |
252 |
// Create the adapted listener for the filter entry field |
225 |
fFilteredTree.createUIListenerEntryFilter(this); |
253 |
fFilteredTree.createUIListenerEntryFilter(this); |
226 |
Text filterText = fFilteredTree.getFilterControl(); |
254 |
final Text filterText = fFilteredTree.getFilterControl(); |
227 |
if (filterText != null) { |
255 |
if (filterText != null) { |
228 |
filterText.addModifyListener(new ModifyListener() { |
256 |
filterText.addModifyListener(new ModifyListener() { |
229 |
public void modifyText(ModifyEvent e) { |
257 |
public void modifyText(ModifyEvent e) { |
Lines 252-260
Link Here
|
252 |
} |
280 |
} |
253 |
} |
281 |
} |
254 |
}); |
282 |
}); |
|
|
283 |
// Add action to filter tree with some of the selection's attributes |
284 |
fFilterRelatedAction = new FilterRelatedExtensionsAction(fExtensionTree, fFilteredTree, this, false); |
285 |
toolBarManager.add(fFilterRelatedAction); |
286 |
// Add action to search all workspace plugins with current filtering applied to the tree viewer |
287 |
fSearchAction = new SearchExtensionsAction(fFilteredTree, PDEUIMessages.ExtensionsPage_searchWithExtensionsFilter); |
288 |
toolBarManager.add(fSearchAction); |
289 |
// Add separator |
290 |
Separator separator = new Separator(); |
291 |
toolBarManager.add(separator); |
255 |
// Add sort action to the tool bar |
292 |
// Add sort action to the tool bar |
256 |
fSortAction = new SortAction(fExtensionTree, PDEUIMessages.ExtensionsPage_sortAlpha, null, null, this); |
293 |
fSortAction = new SortAction(fExtensionTree, PDEUIMessages.ExtensionsPage_sortAlpha, null, null, this) { |
|
|
294 |
public void run() { |
295 |
Object[] expanded = fFilteredTree.getViewer().getVisibleExpandedElements(); |
296 |
try { |
297 |
fFilteredTree.setRedraw(false); |
298 |
super.run(); |
299 |
// bugfix: retain tree expand state after sort action |
300 |
fFilteredTree.getViewer().setExpandedElements(expanded); |
301 |
} finally { |
302 |
fFilteredTree.setRedraw(true); |
303 |
} |
304 |
} |
305 |
}; |
257 |
toolBarManager.add(fSortAction); |
306 |
toolBarManager.add(fSortAction); |
|
|
307 |
// Add expand selected leafs action to the toolbar |
308 |
fExpandAction = new ToggleExpandStateAction(fFilteredTree, fExtensionTree); |
309 |
toolBarManager.add(fExpandAction); |
258 |
// Add collapse action to the tool bar |
310 |
// Add collapse action to the tool bar |
259 |
fCollapseAction = new CollapseAction(fExtensionTree, PDEUIMessages.ExtensionsPage_collapseAll); |
311 |
fCollapseAction = new CollapseAction(fExtensionTree, PDEUIMessages.ExtensionsPage_collapseAll); |
260 |
toolBarManager.add(fCollapseAction); |
312 |
toolBarManager.add(fCollapseAction); |
Lines 309-319
Link Here
|
309 |
* @see org.eclipse.pde.internal.ui.editor.PDESection#doGlobalAction(java.lang.String) |
361 |
* @see org.eclipse.pde.internal.ui.editor.PDESection#doGlobalAction(java.lang.String) |
310 |
*/ |
362 |
*/ |
311 |
public boolean doGlobalAction(String actionId) { |
363 |
public boolean doGlobalAction(String actionId) { |
312 |
|
364 |
if (actionId.equals(ActionFactory.FIND.getId()) && fFilterRelatedAction != null) { |
|
|
365 |
fFilterRelatedAction.run(); |
366 |
return true; |
367 |
} |
313 |
if (!isEditable()) { |
368 |
if (!isEditable()) { |
314 |
return false; |
369 |
return false; |
315 |
} |
370 |
} |
316 |
|
|
|
317 |
if (actionId.equals(ActionFactory.DELETE.getId())) { |
371 |
if (actionId.equals(ActionFactory.DELETE.getId())) { |
318 |
handleDelete(); |
372 |
handleDelete(); |
319 |
return true; |
373 |
return true; |
Lines 348-360
Link Here
|
348 |
|
402 |
|
349 |
protected void fillContextMenu(IMenuManager manager) { |
403 |
protected void fillContextMenu(IMenuManager manager) { |
350 |
ISelection selection = fExtensionTree.getSelection(); |
404 |
ISelection selection = fExtensionTree.getSelection(); |
351 |
IStructuredSelection ssel = (IStructuredSelection) selection; |
405 |
final IStructuredSelection ssel = (IStructuredSelection) selection; |
352 |
if (ssel.size() == 1) { |
406 |
if (ssel.size() == 1) { |
353 |
Object object = ssel.getFirstElement(); |
407 |
Object object = ssel.getFirstElement(); |
354 |
if (object instanceof IPluginParent) { |
408 |
if (object instanceof IPluginParent) { |
355 |
IPluginParent parent = (IPluginParent) object; |
409 |
IPluginParent parent = (IPluginParent) object; |
356 |
if (parent.getModel().getUnderlyingResource() != null) { |
410 |
if (parent.getModel().getUnderlyingResource() != null) { |
357 |
fillContextMenu(getPage(), parent, manager); |
411 |
boolean removeEnabled = !fFilteredTree.isFiltered() || isRemoveEnabled(ssel); |
|
|
412 |
fillContextMenu(getPage(), parent, manager, false, removeEnabled); |
358 |
manager.add(new Separator()); |
413 |
manager.add(new Separator()); |
359 |
} |
414 |
} |
360 |
} |
415 |
} |
Lines 366-371
Link Here
|
366 |
manager.add(new Separator()); |
421 |
manager.add(new Separator()); |
367 |
} |
422 |
} |
368 |
} else if (ssel.size() > 1) { |
423 |
} else if (ssel.size() > 1) { |
|
|
424 |
boolean removeEnabled = !fFilteredTree.isFiltered() || isRemoveEnabled(ssel); |
369 |
// multiple |
425 |
// multiple |
370 |
Action delAction = new Action() { |
426 |
Action delAction = new Action() { |
371 |
public void run() { |
427 |
public void run() { |
Lines 375-388
Link Here
|
375 |
delAction.setText(PDEUIMessages.Actions_delete_label); |
431 |
delAction.setText(PDEUIMessages.Actions_delete_label); |
376 |
manager.add(delAction); |
432 |
manager.add(delAction); |
377 |
manager.add(new Separator()); |
433 |
manager.add(new Separator()); |
378 |
delAction.setEnabled(isEditable()); |
434 |
delAction.setEnabled(isEditable() && removeEnabled); |
|
|
435 |
} |
436 |
if (ssel.size() > 0) { |
437 |
if (ExtensionsFilterUtil.isFilterRelatedEnabled(ssel)) { |
438 |
FilterRelatedExtensionsAction filterRelatedAction = new FilterRelatedExtensionsAction(fExtensionTree, fFilteredTree, this, true); |
439 |
manager.add(filterRelatedAction); |
440 |
SearchExtensionsAction searchRelatedAction = new SearchExtensionsAction(ssel, PDEUIMessages.Actions_search_relatedPluginElements); |
441 |
manager.add(searchRelatedAction); |
442 |
manager.add(new Separator()); |
443 |
} |
379 |
} |
444 |
} |
380 |
manager.add(new Separator()); |
445 |
manager.add(new Separator()); |
|
|
446 |
|
447 |
if (fFilteredTree.isFiltered()) { |
448 |
// Add action to reveal all extensions when the tree is in filter mode |
449 |
ShowAllExtensionsAction fShowAllAction = new ShowAllExtensionsAction(getPage().getModel(), fFilteredTree, fPatternFilter); |
450 |
if (manager.find(MENU_NEW_ID) != null) { |
451 |
manager.insertAfter(MENU_NEW_ID, fShowAllAction); |
452 |
} else { |
453 |
manager.add(fShowAllAction); |
454 |
manager.add(new Separator()); |
455 |
} |
456 |
} |
381 |
if (ssel.size() < 2) { // only cut things when the selection is one |
457 |
if (ssel.size() < 2) { // only cut things when the selection is one |
382 |
getPage().getPDEEditor().getContributor().addClipboardActions(manager); |
458 |
getPage().getPDEEditor().getContributor().addClipboardActions(manager); |
383 |
} |
459 |
} |
384 |
getPage().getPDEEditor().getContributor().contextMenuAboutToShow(manager, false); |
460 |
getPage().getPDEEditor().getContributor().contextMenuAboutToShow(manager, false); |
385 |
|
461 |
this.fFilteredTree.update(); |
386 |
} |
462 |
} |
387 |
|
463 |
|
388 |
static IMenuManager fillContextMenu(PDEFormPage page, final IPluginParent parent, IMenuManager manager) { |
464 |
static IMenuManager fillContextMenu(PDEFormPage page, final IPluginParent parent, IMenuManager manager) { |
Lines 394-400
Link Here
|
394 |
} |
470 |
} |
395 |
|
471 |
|
396 |
static IMenuManager fillContextMenu(PDEFormPage page, final IPluginParent parent, IMenuManager manager, boolean addSiblingItems, boolean fullMenu) { |
472 |
static IMenuManager fillContextMenu(PDEFormPage page, final IPluginParent parent, IMenuManager manager, boolean addSiblingItems, boolean fullMenu) { |
397 |
MenuManager menu = new MenuManager(PDEUIMessages.Menus_new_label); |
473 |
MenuManager menu = new MenuManager(PDEUIMessages.Menus_new_label, MENU_NEW_ID); |
398 |
IPluginExtension extension = getExtension(parent); |
474 |
IPluginExtension extension = getExtension(parent); |
399 |
ISchema schema = getSchema(extension); |
475 |
ISchema schema = getSchema(extension); |
400 |
if (schema == null) { |
476 |
if (schema == null) { |
Lines 493-498
Link Here
|
493 |
} |
569 |
} |
494 |
} |
570 |
} |
495 |
|
571 |
|
|
|
572 |
public FormFilteredTree getFormFilteredTree() { |
573 |
return fFilteredTree; |
574 |
} |
575 |
|
576 |
/** |
577 |
* Adds another value to filter text and a preceding separator character if necessary. |
578 |
* Empty values as well as <code>true</code> and <code>false</code> are omitted. |
579 |
* |
580 |
* @param attributeValue Value to be trimmed and added to the filter text |
581 |
* @param clearFilterText When <code>true</code> the filter text is replaced with the attribute value, appended otherwise. |
582 |
*/ |
583 |
public void addAttributeToFilter(String attributeValue, boolean clearFilterText) { |
584 |
Text filterControl = fFilteredTree.getFilterControl(); |
585 |
if (filterControl != null && attributeValue != null) { |
586 |
String trimmedValue = attributeValue.trim(); |
587 |
if (trimmedValue.length() > 0 && ExtensionsFilterUtil.isNotBoolean(trimmedValue)) { |
588 |
if (trimmedValue.startsWith("%")) {//$NON-NLS-1$ |
589 |
IPluginModelBase model = getPluginModelBase(); |
590 |
trimmedValue = ((model != null) ? model.getResourceString(trimmedValue) : trimmedValue).replaceAll("\"", ""); //$NON-NLS-1$ //$NON-NLS-2$ |
591 |
} |
592 |
String filterPattern; |
593 |
if (clearFilterText) { |
594 |
filterPattern = trimmedValue; |
595 |
} else { |
596 |
filterPattern = filterControl.getText(); |
597 |
if (filterPattern.length() > 0 && !filterPattern.endsWith("/")) { //$NON-NLS-1$ |
598 |
filterPattern += "/"; //$NON-NLS-1$ |
599 |
} |
600 |
filterPattern += trimmedValue; |
601 |
} |
602 |
if (filterPattern.indexOf('/') != -1) { // quote when |
603 |
filterPattern = "\"" + filterPattern + "\""; //$NON-NLS-1$ //$NON-NLS-2$ |
604 |
} |
605 |
setBypassFilterDelay(true); // force immediate job run |
606 |
filterControl.setText(filterPattern); |
607 |
} |
608 |
} |
609 |
} |
610 |
|
496 |
private void handleNew() { |
611 |
private void handleNew() { |
497 |
final IProject project = getPage().getPDEEditor().getCommonProject(); |
612 |
final IProject project = getPage().getPDEEditor().getCommonProject(); |
498 |
BusyIndicator.showWhile(fExtensionTree.getTree().getDisplay(), new Runnable() { |
613 |
BusyIndicator.showWhile(fExtensionTree.getTree().getDisplay(), new Runnable() { |
Lines 555-560
Link Here
|
555 |
|
670 |
|
556 |
private void handleSelectAll() { |
671 |
private void handleSelectAll() { |
557 |
fExtensionTree.getTree().selectAll(); |
672 |
fExtensionTree.getTree().selectAll(); |
|
|
673 |
updateButtons(fFilteredTree.getViewer().getSelection()); |
558 |
} |
674 |
} |
559 |
|
675 |
|
560 |
private ArrayList getEditorWizards(IStructuredSelection selection) { |
676 |
private ArrayList getEditorWizards(IStructuredSelection selection) { |
Lines 643-655
Link Here
|
643 |
// The model changed but the editor is still open, we should try to retain expansion, selection will be retained on its own |
759 |
// The model changed but the editor is still open, we should try to retain expansion, selection will be retained on its own |
644 |
Object[] expanded = fExtensionTree.getExpandedElements(); |
760 |
Object[] expanded = fExtensionTree.getExpandedElements(); |
645 |
IPluginModelBase model = (IPluginModelBase) getPage().getModel(); |
761 |
IPluginModelBase model = (IPluginModelBase) getPage().getModel(); |
646 |
fExtensionTree.getControl().setRedraw(false); |
762 |
int[] indexPath = getTreeIndexPath(fExtensionTree.getTree()); |
647 |
fExtensionTree.setInput(model.getPluginBase()); |
763 |
try { |
648 |
fExtensionTree.setExpandedElements(expanded); |
764 |
fExtensionTree.getControl().setRedraw(false); |
649 |
fExtensionTree.getControl().setRedraw(true); |
765 |
fExtensionTree.setInput(model.getPluginBase()); |
650 |
reportMissingExtensionPointSchemas(model.getPluginBase()); |
766 |
fExtensionTree.setExpandedElements(expanded); |
651 |
getManagedForm().fireSelectionChanged(ExtensionsSection.this, fExtensionTree.getSelection()); |
767 |
|
652 |
super.refresh(); |
768 |
reportMissingExtensionPointSchemas(model.getPluginBase()); |
|
|
769 |
getManagedForm().fireSelectionChanged(ExtensionsSection.this, fExtensionTree.getSelection()); |
770 |
super.refresh(); |
771 |
|
772 |
if (indexPath != null) { |
773 |
// fix for Bug 371066 |
774 |
revealTopItem(fExtensionTree.getTree(), indexPath); |
775 |
} |
776 |
} finally { |
777 |
fExtensionTree.getControl().setRedraw(true); |
778 |
} |
779 |
} |
780 |
|
781 |
private static int[] getTreeIndexPath(Tree tree) { |
782 |
int[] indexPath = null; |
783 |
if (tree != null) { |
784 |
TreeItem item = tree.getTopItem(); |
785 |
int count = 1; |
786 |
while (item != null && (item = item.getParentItem()) != null) { |
787 |
count++; |
788 |
} |
789 |
indexPath = new int[count]; |
790 |
int index = 0; |
791 |
item = tree.getTopItem(); |
792 |
while (item != null && index < count) { |
793 |
TreeItem parent = item.getParentItem(); |
794 |
if (parent != null) { |
795 |
indexPath[index++] = parent.indexOf(item); |
796 |
} else { |
797 |
indexPath[index++] = tree.indexOf(item); |
798 |
} |
799 |
item = parent; |
800 |
} |
801 |
} |
802 |
return indexPath; |
803 |
} |
804 |
|
805 |
private static void revealTopItem(Tree tree, int[] indexPath) { |
806 |
TreeItem itemFound = null; |
807 |
for (int i = indexPath.length - 1; i >= 0; i--) { |
808 |
int index = indexPath[i]; |
809 |
if (itemFound != null) { |
810 |
itemFound = (itemFound.getItemCount() > index) ? itemFound.getItem(indexPath[i]) : null; |
811 |
} else if (i == indexPath.length - 1) { |
812 |
itemFound = (tree.getItemCount() > index) ? tree.getItem(indexPath[i]) : null; |
813 |
} |
814 |
} |
815 |
if (itemFound != null) { |
816 |
tree.setTopItem(itemFound); |
817 |
} |
653 |
} |
818 |
} |
654 |
|
819 |
|
655 |
public void modelChanged(IModelChangedEvent event) { |
820 |
public void modelChanged(IModelChangedEvent event) { |
Lines 669-674
Link Here
|
669 |
IPluginObject pobj = (IPluginObject) changeObject; |
834 |
IPluginObject pobj = (IPluginObject) changeObject; |
670 |
IPluginObject parent = changeObject instanceof IPluginExtension ? ((IPluginModelBase) getPage().getModel()).getPluginBase() : pobj.getParent(); |
835 |
IPluginObject parent = changeObject instanceof IPluginExtension ? ((IPluginModelBase) getPage().getModel()).getPluginBase() : pobj.getParent(); |
671 |
if (event.getChangeType() == IModelChangedEvent.INSERT) { |
836 |
if (event.getChangeType() == IModelChangedEvent.INSERT) { |
|
|
837 |
// enables adding extensions while tree is filtered |
838 |
if (fFilteredTree.isFiltered()) { |
839 |
Object[] inserted = event.getChangedObjects(); |
840 |
for (int i = 0; i < inserted.length; i++) { |
841 |
fPatternFilter.addElement(inserted[i]); |
842 |
} |
843 |
if (inserted.length == 1) { |
844 |
fFilteredTree.getViewer().setSelection(new StructuredSelection(inserted[0])); |
845 |
} |
846 |
} |
847 |
|
848 |
// |
672 |
fExtensionTree.refresh(parent); |
849 |
fExtensionTree.refresh(parent); |
673 |
if (changeObject instanceof IPluginExtension) { |
850 |
if (changeObject instanceof IPluginExtension) { |
674 |
IPluginExtension ext = (IPluginExtension) changeObject; |
851 |
IPluginExtension ext = (IPluginExtension) changeObject; |
Lines 809-817
Link Here
|
809 |
if (labelAtt == null) { |
986 |
if (labelAtt == null) { |
810 |
// try some hard-coded attributes that |
987 |
// try some hard-coded attributes that |
811 |
// are used frequently |
988 |
// are used frequently |
812 |
for (int i = 0; i < COMMON_LABEL_PROPERTIES.length; i++) { |
989 |
for (int i = 0; i < COMMON_LABEL_ATTRIBUTES.length; i++) { |
813 |
labelAtt = element.getAttribute(COMMON_LABEL_PROPERTIES[i]); |
990 |
labelAtt = element.getAttribute(COMMON_LABEL_ATTRIBUTES[i]); |
814 |
if (labelAtt != null) |
991 |
if (labelAtt != null && labelAtt.getValue().length() > 0) |
815 |
break; |
992 |
break; |
816 |
} |
993 |
} |
817 |
if (labelAtt == null) { |
994 |
if (labelAtt == null) { |
Lines 821-829
Link Here
|
821 |
labelAtt = element.getAttributes()[0]; |
998 |
labelAtt = element.getAttributes()[0]; |
822 |
} |
999 |
} |
823 |
} |
1000 |
} |
824 |
if (labelAtt != null && labelAtt.getValue() != null) |
1001 |
if (labelAtt != null && labelAtt.getValue() != null) { |
825 |
fullName = stripShortcuts(labelAtt.getValue()); |
1002 |
fullName = stripShortcuts(labelAtt.getValue()); |
|
|
1003 |
if (labelAtt.getName().equals(COMMON_LABEL_ATTRIBUTES[3])) { // remove package from handler class |
1004 |
fullName = fullName.substring(fullName.lastIndexOf('.') + 1, fullName.length()); |
1005 |
} |
1006 |
} |
826 |
fullName = element.getResourceString(fullName); |
1007 |
fullName = element.getResourceString(fullName); |
|
|
1008 |
|
827 |
if (fullNames) |
1009 |
if (fullNames) |
828 |
return fullName != null ? fullName : baseName; |
1010 |
return fullName != null ? fullName : baseName; |
829 |
if (fullName == null) |
1011 |
if (fullName == null) |
Lines 836-847
Link Here
|
836 |
return fullName + " \u200f(\u200e" + baseName + ")"; //$NON-NLS-1$ //$NON-NLS-2$ |
1018 |
return fullName + " \u200f(\u200e" + baseName + ")"; //$NON-NLS-1$ //$NON-NLS-2$ |
837 |
return fullName + " (" + baseName + ')'; //$NON-NLS-1$ |
1019 |
return fullName + " (" + baseName + ')'; //$NON-NLS-1$ |
838 |
} |
1020 |
} |
839 |
return obj.toString(); |
1021 |
if (obj != null) { |
|
|
1022 |
return obj.toString(); |
1023 |
} |
1024 |
return new String(); |
840 |
} |
1025 |
} |
841 |
|
1026 |
|
842 |
public void setFocus() { |
1027 |
public void setFocus() { |
843 |
if (fExtensionTree != null) |
1028 |
if (fExtensionTree != null) |
844 |
fExtensionTree.getTree().setFocus(); |
1029 |
fExtensionTree.getTree().setFocus(); |
|
|
1030 |
} |
1031 |
|
1032 |
/** |
1033 |
* Temporarily bypasses default {@link FormFilteredTree#getRefreshJobDelay()} for several actions to immediatly start tree |
1034 |
* filtering. Only the next job to call <code>getRefreshJobDelay()</code> will be affected and reset this value. |
1035 |
* |
1036 |
* @param bypassFilterDelay <code>true</code> bypasses the refresh job delay by overriding it with <code>0</code> |
1037 |
*/ |
1038 |
public void setBypassFilterDelay(boolean bypassFilterDelay) { |
1039 |
fBypassFilterDelay = bypassFilterDelay; |
845 |
} |
1040 |
} |
846 |
|
1041 |
|
847 |
public static String stripShortcuts(String input) { |
1042 |
public static String stripShortcuts(String input) { |
Lines 855-860
Link Here
|
855 |
output.append(c); |
1050 |
output.append(c); |
856 |
} |
1051 |
} |
857 |
return output.toString(); |
1052 |
return output.toString(); |
|
|
1053 |
} |
1054 |
|
1055 |
public boolean canCopy(ISelection selection) { |
1056 |
// Partial fix for Bug 360079, enables Ctrl+C in filter text if plugin model is editable |
1057 |
if (fFilteredTree.getFilterControl().isFocusControl() && !selection.isEmpty()) { |
1058 |
return true; |
1059 |
} |
1060 |
// TODO enable copy also when plugin model is not editable |
1061 |
return super.canCopy(selection); |
1062 |
} |
1063 |
|
1064 |
public boolean canPaste(Clipboard clipboard) { |
1065 |
// Partial fix for Bug 360079, enables Ctrl+V in filter text if plugin model is editable |
1066 |
if (fFilteredTree.getFilterControl().isFocusControl()) { |
1067 |
return true; |
1068 |
} |
1069 |
// TODO enable paste also when plugin model is not editable |
1070 |
return super.canPaste(clipboard); |
858 |
} |
1071 |
} |
859 |
|
1072 |
|
860 |
/* (non-Javadoc) |
1073 |
/* (non-Javadoc) |
Lines 1081-1086
Link Here
|
1081 |
} |
1294 |
} |
1082 |
|
1295 |
|
1083 |
private void updateButtons(Object item) { |
1296 |
private void updateButtons(Object item) { |
|
|
1297 |
if (fExpandAction != null) { |
1298 |
fExpandAction.setEnabled(ToggleExpandStateAction.isExpandable((IStructuredSelection) fExtensionTree.getSelection())); |
1299 |
} |
1300 |
if (fFilterRelatedAction != null) { |
1301 |
fFilterRelatedAction.setEnabled(ExtensionsFilterUtil.isFilterRelatedEnabled((IStructuredSelection) fExtensionTree.getSelection())); |
1302 |
} |
1303 |
if (fSearchAction != null) { |
1304 |
Text filterControl = fFilteredTree.getFilterControl(); |
1305 |
boolean searchEnabled = filterControl != null && filterControl.getText().length() > 0; |
1306 |
fSearchAction.setEnabled(searchEnabled); |
1307 |
} |
1308 |
|
1084 |
if (getPage().getModel().isEditable() == false) |
1309 |
if (getPage().getModel().isEditable() == false) |
1085 |
return; |
1310 |
return; |
1086 |
boolean sorted = fSortAction != null && fSortAction.isChecked(); |
1311 |
boolean sorted = fSortAction != null && fSortAction.isChecked(); |
Lines 1089-1132
Link Here
|
1089 |
getTreePart().setButtonEnabled(BUTTON_MOVE_DOWN, false); |
1314 |
getTreePart().setButtonEnabled(BUTTON_MOVE_DOWN, false); |
1090 |
return; |
1315 |
return; |
1091 |
} |
1316 |
} |
|
|
1317 |
IStructuredSelection selection = (item instanceof IStructuredSelection) ? (IStructuredSelection) item : null; |
1092 |
|
1318 |
|
1093 |
boolean filtered = fFilteredTree.isFiltered(); |
1319 |
boolean filtered = fFilteredTree.isFiltered(); |
1094 |
boolean addEnabled = true; |
1320 |
boolean addEnabled = true; |
1095 |
boolean removeEnabled = false; |
1321 |
boolean removeEnabled = true; |
1096 |
boolean upEnabled = false; |
1322 |
boolean upEnabled = false; |
1097 |
boolean downEnabled = false; |
1323 |
boolean downEnabled = false; |
1098 |
|
1324 |
|
1099 |
if (item != null) { |
|
|
1100 |
removeEnabled = true; |
1101 |
} |
1102 |
if (filtered) { |
1325 |
if (filtered) { |
1103 |
// Fix for bug 194529 and bug 194828 |
1326 |
// Fix for bug 194529 and bug 194828 |
1104 |
addEnabled = false; |
1327 |
// Update: adding during filtering enabled by additional filter capability |
|
|
1328 |
addEnabled = true; |
1105 |
upEnabled = false; |
1329 |
upEnabled = false; |
1106 |
downEnabled = false; |
1330 |
downEnabled = false; |
|
|
1331 |
removeEnabled = isRemoveEnabled(selection); |
1107 |
} else { |
1332 |
} else { |
1108 |
if (item instanceof IStructuredSelection) { |
1333 |
if (selection != null && selection.size() == 1) { |
1109 |
if (((IStructuredSelection) item).size() == 1) { |
1334 |
Object selected = selection.getFirstElement(); |
1110 |
Object selected = ((IStructuredSelection) item).getFirstElement(); |
1335 |
if (selected instanceof IPluginElement) { |
1111 |
if (selected instanceof IPluginElement) { |
1336 |
IPluginElement element = (IPluginElement) selected; |
1112 |
IPluginElement element = (IPluginElement) selected; |
1337 |
IPluginParent parent = (IPluginParent) element.getParent(); |
1113 |
IPluginParent parent = (IPluginParent) element.getParent(); |
1338 |
// check up |
1114 |
// check up |
1339 |
int index = parent.getIndexOf(element); |
1115 |
int index = parent.getIndexOf(element); |
1340 |
if (index > 0) |
1116 |
if (index > 0) |
1341 |
upEnabled = true; |
1117 |
upEnabled = true; |
1342 |
if (index < parent.getChildCount() - 1) |
1118 |
if (index < parent.getChildCount() - 1) |
1343 |
downEnabled = true; |
1119 |
downEnabled = true; |
1344 |
} else if (selected instanceof IPluginExtension) { |
1120 |
} else if (selected instanceof IPluginExtension) { |
1345 |
IPluginExtension extension = (IPluginExtension) selected; |
1121 |
IPluginExtension extension = (IPluginExtension) selected; |
1346 |
IExtensions extensions = (IExtensions) extension.getParent(); |
1122 |
IExtensions extensions = (IExtensions) extension.getParent(); |
1347 |
int index = extensions.getIndexOf(extension); |
1123 |
int index = extensions.getIndexOf(extension); |
1348 |
int size = extensions.getExtensions().length; |
1124 |
int size = extensions.getExtensions().length; |
1349 |
if (index > 0) |
1125 |
if (index > 0) |
1350 |
upEnabled = true; |
1126 |
upEnabled = true; |
1351 |
if (index < size - 1) |
1127 |
if (index < size - 1) |
1352 |
downEnabled = true; |
1128 |
downEnabled = true; |
|
|
1129 |
} |
1130 |
} |
1353 |
} |
1131 |
} |
1354 |
} |
1132 |
} |
1355 |
} |
Lines 1136-1146
Link Here
|
1136 |
getTreePart().setButtonEnabled(BUTTON_MOVE_DOWN, downEnabled); |
1359 |
getTreePart().setButtonEnabled(BUTTON_MOVE_DOWN, downEnabled); |
1137 |
} |
1360 |
} |
1138 |
|
1361 |
|
|
|
1362 |
/** |
1363 |
* Since filtering potentially hides children of extensions, removing them when they still have children is intransparent. |
1364 |
* Needs to be called only when the tree is filtered. |
1365 |
* |
1366 |
* @param selection selection to be tested |
1367 |
* @return whether removing the selected elements is enabled |
1368 |
*/ |
1369 |
boolean isRemoveEnabled(IStructuredSelection selection) { |
1370 |
if (selection != null) { |
1371 |
for (Iterator iterator = selection.iterator(); iterator.hasNext();) { |
1372 |
Object element = iterator.next(); |
1373 |
if (element instanceof PluginExtensionNode) { |
1374 |
return ((PluginExtensionNode) element).getChildCount() == 0; |
1375 |
} |
1376 |
} |
1377 |
} |
1378 |
return true; |
1379 |
} |
1380 |
|
1139 |
/* (non-Javadoc) |
1381 |
/* (non-Javadoc) |
1140 |
* @see org.eclipse.pde.internal.ui.editor.TreeSection#createTreeViewer(org.eclipse.swt.widgets.Composite, int) |
1382 |
* @see org.eclipse.pde.internal.ui.editor.TreeSection#createTreeViewer(org.eclipse.swt.widgets.Composite, int) |
1141 |
*/ |
1383 |
*/ |
1142 |
protected TreeViewer createTreeViewer(Composite parent, int style) { |
1384 |
protected TreeViewer createTreeViewer(Composite parent, int style) { |
1143 |
fFilteredTree = new FormFilteredTree(parent, style, new PatternFilter()); |
1385 |
fPatternFilter = new ExtensionsPatternFilter(); |
|
|
1386 |
fFilteredTree = new FormFilteredTree(parent, style, fPatternFilter) { |
1387 |
protected WorkbenchJob doCreateRefreshJob() { |
1388 |
final WorkbenchJob job = super.doCreateRefreshJob(); |
1389 |
job.addJobChangeListener(new JobChangeAdapter() { |
1390 |
private ISelection selection; |
1391 |
private boolean aboutToRunPassed = false; |
1392 |
|
1393 |
public void scheduled(IJobChangeEvent event) { |
1394 |
((ExtensionsPatternFilter) fFilteredTree.getPatternFilter()).clearMatchingLeafs(); |
1395 |
selection = fExtensionTree.getSelection(); |
1396 |
} |
1397 |
|
1398 |
public void aboutToRun(IJobChangeEvent event) { |
1399 |
aboutToRunPassed = true; |
1400 |
} |
1401 |
|
1402 |
/* |
1403 |
* Restores selection after tree refresh and expands tree up to matching leafs only |
1404 |
*/ |
1405 |
public void done(IJobChangeEvent event) { |
1406 |
if (aboutToRunPassed) { // restoring is only required if the job actually ran |
1407 |
try { |
1408 |
fFilteredTree.setRedraw(false); |
1409 |
ExtensionsPatternFilter extensionsPatternFilter = ((ExtensionsPatternFilter) fFilteredTree.getPatternFilter()); |
1410 |
fExtensionTree.collapseAll(); |
1411 |
Object[] leafs = extensionsPatternFilter.getMatchingLeafsAsArray(); |
1412 |
for (int i = 0; i < leafs.length; i++) { |
1413 |
fExtensionTree.expandToLevel(leafs[i], 0); |
1414 |
} |
1415 |
if (selection != null && !(selection.isEmpty())) { |
1416 |
fExtensionTree.setSelection(selection, true); |
1417 |
} |
1418 |
} finally { |
1419 |
fFilteredTree.setRedraw(true); |
1420 |
} |
1421 |
} |
1422 |
} |
1423 |
}); |
1424 |
return job; |
1425 |
} |
1426 |
|
1427 |
protected long getRefreshJobDelay() { |
1428 |
// Prolonged job delay time is required because of the attribute search being more costly in nature. |
1429 |
// This can block input to the filter text severly. Thus it shouldn't happen when typing slowly. |
1430 |
// The delay of 1500ms is bypassed by some actions that use the filter text to initiate searches or clear the text. |
1431 |
long delay = (fBypassFilterDelay) ? 0 : REFRESHJOB_DELAY_TIME; |
1432 |
setBypassFilterDelay(false); // reset afterwards |
1433 |
return delay; |
1434 |
} |
1435 |
|
1436 |
protected void clearText() { |
1437 |
// bugfix: additional notification with textChanged() would cause a needless 2nd refresh job run |
1438 |
// which in turn would have a longer delay time than the 1st run. |
1439 |
setFilterText(""); //$NON-NLS-1$ |
1440 |
} |
1441 |
|
1442 |
protected void textChanged() { |
1443 |
String filterText = getFilterString(); |
1444 |
if (filterText != null && filterText.length() == 0) { |
1445 |
// clearing the filter text doesn't require a refresh job delay |
1446 |
setBypassFilterDelay(true); |
1447 |
} |
1448 |
super.textChanged(); |
1449 |
} |
1450 |
}; |
1144 |
parent.setData("filtered", Boolean.TRUE); //$NON-NLS-1$ |
1451 |
parent.setData("filtered", Boolean.TRUE); //$NON-NLS-1$ |
1145 |
return fFilteredTree.getViewer(); |
1452 |
return fFilteredTree.getViewer(); |
1146 |
} |
1453 |
} |