diff --git a/com.archimatetool.editor/src/com/archimatetool/editor/propertysections/UserPropertiesManagerDialog.java b/com.archimatetool.editor/src/com/archimatetool/editor/propertysections/UserPropertiesManagerDialog.java index 09cdfaecd..db4625b9f 100644 --- a/com.archimatetool.editor/src/com/archimatetool/editor/propertysections/UserPropertiesManagerDialog.java +++ b/com.archimatetool.editor/src/com/archimatetool/editor/propertysections/UserPropertiesManagerDialog.java @@ -5,9 +5,12 @@ */ package com.archimatetool.editor.propertysections; -import java.text.Collator; -import java.util.Hashtable; +import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; import java.util.Map.Entry; import org.eclipse.draw2d.ColorConstants; @@ -31,8 +34,8 @@ import org.eclipse.jface.viewers.ColumnViewerEditorActivationStrategy; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.jface.viewers.IIndexableLazyContentProvider; import org.eclipse.jface.viewers.ISelectionChangedListener; -import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.ITableColorProvider; import org.eclipse.jface.viewers.ITableLabelProvider; @@ -43,7 +46,6 @@ import org.eclipse.jface.viewers.TableViewerEditor; import org.eclipse.jface.viewers.TextCellEditor; import org.eclipse.jface.viewers.Viewer; -import org.eclipse.jface.viewers.ViewerComparator; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.events.SelectionAdapter; @@ -78,7 +80,7 @@ public class UserPropertiesManagerDialog extends ExtendedTitleAreaDialog { private static String HELP_ID = "com.archimatetool.help.userProperties"; //$NON-NLS-1$ - + private static class KeyEntry { String newName; int usedTimes = 1; @@ -92,7 +94,7 @@ private static class KeyEntry { private IArchimateModel fArchimateModel; - private Hashtable fKeysTable = new Hashtable(); + private Map fKeysMap = new LinkedHashMap<>(); private Button fButtonDelete, fButtonRename; private IAction fActionDelete, fActionRename; @@ -205,7 +207,7 @@ private void createTableControl(Composite parent) { tableComp.setLayout(tableLayout); tableComp.setLayoutData(new GridData(GridData.FILL_BOTH)); - fTableViewer = new TableViewer(tableComp, SWT.MULTI | SWT.FULL_SELECTION); + fTableViewer = new TableViewer(tableComp, SWT.MULTI | SWT.FULL_SELECTION | SWT.VIRTUAL); fTableViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH)); // Mac Silicon Item height @@ -228,8 +230,6 @@ protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent even fTableViewer.getTable().setHeaderVisible(true); fTableViewer.getTable().setLinesVisible(true); - fTableViewer.setComparator(new ViewerComparator(Collator.getInstance())); - // Columns TableViewerColumn columnOldKey = new TableViewerColumn(fTableViewer, SWT.NONE, 0); columnOldKey.getColumn().setText(Messages.UserPropertiesManagerDialog_6); @@ -245,9 +245,17 @@ protected boolean isEditorActivationEvent(ColumnViewerEditorActivationEvent even tableLayout.setColumnData(columnUsedNumber.getColumn(), new ColumnWeightData(20, true)); // Content Provider - fTableViewer.setContentProvider(new IStructuredContentProvider() { + // Use an IIndexableLazyContentProvider so we can find an element faster when calling TableViewer.update(key, null) + fTableViewer.setContentProvider(new IIndexableLazyContentProvider() { + List keys; + @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + if(newInput != null) { + keys = new ArrayList<>(fKeysMap.keySet()); + Collections.sort(keys, (s1, s2) -> s1.compareToIgnoreCase(s2)); // Don't use Collator.getInstance() as it's too slow + fTableViewer.setItemCount(keys.size()); + } } @Override @@ -255,8 +263,13 @@ public void dispose() { } @Override - public Object[] getElements(Object inputElement) { - return fKeysTable.entrySet().toArray(); + public void updateElement(int index) { + fTableViewer.replace(keys.get(index), index); + } + + @Override + public int findElement(Object element) { + return keys.indexOf(element); } }); @@ -274,7 +287,7 @@ public void selectionChanged(SelectionChangedEvent event) { } }); - fTableViewer.setInput(""); // anything will do //$NON-NLS-1$ + fTableViewer.setInput(fKeysMap); } private void createButtonPanel(Composite parent) { @@ -315,9 +328,10 @@ public void widgetSelected(SelectionEvent e) { private void deleteSelectedPropertyKeys() { for(Object o : ((IStructuredSelection)fTableViewer.getSelection()).toList()) { - fKeysTable.entrySet().remove(o); + fKeysMap.remove(o); } - fTableViewer.refresh(); + + fTableViewer.setInput(fKeysMap); getButton(IDialogConstants.OK_ID).setEnabled(true); } @@ -331,14 +345,14 @@ private void renameSelectedPropertyKey() { private void getAllUniquePropertyKeysForModel() { for(Iterator iter = fArchimateModel.eAllContents(); iter.hasNext();) { EObject element = iter.next(); - if(element instanceof IProperty) { - String key = ((IProperty)element).getKey(); + if(element instanceof IProperty p) { + String key = p.getKey(); if(key != null) { - if(fKeysTable.containsKey(key)) { - fKeysTable.get(key).usedTimes++; + if(fKeysMap.containsKey(key)) { + fKeysMap.get(key).usedTimes++; } else { - fKeysTable.put(key, new KeyEntry(key)); + fKeysMap.put(key, new KeyEntry(key)); } } } @@ -406,10 +420,9 @@ void doSuperRedo() { private void checkDeletions(CompoundCommand compoundCmd) { for(Iterator iter = fArchimateModel.eAllContents(); iter.hasNext();) { EObject element = iter.next(); - if(element instanceof IProperty) { - IProperty property = (IProperty)element; + if(element instanceof IProperty property) { String key = property.getKey(); - if(key != null && !fKeysTable.containsKey(key)) { + if(key != null && !fKeysMap.containsKey(key)) { Command cmd = new DeletePropertyKeyCommand(((IProperties)property.eContainer()).getProperties(), property); compoundCmd.add(cmd); } @@ -421,7 +434,7 @@ private void checkDeletions(CompoundCommand compoundCmd) { * Check for renames */ private void checkRenames(CompoundCommand compoundCmd) { - for(Entry entry : fKeysTable.entrySet()) { + for(Entry entry : fKeysMap.entrySet()) { String oldName = entry.getKey(); String newName = entry.getValue().newName; if(!oldName.equals(newName)) { @@ -436,10 +449,10 @@ private void checkRenames(CompoundCommand compoundCmd) { private void addKeyNameChangeCommands(CompoundCommand compoundCmd, String oldName, String newName) { for(Iterator iter = fArchimateModel.eAllContents(); iter.hasNext();) { EObject element = iter.next(); - if(element instanceof IProperty) { - String key = ((IProperty)element).getKey(); + if(element instanceof IProperty property) { + String key = property.getKey(); if(key != null && key.equals(oldName)) { - Command cmd = new RenamePropertyKeyCommand((IProperty)element, oldName, newName); + Command cmd = new RenamePropertyKeyCommand(property, oldName, newName); compoundCmd.add(cmd); } } @@ -454,7 +467,7 @@ protected Point getDefaultDialogSize() { /** * Label Provider */ - private static class LabelCellProvider extends LabelProvider implements ITableLabelProvider, ITableColorProvider { + private class LabelCellProvider extends LabelProvider implements ITableLabelProvider, ITableColorProvider { @Override public Image getColumnImage(Object element, int columnIndex) { return null; @@ -462,18 +475,17 @@ public Image getColumnImage(Object element, int columnIndex) { @Override public String getColumnText(Object element, int columnIndex) { - @SuppressWarnings("unchecked") - Entry entry = (Entry)element; + String key = (String)element; switch(columnIndex) { case 0: - return entry.getKey(); + return key; case 1: - return entry.getValue().newName; + return fKeysMap.get(key).newName; case 2: - return "" + entry.getValue().usedTimes; //$NON-NLS-1$ + return "" + fKeysMap.get(key).usedTimes; //$NON-NLS-1$ default: return null; @@ -482,14 +494,14 @@ public String getColumnText(Object element, int columnIndex) { @Override public Color getForeground(Object element, int columnIndex) { - @SuppressWarnings("unchecked") - Entry entry = (Entry)element; - if(columnIndex == 1) { - if(!entry.getKey().equals(entry.getValue().newName)) { + String key = (String)element; + KeyEntry entry = fKeysMap.get(key); + if(!key.equals(entry.newName)) { return ColorConstants.red; } } + return null; } @@ -522,18 +534,19 @@ protected boolean canEdit(Object element) { @Override protected Object getValue(Object element) { - @SuppressWarnings("unchecked") - Entry entry = (Entry)element; - return entry.getValue().newName; + String key = (String)element; + return fKeysMap.get(key).newName; } @Override protected void setValue(Object element, Object value) { - @SuppressWarnings("unchecked") - Entry entry = (Entry)element; - if(!value.equals(entry.getValue().newName)) { - entry.getValue().newName = (String)value; - fTableViewer.update(entry, null); + String key = (String)element; + KeyEntry entry = fKeysMap.get(key); + String newValue = (String)value; + + if(!newValue.equals(entry.newName)) { + entry.newName = newValue; + fTableViewer.update(key, null); getButton(IDialogConstants.OK_ID).setEnabled(true); } } diff --git a/com.archimatetool.editor/src/com/archimatetool/editor/propertysections/UserPropertiesSection.java b/com.archimatetool.editor/src/com/archimatetool/editor/propertysections/UserPropertiesSection.java index 97d7433cf..eabf0d2e7 100644 --- a/com.archimatetool.editor/src/com/archimatetool/editor/propertysections/UserPropertiesSection.java +++ b/com.archimatetool.editor/src/com/archimatetool/editor/propertysections/UserPropertiesSection.java @@ -40,7 +40,6 @@ import org.eclipse.jface.util.LocalSelectionTransfer; import org.eclipse.jface.viewers.CellEditor; import org.eclipse.jface.viewers.CellLabelProvider; -import org.eclipse.jface.viewers.CheckboxTableViewer; import org.eclipse.jface.viewers.ColumnViewer; import org.eclipse.jface.viewers.ColumnViewerEditor; import org.eclipse.jface.viewers.ColumnViewerEditorActivationEvent; @@ -48,10 +47,10 @@ import org.eclipse.jface.viewers.ColumnViewerToolTipSupport; import org.eclipse.jface.viewers.ColumnWeightData; import org.eclipse.jface.viewers.EditingSupport; +import org.eclipse.jface.viewers.ILazyContentProvider; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredContentProvider; import org.eclipse.jface.viewers.IStructuredSelection; -import org.eclipse.jface.viewers.LabelProvider; import org.eclipse.jface.viewers.TableViewer; import org.eclipse.jface.viewers.TableViewerColumn; import org.eclipse.jface.viewers.TableViewerEditor; @@ -67,8 +66,7 @@ import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.events.KeyListener; import org.eclipse.swt.events.MouseListener; -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.Image; import org.eclipse.swt.graphics.Point; @@ -82,7 +80,6 @@ import org.eclipse.swt.widgets.Listener; import org.eclipse.swt.widgets.Menu; import org.eclipse.swt.widgets.Shell; -import org.eclipse.swt.widgets.Table; import org.eclipse.swt.widgets.TableItem; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.ui.IActionBars; @@ -97,6 +94,7 @@ import com.archimatetool.editor.ui.components.ExtendedTitleAreaDialog; import com.archimatetool.editor.ui.components.GlobalActionDisablementHandler; import com.archimatetool.editor.ui.components.StringComboBoxCellEditor; +import com.archimatetool.editor.ui.components.TableCheckListener; import com.archimatetool.editor.utils.HTMLUtils; import com.archimatetool.editor.utils.StringUtils; import com.archimatetool.model.IArchimateFactory; @@ -145,6 +143,12 @@ public Class getAdaptableType() { // Indicates multiple property values (unlikely to be a user-given value) private static final String multipleValuesIndicator = UUID.randomUUID().toString(); + // Maximum amount of items to display when getting all unique keys and values for combo boxes + private static final int MAX_ITEMS_COMBO = 20000; + + // Display all items + private static final int MAX_ITEMS_ALL = -1; + @Override protected void createControls(Composite parent) { createTableControl(parent); @@ -514,38 +518,44 @@ private IArchimateModel getArchimateModel() { /** * @return All unique Property Keys for an entire model (sorted) */ - private String[] getAllUniquePropertyKeysForModel() { + private String[] getAllUniquePropertyKeysForModel(int maxSize) { IArchimateModel model = getArchimateModel(); - Set set = new HashSet(); - + int count = 0; + for(Iterator iter = model.eAllContents(); iter.hasNext();) { EObject element = iter.next(); if(element instanceof IProperty p) { + if(maxSize != MAX_ITEMS_ALL && ++count > maxSize) { // Don't get more than this + break; + } String key = p.getKey(); if(StringUtils.isSetAfterTrim(key)) { set.add(key); } } } - + String[] items = set.toArray(new String[set.size()]); - Arrays.sort(items, (s1, s2) -> s1.compareToIgnoreCase(s2)); - + Arrays.sort(items, (s1, s2) -> s1.compareToIgnoreCase(s2)); // Don't use Collator.getInstance() as it's too slow + return items; } /** * @return All unique Property Values for an entire model (sorted) */ - private String[] getAllUniquePropertyValuesForKeyForModel(String key) { + private String[] getAllUniquePropertyValuesForKeyForModel(String key, int maxSize) { IArchimateModel model = getArchimateModel(); - Set set = new HashSet(); + int count = 0; for(Iterator iter = model.eAllContents(); iter.hasNext();) { EObject element = iter.next(); if(element instanceof IProperty p) { + if(maxSize != MAX_ITEMS_ALL && ++count > maxSize) { // Don't get more than this + break; + } if(p.getKey().equals(key)) { String value = p.getValue(); if(StringUtils.isSetAfterTrim(value)) { @@ -554,9 +564,9 @@ private String[] getAllUniquePropertyValuesForKeyForModel(String key) { } } } - + String[] items = set.toArray(new String[set.size()]); - Arrays.sort(items, (s1, s2) -> s1.compareToIgnoreCase(s2)); + Arrays.sort(items, (s1, s2) -> s1.compareToIgnoreCase(s2)); // Don't use Collator.getInstance() as it's too slow return items; } @@ -660,14 +670,8 @@ public KeyEditingSupport(ColumnViewer viewer) { @Override protected CellEditor getCellEditor(Object element) { - String[] items = new String[0]; - - if(isAlive(getFirstSelectedElement())) { - items = getAllUniquePropertyKeysForModel(); - } - + String[] items = isAlive(getFirstSelectedElement()) ? getAllUniquePropertyKeysForModel(MAX_ITEMS_COMBO) : new String[0]; cellEditor.setItems(items); - return cellEditor; } @@ -736,14 +740,8 @@ public ValueEditingSupport(ColumnViewer viewer) { @Override protected CellEditor getCellEditor(Object element) { - String[] items = new String[0]; - - if(isAlive(getFirstSelectedElement())) { - items = getAllUniquePropertyValuesForKeyForModel(((IProperty)element).getKey()); - } - + String[] items = isAlive(getFirstSelectedElement()) ? getAllUniquePropertyValuesForKeyForModel(((IProperty)element).getKey(), MAX_ITEMS_COMBO) : new String[0]; cellEditor.setItems(items); - return cellEditor; } @@ -1100,7 +1098,7 @@ private NewMultiplePropertiesAction() { @Override public void run() { if(isAlive(getFirstSelectedElement())) { - MultipleAddDialog dialog = new MultipleAddDialog(fPage.getSite().getShell(), getAllUniquePropertyKeysForModel()); + MultipleAddDialog dialog = new MultipleAddDialog(fPage.getSite().getShell(), getAllUniquePropertyKeysForModel(MAX_ITEMS_ALL)); if(dialog.open() == Window.OK) { List newKeys = dialog.getSelectedKeys(); CompoundCommand cmd = isMultiSelection() ? new CompoundCommand(Messages.UserPropertiesSection_20) : @@ -1350,11 +1348,11 @@ public void dispose() { // ----------------------------------------------------------------------------------------------------------------- private static class MultipleAddDialog extends ExtendedTitleAreaDialog { - private CheckboxTableViewer tableViewer; + private TableViewer tableViewer; private Button buttonSelectAll, buttonDeselectAll; private String[] keys; - private List selectedKeys; + private Set selectedKeys = new HashSet<>(); public MultipleAddDialog(Shell parentShell, String[] keys) { super(parentShell, "ArchimatePropertiesMultipleAddDialog"); //$NON-NLS-1$ @@ -1407,12 +1405,11 @@ private void createTableControl(Composite parent) { tableComp.setLayout(tableLayout); tableComp.setLayoutData(new GridData(GridData.FILL_BOTH)); - Table table = new Table(tableComp, SWT.FULL_SELECTION | SWT.CHECK); - tableViewer = new CheckboxTableViewer(table); + tableViewer = new TableViewer(tableComp, SWT.FULL_SELECTION | SWT.VIRTUAL); tableViewer.getControl().setLayoutData(new GridData(GridData.FILL_BOTH)); // Mac Silicon Item height - UIUtils.fixMacSiliconItemHeight(table); + UIUtils.fixMacSiliconItemHeight(tableViewer.getControl()); tableViewer.getTable().setLinesVisible(true); @@ -1421,23 +1418,49 @@ private void createTableControl(Composite parent) { tableLayout.setColumnData(columnKey.getColumn(), new ColumnWeightData(100, true)); // Content Provider - tableViewer.setContentProvider(new IStructuredContentProvider() { + tableViewer.setContentProvider(new ILazyContentProvider() { @Override public void inputChanged(Viewer viewer, Object oldInput, Object newInput) { + if(newInput != null) { + tableViewer.setItemCount(keys.length); + } } @Override - public void dispose() { + public void updateElement(int index) { + tableViewer.replace(keys[index], index); } @Override - public Object[] getElements(Object inputElement) { - return keys; + public void dispose() { } }); - + // Label Provider - tableViewer.setLabelProvider(new LabelProvider()); + tableViewer.setLabelProvider(new CellLabelProvider() { + @Override + public void update(ViewerCell cell) { + String key = (String)cell.getElement(); + cell.setText(key); + cell.setImage(selectedKeys.contains(key) ? IArchiImages.ImageFactory.getImage(IArchiImages.ICON_CHECKED) + : IArchiImages.ImageFactory.getImage(IArchiImages.ICON_UNCHECKED)); + } + }); + + // Mouse click in Assets table - did we click the checkbox? + new TableCheckListener(tableViewer.getTable()) { + @Override + protected void hit(Object object) { + String key = (String)object; + if(selectedKeys.contains(key)) { + selectedKeys.remove(key); + } + else { + selectedKeys.add(key); + } + } + }; + tableViewer.setInput(keys); } @@ -1456,37 +1479,27 @@ private void createButtonPanel(Composite parent) { buttonSelectAll.setText(Messages.UserPropertiesSection_18); gd = new GridData(GridData.FILL_HORIZONTAL); buttonSelectAll.setLayoutData(gd); - buttonSelectAll.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - tableViewer.setCheckedElements(keys); + buttonSelectAll.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> { + for(String key : keys) { + selectedKeys.add(key); } - }); + tableViewer.setInput(keys); + })); buttonDeselectAll = new Button(client, SWT.PUSH); buttonDeselectAll.setText(Messages.UserPropertiesSection_19); gd = new GridData(GridData.FILL_HORIZONTAL); buttonDeselectAll.setLayoutData(gd); - buttonDeselectAll.addSelectionListener(new SelectionAdapter() { - @Override - public void widgetSelected(SelectionEvent e) { - tableViewer.setCheckedElements(new Object[] {}); - } - }); + buttonDeselectAll.addSelectionListener(SelectionListener.widgetSelectedAdapter(e -> { + selectedKeys = new HashSet<>(); + tableViewer.setInput(keys); + })); } - @Override - protected void okPressed() { - selectedKeys = new ArrayList<>(); - for(Object o : tableViewer.getCheckedElements()) { - selectedKeys.add((String)o); - } - - super.okPressed(); - } - List getSelectedKeys() { - return selectedKeys; + List list = new ArrayList<>(selectedKeys); + Collections.sort(list, (s1, s2) -> s1.compareToIgnoreCase(s2)); + return list; } @Override