1 /******************************************************************************* 2 * Copyright (c) 2014, 2017 TwelveTone LLC and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * Steven Spungin <steven@spungin.tv> - initial API and implementation, Bug 432555, Bug 436889, Bug 437372, Bug 440469, 13 * Ongoing Maintenance 14 *******************************************************************************/ 15 16 package org.eclipse.e4.tools.emf.ui.internal.common.component.tabs; 17 18 import java.io.StringReader; 19 import java.io.StringWriter; 20 import java.util.ArrayList; 21 import java.util.Collection; 22 import java.util.HashSet; 23 import java.util.LinkedHashMap; 24 import java.util.List; 25 import java.util.Map; 26 import java.util.Map.Entry; 27 import java.util.concurrent.ConcurrentHashMap; 28 29 import javax.annotation.PostConstruct; 30 import javax.annotation.PreDestroy; 31 import javax.inject.Inject; 32 import javax.xml.parsers.DocumentBuilderFactory; 33 import javax.xml.parsers.ParserConfigurationException; 34 import javax.xml.transform.OutputKeys; 35 import javax.xml.transform.Transformer; 36 import javax.xml.transform.TransformerException; 37 import javax.xml.transform.TransformerFactory; 38 import javax.xml.transform.dom.DOMSource; 39 import javax.xml.transform.stream.StreamResult; 40 import javax.xml.xpath.XPath; 41 import javax.xml.xpath.XPathConstants; 42 import javax.xml.xpath.XPathFactory; 43 44 import org.eclipse.core.runtime.preferences.IEclipsePreferences; 45 import org.eclipse.core.runtime.preferences.InstanceScope; 46 import org.eclipse.e4.core.contexts.IEclipseContext; 47 import org.eclipse.e4.core.services.nls.Translation; 48 import org.eclipse.e4.tools.emf.ui.common.IModelResource; 49 import org.eclipse.e4.tools.emf.ui.common.ModelEditorPreferences; 50 import org.eclipse.e4.tools.emf.ui.common.Plugin; 51 import org.eclipse.e4.tools.emf.ui.internal.Messages; 52 import org.eclipse.e4.tools.emf.ui.internal.ResourceProvider; 53 import org.eclipse.e4.tools.emf.ui.internal.common.ModelEditor; 54 import org.eclipse.e4.tools.emf.ui.internal.common.component.dialogs.BundleImageCache; 55 import org.eclipse.e4.tools.emf.ui.internal.common.component.tabs.EAttributeEditingSupport.ATT_TYPE; 56 import org.eclipse.e4.tools.emf.ui.internal.common.component.tabs.empty.E; 57 import org.eclipse.e4.tools.emf.ui.internal.common.component.tabs.empty.EmptyFilterOption; 58 import org.eclipse.e4.tools.emf.ui.internal.common.component.tabs.empty.TitleAreaFilterDialog; 59 import org.eclipse.e4.tools.emf.ui.internal.common.component.tabs.empty.TitleAreaFilterDialogWithEmptyOptions; 60 import org.eclipse.e4.tools.emf.ui.internal.common.xml.EMFDocumentResourceMediator; 61 import org.eclipse.e4.tools.services.IResourcePool; 62 import org.eclipse.e4.ui.model.application.MApplication; 63 import org.eclipse.emf.common.command.Command; 64 import org.eclipse.emf.common.util.TreeIterator; 65 import org.eclipse.emf.ecore.EAttribute; 66 import org.eclipse.emf.ecore.EObject; 67 import org.eclipse.emf.ecore.util.EcoreUtil; 68 import org.eclipse.emf.edit.command.DeleteCommand; 69 import org.eclipse.emf.edit.domain.EditingDomain; 70 import org.eclipse.jface.text.DocumentEvent; 71 import org.eclipse.jface.text.IDocumentListener; 72 import org.eclipse.jface.viewers.ArrayContentProvider; 73 import org.eclipse.jface.viewers.ColumnLabelProvider; 74 import org.eclipse.jface.viewers.ILabelProvider; 75 import org.eclipse.jface.viewers.IStructuredSelection; 76 import org.eclipse.jface.viewers.LabelProvider; 77 import org.eclipse.jface.viewers.TableViewer; 78 import org.eclipse.jface.viewers.TableViewerColumn; 79 import org.eclipse.jface.viewers.Viewer; 80 import org.eclipse.jface.viewers.ViewerFilter; 81 import org.eclipse.jface.window.Window; 82 import org.eclipse.swt.SWT; 83 import org.eclipse.swt.custom.CTabFolder; 84 import org.eclipse.swt.custom.CTabItem; 85 import org.eclipse.swt.events.MouseAdapter; 86 import org.eclipse.swt.events.MouseEvent; 87 import org.eclipse.swt.events.SelectionAdapter; 88 import org.eclipse.swt.events.SelectionEvent; 89 import org.eclipse.swt.graphics.Color; 90 import org.eclipse.swt.graphics.GC; 91 import org.eclipse.swt.graphics.Image; 92 import org.eclipse.swt.layout.GridData; 93 import org.eclipse.swt.layout.GridLayout; 94 import org.eclipse.swt.widgets.Composite; 95 import org.eclipse.swt.widgets.Control; 96 import org.eclipse.swt.widgets.Display; 97 import org.eclipse.swt.widgets.Shell; 98 import org.eclipse.swt.widgets.Table; 99 import org.eclipse.swt.widgets.TableColumn; 100 import org.eclipse.swt.widgets.TableItem; 101 import org.eclipse.swt.widgets.ToolBar; 102 import org.eclipse.swt.widgets.ToolItem; 103 import org.osgi.service.prefs.BackingStoreException; 104 import org.w3c.dom.Document; 105 import org.w3c.dom.Element; 106 import org.w3c.dom.NodeList; 107 import org.xml.sax.InputSource; 108 109 /** 110 * A tab that contains a list EObjects, and provides editable columns for 111 * EObject features. 112 * 113 * @author Steven Spungin 114 * 115 */ 116 public class ListTab implements IViewEObjects { 117 118 static final String ELIPSIS = "..."; //$NON-NLS-1$ 119 120 ConcurrentHashMap<String, List<EObject>> mapId_Object = new ConcurrentHashMap<>(); 121 122 @Inject 123 private IEclipseContext context; 124 125 @Inject 126 private IModelResource modelResource; 127 128 private TableViewer tvResults; 129 130 @Inject 131 private IGotoObject gotoObjectHandler; 132 133 @Inject 134 private IResourcePool resourcePool; 135 136 @Inject 137 @Translation 138 protected Messages Messages; 139 140 @Inject 141 MApplication app; 142 143 BundleImageCache imageCache; 144 145 private CTabItem tabItem; 146 147 private ModelResourceContentProvider provider; 148 149 private IDocumentListener documentListener; 150 151 private Collection<?> highlightedItems; 152 153 protected Image imgMarkedItem; 154 155 LinkedHashMap<String, EAttributeTableViewerColumn> defaultColumns = new LinkedHashMap<>(); 156 LinkedHashMap<String, EAttributeTableViewerColumn> optionalColumns = new LinkedHashMap<>(); 157 LinkedHashMap<String, TableColumn> requiredColumns = new LinkedHashMap<>(); 158 private TableViewerColumn colItem; 159 private TableViewerColumn colGo; 160 private TableViewerColumn colGoXmi; 161 private TableViewerColumn colMarked; 162 163 private ToolItem filterByItem; 164 private ToolItem filterByAttribute; 165 private String filterByAttrName; 166 private String filterByItemName; 167 private EmptyFilterOption filterByAttrEmptyOption; 168 169 @PreDestroy preDestroy()170 public void preDestroy() { 171 // race condition issue with observables (exception is not thrown when 172 // break points are set) 173 tvResults.setContentProvider(ArrayContentProvider.getInstance()); 174 context.get(EMFDocumentResourceMediator.class).getDocument().removeDocumentListener(documentListener); 175 } 176 177 // save custom column and filter settings saveSettings()178 public void saveSettings() { 179 final IEclipsePreferences pref = InstanceScope.INSTANCE.getNode(Plugin.ID); 180 try { 181 final Document doc = DocUtil.createDocument("list-tab"); //$NON-NLS-1$ 182 final Element cols = DocUtil.createChild(doc.getDocumentElement(), "columns"); //$NON-NLS-1$ 183 184 final ArrayList<TableColumn> allCols = TableViewerUtil.getColumnsInDisplayOrder(tvResults); 185 for (final TableColumn col : allCols) { 186 String id; 187 if (requiredColumns.containsValue(col)) { 188 id = getKey(requiredColumns, col); 189 } else { 190 id = col.getText(); 191 } 192 saveColumn(cols, id, col); 193 } 194 195 final Element filters = DocUtil.createChild(doc.getDocumentElement(), "filters"); //$NON-NLS-1$ 196 if (E.notEmpty(filterByAttrName)) { 197 final Element filter = DocUtil.createChild(filters, "filter"); //$NON-NLS-1$ 198 DocUtil.createChild(filter, "type").setTextContent("attribute"); //$NON-NLS-1$//$NON-NLS-2$ 199 DocUtil.createChild(filter, "condition").setTextContent(filterByAttrName); //$NON-NLS-1$ 200 DocUtil.createChild(filter, "emptyOption").setTextContent(filterByAttrEmptyOption.name()); //$NON-NLS-1$ 201 } 202 if (E.notEmpty(filterByItemName)) { 203 final Element filter = DocUtil.createChild(filters, "filter"); //$NON-NLS-1$ 204 DocUtil.createChild(filter, "type").setTextContent("item"); //$NON-NLS-1$ //$NON-NLS-2$ 205 DocUtil.createChild(filter, "condition").setTextContent(filterByItemName); //$NON-NLS-1$ 206 } 207 208 pref.put("list-tab-xml", docToString(doc)); //$NON-NLS-1$ 209 } catch (final ParserConfigurationException e1) { 210 e1.printStackTrace(); 211 } catch (final TransformerException e) { 212 e.printStackTrace(); 213 } 214 215 try { 216 pref.flush(); 217 } catch (final BackingStoreException e) { 218 e.printStackTrace(); 219 } 220 } 221 getKey(Map<String, ?> map, Object value)222 private String getKey(Map<String, ?> map, Object value) { 223 for (final Entry<String, ?> entry : map.entrySet()) { 224 if (entry.getValue().equals(value)) { 225 return entry.getKey(); 226 } 227 } 228 return null; 229 } 230 saveColumn(Element eleCols, String columnName, TableColumn objCol)231 private void saveColumn(Element eleCols, String columnName, TableColumn objCol) { 232 final Element col = DocUtil.createChild(eleCols, "column"); //$NON-NLS-1$ 233 234 DocUtil.createChild(col, "attribute").setTextContent(columnName); //$NON-NLS-1$ 235 236 final Integer width = objCol.getWidth(); 237 DocUtil.createChild(col, "width").setTextContent(width.toString()); //$NON-NLS-1$ 238 } 239 240 // load custom column and filter settings loadSettings()241 private void loadSettings() { 242 final IEclipsePreferences pref = InstanceScope.INSTANCE.getNode(Plugin.ID); 243 244 final boolean restoreColumns = pref.getBoolean(ModelEditorPreferences.LIST_TAB_REMEMBER_COLUMNS, false); 245 final boolean restoreFilters = pref.getBoolean(ModelEditorPreferences.LIST_TAB_REMEMBER_FILTERS, false); 246 if (!restoreColumns && !restoreFilters) { 247 return; 248 } 249 250 final String xml = pref.get("list-tab-xml", ""); //$NON-NLS-1$ //$NON-NLS-2$ 251 if (E.notEmpty(xml)) { 252 try { 253 final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder() 254 .parse(new InputSource(new StringReader(xml))); 255 final XPath xpath = XPathFactory.newInstance().newXPath(); 256 NodeList list; 257 if (restoreColumns) { 258 // restore columns and column widths 259 list = (NodeList) xpath.evaluate("//columns/column", doc, XPathConstants.NODESET); //$NON-NLS-1$ 260 for (int i = 0; i < list.getLength(); i++) { 261 final Element ele = (Element) list.item(i); 262 TableColumn col; 263 final String colName = xpath.evaluate("attribute/text()", ele); //$NON-NLS-1$ 264 if (colName.isEmpty()) { 265 continue; 266 } 267 col = requiredColumns.get(colName); 268 if (col == null) { 269 col = addColumn(colName).getTableViewerColumn().getColumn(); 270 } 271 272 // move it to the end of the list. 273 final int currentIndex = TableViewerUtil.getVisibleColumnIndex(tvResults, col); 274 final int[] order = tvResults.getTable().getColumnOrder(); 275 for (int idx = 0; idx < order.length; idx++) { 276 if (order[idx] > currentIndex) { 277 order[idx]--; 278 } else if (order[idx] == currentIndex) { 279 order[idx] = order.length - 1; 280 } 281 } 282 tvResults.getTable().setColumnOrder(order); 283 284 // if ("Item".equals(colName)) { //$NON-NLS-1$ 285 // col = colItem; 286 // } else if ("Item".equals(colName)) { //$NON-NLS-1$ 287 // col = colItem; 288 // } 289 290 final String sWidth = xpath.evaluate("width/text()", ele); //$NON-NLS-1$ 291 try { 292 col.setWidth(Integer.parseInt(sWidth)); 293 } catch (final Exception e) { 294 } 295 } 296 } 297 298 if (restoreFilters) { 299 // restore filters 300 list = (NodeList) xpath.evaluate("//filters/filter", doc, XPathConstants.NODESET); //$NON-NLS-1$ 301 for (int i = 0; i < list.getLength(); i++) { 302 final Element ele = (Element) list.item(i); 303 final String type = xpath.evaluate("type/text()", ele); //$NON-NLS-1$ 304 final String condition = xpath.evaluate("condition/text()", ele); //$NON-NLS-1$ 305 final String emptyOption = xpath.evaluate("emptyOption/text()", ele); //$NON-NLS-1$ 306 if ("item".equals(type)) { //$NON-NLS-1$ 307 filterByItem(condition); 308 } else if ("attribute".equals(type)) { //$NON-NLS-1$ 309 EmptyFilterOption emptyFilterOption; 310 try { 311 emptyFilterOption = EmptyFilterOption.valueOf(emptyOption); 312 } catch (final Exception e) { 313 emptyFilterOption = EmptyFilterOption.INCLUDE; 314 } 315 filterByAttribute(condition, emptyFilterOption); 316 } 317 } 318 } 319 } catch (final Exception e) { 320 } 321 } 322 } 323 324 // @Refactor docToString(Document doc)325 static private String docToString(Document doc) throws TransformerException { 326 final TransformerFactory tf = TransformerFactory.newInstance(); 327 final Transformer transformer = tf.newTransformer(); 328 transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); //$NON-NLS-1$ 329 final StringWriter writer = new StringWriter(); 330 transformer.transform(new DOMSource(doc), new StreamResult(writer)); 331 final String output = writer.getBuffer().toString().replaceAll("\n|\r", ""); //$NON-NLS-1$ //$NON-NLS-2$ 332 return output; 333 } 334 335 // @Refactor join(Collection<String> items, String separator)336 static String join(Collection<String> items, String separator) { 337 final StringBuilder sb = new StringBuilder(); 338 for (final String item : items) { 339 sb.append(item); 340 sb.append(separator); 341 } 342 if (sb.length() > 0) { 343 sb.setLength(sb.length() - separator.length()); 344 } 345 return sb.toString(); 346 } 347 348 @PostConstruct postConstruct(final CTabFolder tabFolder)349 public void postConstruct(final CTabFolder tabFolder) { 350 imageCache = new BundleImageCache(context.get(Display.class), getClass().getClassLoader()); 351 tabFolder.addDisposeListener(e -> imageCache.dispose()); 352 try { 353 imgMarkedItem = imageCache.create(Plugin.ID, "/icons/full/obj16/mark_occurrences.png"); //$NON-NLS-1$ 354 } catch (final Exception e2) { 355 e2.printStackTrace(); 356 } 357 358 documentListener = new IDocumentListener() { 359 360 @Override 361 public void documentChanged(DocumentEvent event) { 362 reload(); 363 } 364 365 @Override 366 public void documentAboutToBeChanged(DocumentEvent event) { 367 } 368 }; 369 context.get(EMFDocumentResourceMediator.class).getDocument().addDocumentListener(documentListener); 370 371 tabItem = new CTabItem(tabFolder, SWT.NONE, 1); 372 373 final Composite composite = new Composite(tabFolder, SWT.NONE); 374 composite.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 375 composite.setLayout(new GridLayout(2, false)); 376 tabItem.setControl(composite); 377 tabItem.setText(Messages.ListTab_0); 378 379 tabItem.setImage(resourcePool.getImageUnchecked(ResourceProvider.IMG_Widgets_table_obj)); 380 381 final ToolBar toolBar = new ToolBar(composite, SWT.FLAT | SWT.NO_FOCUS); 382 toolBar.setLayoutData(new GridData(SWT.FILL, SWT.TOP, true, false, 2, 1)); 383 384 { 385 final ToolItem button = new ToolItem(toolBar, SWT.PUSH); 386 button.setText(Messages.ListTab_addColumn + ELIPSIS); 387 button.setImage(imageCache.create("/icons/full/obj16/add_column.gif")); //$NON-NLS-1$ 388 389 button.addSelectionListener(new SelectionAdapter() { 390 @Override 391 public void widgetSelected(SelectionEvent e) { 392 final TitleAreaFilterDialogWithEmptyOptions dlg = createEObjectAttributePicker(Messages.ListTab_addColumn); 393 dlg.setShowEmptyOptions(false); 394 if (dlg.open() == Window.OK) { 395 // Add Column 396 final String attName = dlg.getFirstElement().toString(); 397 final EAttributeTableViewerColumn col = addColumn(attName); 398 col.getTableViewerColumn().getColumn().pack(); 399 tvResults.refresh(); 400 } 401 } 402 }); 403 } 404 405 { 406 final ToolItem button = new ToolItem(toolBar, SWT.PUSH); 407 button.setText(Messages.ListTab_resetColumns); 408 button.setImage(imageCache.create("/icons/full/obj16/reset_columns.gif")); //$NON-NLS-1$ 409 410 button.addSelectionListener(new SelectionAdapter() { 411 @Override 412 public void widgetSelected(SelectionEvent e) { 413 for (final EAttributeTableViewerColumn col : optionalColumns.values()) { 414 col.dispose(); 415 } 416 optionalColumns.clear(); 417 } 418 }); 419 } 420 421 new ToolItem(toolBar, SWT.SEPARATOR); 422 423 filterByItem = new ToolItem(toolBar, SWT.NONE); 424 { 425 426 filterByItem.setText(Messages.ListTab_filterByItem + ELIPSIS); 427 filterByItem.setImage(imageCache.create("/icons/full/obj16/filter_by_item.gif")); //$NON-NLS-1$ 428 429 filterByItem.addSelectionListener(new SelectionAdapter() { 430 431 @Override 432 public void widgetSelected(SelectionEvent e) { 433 final TitleAreaFilterDialog dlg = createElementTypePicker(Messages.ListTab_filterByItem); 434 if (dlg.open() == Window.OK) { 435 filterByItem(dlg.getFirstElement().toString()); 436 } 437 } 438 }); 439 } 440 441 filterByAttribute = new ToolItem(toolBar, SWT.NONE); 442 { 443 444 filterByAttribute.setText(Messages.ListTab_filterByAttribute + ELIPSIS); 445 filterByAttribute.setImage(imageCache.create("/icons/full/obj16/filter_by_attribute.gif")); //$NON-NLS-1$ 446 447 filterByAttribute.addSelectionListener(new SelectionAdapter() { 448 @Override 449 public void widgetSelected(SelectionEvent e) { 450 final TitleAreaFilterDialogWithEmptyOptions dlg = createEObjectAttributePicker(Messages.ListTab_filterByAttribute); 451 if (dlg.open() == Window.OK) { 452 filterByAttribute(dlg.getFirstElement().toString(), dlg.getEmptyFilterOption()); 453 } 454 } 455 }); 456 } 457 458 { 459 final ToolItem filterRemove = new ToolItem(toolBar, SWT.NONE); 460 filterRemove.setText(Messages.ListTab_removeFilter); 461 filterRemove.setImage(imageCache.create("/icons/full/obj16/remove_filter.png")); //$NON-NLS-1$ 462 463 filterRemove.addSelectionListener(new SelectionAdapter() { 464 @Override 465 public void widgetSelected(SelectionEvent e) { 466 filterByItemName = null; 467 filterByAttrName = null; 468 tvResults.setFilters(); 469 filterByItem.setText(Messages.ListTab_filterByItem + ELIPSIS); 470 filterByAttribute.setText(Messages.ListTab_markAttribute + ELIPSIS); 471 } 472 }); 473 } 474 475 new ToolItem(toolBar, SWT.SEPARATOR); 476 477 { 478 final E4ToolItemMenu tiCommands = new E4ToolItemMenu(toolBar, context); 479 tiCommands.getToolItem().setImage(imageCache.create("/icons/full/obj16/command.gif")); //$NON-NLS-1$ 480 481 final ArrayList<String> commandIds = new ArrayList<>(); 482 commandIds.add("org.eclipse.e4.tools.emf.ui.command.mark_duplicate_attributes"); //$NON-NLS-1$ 483 commandIds.add("org.eclipse.e4.tools.emf.ui.command.mark_duplicate_ids"); //$NON-NLS-1$ 484 commandIds.add("org.eclipse.e4.tools.emf.ui.command.mark_duplicate_labels"); //$NON-NLS-1$ 485 commandIds.add("org.eclipse.e4.tools.emf.ui.command.repair_duplicate_ids"); //$NON-NLS-1$ 486 commandIds.add(E4ToolItemMenu.SEPARATOR); 487 commandIds.add("org.eclipse.e4.tools.emf.ui.command.unmark"); //$NON-NLS-1$ 488 commandIds.add(E4ToolItemMenu.SEPARATOR); 489 commandIds.add("org.eclipse.e4.tools.emf.ui.command.autosizeColumns"); //$NON-NLS-1$ 490 commandIds.add("org.eclipse.e4.tools.emf.ui.command.resetToDefault"); //$NON-NLS-1$ 491 tiCommands.addCommands(commandIds); 492 } 493 494 tvResults = new TableViewer(composite, SWT.FULL_SELECTION); 495 tvResults.getTable().setHeaderVisible(true); 496 tvResults.getTable().setLinesVisible(true); 497 498 provider = new ModelResourceContentProvider(); 499 tvResults.setContentProvider(provider); 500 501 tvResults.getTable().setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); 502 ((GridData) tvResults.getTable().getLayoutData()).horizontalSpan = 2; 503 504 final Image imgForm = resourcePool.getImageUnchecked(ResourceProvider.IMG_Obj16_application_form); 505 final Image imgXmi = resourcePool.getImageUnchecked(ResourceProvider.IMG_Obj16_chart_organisation); 506 507 colGo = new TableViewerColumn(tvResults, SWT.NONE); 508 colGo.getColumn().setText(Messages.ListTab_col_go); 509 requiredColumns.put("GoTree", colGo.getColumn()); //$NON-NLS-1$ 510 colGo.setLabelProvider(new ColumnLabelProvider() { 511 @Override 512 public Image getImage(Object element) { 513 return imgForm; 514 } 515 516 @Override 517 public String getText(Object element) { 518 return ""; //$NON-NLS-1$ 519 } 520 }); 521 522 colGoXmi = new TableViewerColumn(tvResults, SWT.NONE); 523 colGoXmi.getColumn().setText(Messages.ListTab_col_go); 524 requiredColumns.put("GoXmi", colGoXmi.getColumn()); //$NON-NLS-1$ 525 colGoXmi.setLabelProvider(new ColumnLabelProvider() { 526 @Override 527 public String getText(Object element) { 528 return ""; //$NON-NLS-1$ 529 } 530 531 @Override 532 public Image getImage(Object element) { 533 return imgXmi; 534 } 535 }); 536 537 tvResults.getTable().addMouseListener(new MouseAdapter() { 538 @Override 539 public void mouseDown(MouseEvent e) { 540 if (TableViewerUtil.isColumnClicked(tvResults, e, colGo)) { 541 gotoObjectHandler.gotoEObject(ModelEditor.TAB_FORM, (EObject) TableViewerUtil.getData(tvResults, e)); 542 } else if (TableViewerUtil.isColumnClicked(tvResults, e, colGoXmi)) { 543 gotoObjectHandler.gotoEObject(ModelEditor.TAB_XMI, (EObject) TableViewerUtil.getData(tvResults, e)); 544 } 545 } 546 }); 547 548 colMarked = new TableViewerColumn(tvResults, SWT.NONE); 549 colMarked.getColumn().setWidth(16); 550 colMarked.getColumn().setText(Messages.ListTab_mark); 551 requiredColumns.put("Marked", colMarked.getColumn()); //$NON-NLS-1$ 552 colMarked.setLabelProvider(new ColumnLabelProvider() { 553 @Override 554 public Image getImage(Object element) { 555 Image ret = null; 556 if (isHighlighted(element)) { 557 try { 558 ret = imgMarkedItem; 559 } catch (final Exception e) { 560 } 561 } 562 return ret; 563 } 564 565 @Override 566 public String getText(Object element) { 567 return ""; //$NON-NLS-1$ 568 } 569 }); 570 571 colItem = new TableViewerColumn(tvResults, SWT.NONE); 572 colItem.getColumn().setText(Messages.ListTab_col_item); 573 requiredColumns.put("Item", colItem.getColumn()); //$NON-NLS-1$ 574 colItem.setLabelProvider(new ColumnLabelProvider_Markable() { 575 @Override 576 public String getText(Object element) { 577 final EObject eObject = (EObject) element; 578 return super.getText(eObject.eClass().getName()); 579 } 580 }); 581 582 app.getContext().set("org.eclipse.e4.tools.active-object-viewer", this); //$NON-NLS-1$ 583 584 final EAttributeTableViewerColumn colId = new EAttributeTableViewerColumn(tvResults, 585 "elementId", "elementId", context); //$NON-NLS-1$//$NON-NLS-2$ 586 defaultColumns.put("elementId", colId); //$NON-NLS-1$ 587 588 final EAttributeTableViewerColumn colLabel = new EAttributeTableViewerColumn_Markable(tvResults, 589 "label", "label", context); //$NON-NLS-1$//$NON-NLS-2$ 590 defaultColumns.put("label", colLabel); //$NON-NLS-1$ 591 592 // Custom selection for marked items 593 tvResults.getTable().addListener(SWT.EraseItem, event -> { 594 event.detail &= ~SWT.HOT; 595 if ((event.detail & SWT.SELECTED) == 0) { 596 return; // / item not selected 597 } 598 599 final TableItem item = (TableItem) event.item; 600 if (isHighlighted(item.getData())) { 601 602 final Table table = (Table) event.widget; 603 final int clientWidth = table.getClientArea().width; 604 final GC gc = event.gc; 605 // Color oldForeground = gc.getForeground(); 606 // Color oldBackground = gc.getBackground(); 607 608 // gc.setBackground(item.getDisplay().getSystemColor(SWT.COLOR_YELLOW)); 609 gc.setForeground(item.getDisplay().getSystemColor(SWT.COLOR_RED)); 610 gc.fillRectangle(0, event.y, clientWidth, event.height); 611 612 // gc.setForeground(oldForeground); 613 // gc.setBackground(oldBackground); 614 event.detail &= ~SWT.SELECTED; 615 } 616 }); 617 618 tvResults.getTable().setFocus(); 619 620 for (final EAttributeTableViewerColumn col : defaultColumns.values()) { 621 col.getTableViewerColumn().getColumn().setMoveable(true); 622 } 623 for (final TableColumn col : requiredColumns.values()) { 624 col.setMoveable(true); 625 } 626 627 makeSortable(colId.getTableViewerColumn().getColumn(), new AttributeColumnLabelSorter(colId 628 .getTableViewerColumn().getColumn(), "elementId")); //$NON-NLS-1$ 629 makeSortable(colLabel.getTableViewerColumn().getColumn(), new AttributeColumnLabelSorter(colLabel 630 .getTableViewerColumn().getColumn(), "label")); //$NON-NLS-1$ 631 makeSortable(colItem.getColumn(), new TableViewerUtil.ColumnLabelSorter(colItem.getColumn())); 632 makeSortable(colMarked.getColumn(), new TableViewerUtil.AbstractInvertableTableSorter() { 633 634 @Override 635 public int compare(Viewer viewer, Object e1, Object e2) { 636 final boolean mark1 = isHighlighted(e1); 637 final boolean mark2 = isHighlighted(e2); 638 if (mark1 && !mark2) { 639 return -1; 640 } else if (mark2 && !mark1) { 641 return 1; 642 } else { 643 return 0; 644 } 645 } 646 }); 647 648 reload(); 649 TableViewerUtil.refreshAndPack(tvResults); 650 loadSettings(); 651 } 652 makeSortable(TableColumn column, TableViewerUtil.AbstractInvertableTableSorter sorter)653 private void makeSortable(TableColumn column, TableViewerUtil.AbstractInvertableTableSorter sorter) { 654 new TableViewerUtil.TableSortSelectionListener(tvResults, column, sorter, SWT.UP, false); 655 } 656 reload()657 public void reload() { 658 tvResults.setInput(modelResource); 659 } 660 getViewer()661 public TableViewer getViewer() { 662 return tvResults; 663 } 664 getTabItem()665 public CTabItem getTabItem() { 666 return tabItem; 667 } 668 getContext()669 public IEclipseContext getContext() { 670 return context; 671 } 672 673 @Override highlightEObjects(Collection<EObject> items)674 public void highlightEObjects(Collection<EObject> items) { 675 highlightedItems = items; 676 tvResults.refresh(); 677 } 678 679 @Override getAllEObjects()680 public List<EObject> getAllEObjects() { 681 final ArrayList<EObject> list = new ArrayList<>(); 682 final TreeIterator<Object> itTree = EcoreUtil.getAllContents(modelResource.getRoot()); 683 while (itTree.hasNext()) { 684 final Object object = itTree.next(); 685 final EObject eObject = (EObject) object; 686 final EAttribute att = EmfUtil.getAttribute(eObject, "elementId"); //$NON-NLS-1$ 687 if (att != null) { 688 list.add(eObject); 689 } 690 } 691 return list; 692 } 693 694 @Override getSelectedEObjects()695 public Collection<EObject> getSelectedEObjects() { 696 final ArrayList<EObject> selected = new ArrayList<>(); 697 for (final Object item : ((IStructuredSelection) tvResults.getSelection()).toList()) { 698 if (item instanceof EObject) { 699 selected.add((EObject) item); 700 701 } 702 } 703 return selected; 704 } 705 706 @Override deleteEObjects(Collection<EObject> list)707 public void deleteEObjects(Collection<EObject> list) { 708 if (list.isEmpty() == false) { 709 final Command cmd = DeleteCommand.create(modelResource.getEditingDomain(), list); 710 if (cmd.canExecute()) { 711 modelResource.getEditingDomain().getCommandStack().execute(cmd); 712 } 713 reload(); 714 } 715 } 716 createEObjectAttributePicker(final String title)717 private TitleAreaFilterDialogWithEmptyOptions createEObjectAttributePicker(final String title) { 718 // Get Attribute Names 719 final HashSet<String> set = new HashSet<>(); 720 final Collection<EObject> allEObjects = getAllEObjects(); 721 for (final EObject obj : allEObjects) { 722 for (final EAttribute attribute : obj.eClass().getEAllAttributes()) { 723 set.add(attribute.getName()); 724 } 725 } 726 final ArrayList<String> sorted = new ArrayList<>(set); 727 sorted.sort(null); 728 729 // Select Attribute 730 final ILabelProvider renderer = new LabelProvider() { 731 @Override 732 public String getText(Object element) { 733 return String.valueOf(element); 734 } 735 }; 736 final TitleAreaFilterDialogWithEmptyOptions dlg = new TitleAreaFilterDialogWithEmptyOptions( 737 context.get(Shell.class), renderer) { 738 @Override 739 protected Control createContents(Composite parent) { 740 final Control ret = super.createContents(parent); 741 setMessage(Messages.ListTab_selectAnAttribute); 742 try { 743 setTitleImage(imageCache.create(Plugin.ID, "/icons/full/wizban/attribute_wiz.gif")); //$NON-NLS-1$ 744 } catch (final Exception e) { 745 e.printStackTrace(); 746 } 747 setTitle(title); 748 setElements(sorted.toArray(new String[0])); 749 return ret; 750 } 751 }; 752 return dlg; 753 } 754 createElementTypePicker(final String title)755 private TitleAreaFilterDialog createElementTypePicker(final String title) { 756 // Get Attribute Names 757 final HashSet<String> set = new HashSet<>(); 758 final Collection<EObject> allEObjects = getAllEObjects(); 759 for (final EObject obj : allEObjects) { 760 set.add(obj.eClass().getName()); 761 } 762 763 final ArrayList<String> sorted = new ArrayList<>(set); 764 sorted.sort(null); 765 766 final ILabelProvider renderer = new LabelProvider() { 767 @Override 768 public String getText(Object element) { 769 return String.valueOf(element); 770 } 771 }; 772 final TitleAreaFilterDialog dlg = new TitleAreaFilterDialog(context.get(Shell.class), renderer) { 773 774 @Override 775 protected Control createContents(Composite parent) { 776 final Control ret = super.createContents(parent); 777 setMessage(Messages.ListTab_selectAType); 778 setTitle(title); 779 setElements(sorted.toArray(new String[0])); 780 return ret; 781 } 782 }; 783 return dlg; 784 } 785 786 /** 787 * Adds a column if it does not already exist 788 * 789 * @param attName 790 * @return The existing or newly created column 791 */ addColumn(String attName)792 private EAttributeTableViewerColumn addColumn(String attName) { 793 EAttributeTableViewerColumn colName = defaultColumns.get(attName); 794 if (colName == null) { 795 colName = optionalColumns.get(attName); 796 if (colName == null) { 797 colName = new EAttributeTableViewerColumn_Markable(tvResults, attName, attName, context); 798 optionalColumns.put(attName, colName); 799 colName.getTableViewerColumn().getColumn().setMoveable(true); 800 makeSortable(colName.getTableViewerColumn().getColumn(), new AttributeColumnLabelSorter(colName 801 .getTableViewerColumn().getColumn(), attName)); 802 tvResults.refresh(); 803 } 804 } 805 return colName; 806 } 807 808 static private class AttributeColumnLabelSorter extends TableViewerUtil.ColumnLabelSorter { 809 810 private final String attName; 811 AttributeColumnLabelSorter(TableColumn col, String attName)812 AttributeColumnLabelSorter(TableColumn col, String attName) { 813 super(col); 814 this.attName = attName; 815 } 816 817 @Override compare(Viewer viewer, Object e1, Object e2)818 public int compare(Viewer viewer, Object e1, Object e2) { 819 // if either is boolean, use boolean value, otherwise use text value 820 final ATT_TYPE e1Type = EAttributeEditingSupport.getAttributeType(e1, attName); 821 final ATT_TYPE e2Type = EAttributeEditingSupport.getAttributeType(e2, attName); 822 if (e1Type == ATT_TYPE.BOOLEAN || e2Type == ATT_TYPE.BOOLEAN) { 823 final Boolean b1 = (Boolean) EmfUtil.getAttributeValue((EObject) e1, attName); 824 final Boolean b2 = (Boolean) EmfUtil.getAttributeValue((EObject) e2, attName); 825 if (b1 == null && b2 != null) { 826 return -2; 827 } else if (b2 == null && b1 != null) { 828 return 2; 829 } else { 830 return b1.compareTo(b2); 831 } 832 } 833 return super.compare(viewer, e1, e2); 834 } 835 } 836 837 private class EAttributeTableViewerColumn_Markable extends EAttributeTableViewerColumn { EAttributeTableViewerColumn_Markable(TableViewer tvResults, String label, String attName, IEclipseContext context)838 public EAttributeTableViewerColumn_Markable(TableViewer tvResults, String label, String attName, 839 IEclipseContext context) { 840 super(tvResults, label, attName, context); 841 } 842 843 @Override getBackground(Object element)844 public Color getBackground(Object element) { 845 Color ret; 846 if (isHighlighted(element)) { 847 return ret = tvResults.getTable().getDisplay().getSystemColor(SWT.COLOR_YELLOW); 848 } 849 ret = super.getBackground(element); 850 return ret; 851 } 852 } 853 854 private class ColumnLabelProvider_Markable extends ColumnLabelProvider { 855 @Override getBackground(Object element)856 public Color getBackground(Object element) { 857 Color ret; 858 if (isHighlighted(element)) { 859 ret = tvResults.getTable().getDisplay().getSystemColor(SWT.COLOR_YELLOW); 860 } else { 861 ret = super.getBackground(element); 862 } 863 return ret; 864 } 865 } 866 867 @Override getEditingDomain()868 public EditingDomain getEditingDomain() { 869 return modelResource.getEditingDomain(); 870 } 871 isHighlighted(Object element)872 public boolean isHighlighted(Object element) { 873 return highlightedItems != null && highlightedItems.contains(element); 874 } 875 filterByItem(String name)876 private void filterByItem(String name) { 877 filterByItemName = name; 878 filterByAttrName = null; 879 filterByAttrEmptyOption = null; 880 mapId_Object.clear(); 881 final ArrayList<EObject> filtered = new ArrayList<>(); 882 for (final EObject object : getAllEObjects()) { 883 if (object.eClass().getName().equals(filterByItemName)) { 884 filtered.add(object); 885 // filter.setText(Messages.ListTab_7 + 886 // attFilter); 887 888 } 889 890 final ViewerFilter viewerFilter = new ViewerFilter() { 891 892 @Override 893 public boolean select(Viewer viewer, Object parentElement, Object element) { 894 return filtered.contains(element); 895 } 896 897 }; 898 tvResults.setFilters(viewerFilter); 899 filterByItem.setText(Messages.ListTab_filterByItem + ELIPSIS + "(" + filterByItemName + ")"); //$NON-NLS-1$//$NON-NLS-2$ 900 filterByAttribute.setText(Messages.ListTab_filterByAttribute + ELIPSIS); 901 } 902 } 903 filterByAttribute(String name, final EmptyFilterOption emptyOption)904 private void filterByAttribute(String name, final EmptyFilterOption emptyOption) { 905 filterByAttrName = name; 906 filterByAttrEmptyOption = emptyOption; 907 filterByItemName = null; 908 mapId_Object.clear(); 909 final ArrayList<EObject> filtered = new ArrayList<>(); 910 for (final EObject object : getAllEObjects()) { 911 if (EmfUtil.getAttribute(object, filterByAttrName) != null) { 912 filtered.add(object); 913 final ViewerFilter viewerFilter = new ViewerFilter() { 914 915 @Override 916 public boolean select(Viewer viewer, Object parentElement, Object element) { 917 // if filtering on attribute, always 918 // reject if not defined for model 919 // element 920 if (EmfUtil.getAttribute((EObject) element, filterByAttrName) == null) { 921 return false; 922 } 923 switch (emptyOption) { 924 case EXCLUDE: 925 if (E.isEmpty(EmfUtil.getAttributeValue((EObject) element, filterByAttrName))) { 926 return false; 927 } 928 return filtered.contains(element); 929 case ONLY: 930 if (E.notEmpty(EmfUtil.getAttributeValue((EObject) element, filterByAttrName))) { 931 return false; 932 } 933 return true; 934 default: 935 case INCLUDE: 936 if (E.isEmpty(EmfUtil.getAttributeValue((EObject) element, filterByAttrName))) { 937 return true; 938 } 939 return filtered.contains(element); 940 } 941 } 942 }; 943 tvResults.setFilters(viewerFilter); 944 filterByAttribute.setText(Messages.ListTab_filterByAttribute + ELIPSIS + "(" + filterByAttrName + ")"); //$NON-NLS-1$//$NON-NLS-2$ 945 filterByItem.setText(Messages.ListTab_filterByItem + ELIPSIS); 946 947 } 948 } 949 final TableViewerColumn viewerColumn = addColumn(filterByAttrName).getTableViewerColumn(); 950 viewerColumn.getColumn().pack(); 951 } 952 953 @Override autosizeContent()954 public void autosizeContent() { 955 for (final TableColumn col : tvResults.getTable().getColumns()) { 956 col.pack(); 957 if (col.getWidth() < 10) { 958 col.setWidth(10); 959 } 960 } 961 } 962 963 @Override resetToDefault()964 public void resetToDefault() { 965 for (final EAttributeTableViewerColumn col : optionalColumns.values()) { 966 col.dispose(); 967 } 968 optionalColumns.clear(); 969 970 TableViewerUtil.resetColumnOrder(tvResults); 971 TableViewerUtil.packAllColumns(tvResults); 972 } 973 974 } 975