Java tutorial
/* * This file is part of the ZoRa project: http://www.photozora.org. * * ZoRa is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * ZoRa is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with ZoRa; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * (c) 2009-2016 Berthold Daum */ package com.bdaum.zoom.ui.internal.views; import java.io.File; import java.net.URI; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.jface.action.Action; import org.eclipse.jface.action.ControlContribution; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.IToolBarManager; import org.eclipse.jface.action.Separator; import org.eclipse.jface.dialogs.IInputValidator; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.jface.window.Window; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.events.KeyEvent; import org.eclipse.swt.events.MouseEvent; import org.eclipse.swt.events.MouseMoveListener; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.RowData; import org.eclipse.swt.layout.RowLayout; import org.eclipse.swt.widgets.Button; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Control; import org.eclipse.swt.widgets.DirectoryDialog; import org.eclipse.swt.widgets.Event; import org.eclipse.swt.widgets.Scale; import org.eclipse.swt.widgets.Shell; import org.eclipse.swt.widgets.ToolItem; import org.eclipse.swt.widgets.Widget; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IMemento; import org.eclipse.ui.IViewSite; import org.eclipse.ui.IWorkbenchCommandConstants; import org.eclipse.ui.PartInitException; import org.eclipse.ui.actions.ActionFactory; import com.bdaum.zoom.cat.model.asset.Asset; import com.bdaum.zoom.cat.model.asset.AssetImpl; import com.bdaum.zoom.cat.model.asset.Region; import com.bdaum.zoom.cat.model.asset.RegionImpl; import com.bdaum.zoom.cat.model.group.GroupImpl; import com.bdaum.zoom.cat.model.group.SmartCollection; import com.bdaum.zoom.cat.model.group.SmartCollectionImpl; import com.bdaum.zoom.cat.model.group.SortCriterion; import com.bdaum.zoom.core.BagChange; import com.bdaum.zoom.core.Constants; import com.bdaum.zoom.core.Core; import com.bdaum.zoom.core.IAssetFilter; import com.bdaum.zoom.core.IAssetProvider; import com.bdaum.zoom.core.IScoreFormatter; import com.bdaum.zoom.core.IVolumeManager; import com.bdaum.zoom.core.QueryField; import com.bdaum.zoom.core.db.IColorCodeFilter; import com.bdaum.zoom.core.db.IDbManager; import com.bdaum.zoom.core.db.IRatingFilter; import com.bdaum.zoom.core.db.ITypeFilter; import com.bdaum.zoom.core.internal.ImportState; import com.bdaum.zoom.job.OperationJob; import com.bdaum.zoom.operations.internal.AddAlbumOperation; import com.bdaum.zoom.operations.internal.RetargetOperation; import com.bdaum.zoom.ui.AssetSelection; import com.bdaum.zoom.ui.INavigationHistory; import com.bdaum.zoom.ui.IZoomActionConstants; import com.bdaum.zoom.ui.IZoomCommandIds; import com.bdaum.zoom.ui.Ui; import com.bdaum.zoom.ui.dialogs.AcousticMessageDialog; import com.bdaum.zoom.ui.dialogs.ZInputDialog; import com.bdaum.zoom.ui.internal.Icons; import com.bdaum.zoom.ui.internal.Icons.Icon; import com.bdaum.zoom.ui.internal.StartListener; import com.bdaum.zoom.ui.internal.UiActivator; import com.bdaum.zoom.ui.internal.UiUtilities; import com.bdaum.zoom.ui.internal.actions.SelectionActionCluster; import com.bdaum.zoom.ui.internal.actions.ZoomActionFactory; import com.bdaum.zoom.ui.internal.dialogs.AlbumSelectionDialog; import com.bdaum.zoom.ui.internal.dialogs.ColorCodeDialog; import com.bdaum.zoom.ui.internal.dialogs.FileFormatDialog; import com.bdaum.zoom.ui.internal.dialogs.RatingDialog; import com.bdaum.zoom.ui.internal.dialogs.RetargetDialog; import com.bdaum.zoom.ui.internal.dialogs.SelectTargetDialog; import com.bdaum.zoom.ui.internal.dialogs.SetPersonDialog; @SuppressWarnings("restriction") public abstract class AbstractGalleryView extends ImageView implements StartListener, SelectionActionClusterProvider { private static final int DEFAULTTHUMBSIZE = 128; protected class ScaleContributionItem extends ControlContribution { private Scale scale; private final int min; private final int max; private long lastTime = -2000L; private int lastThumbSize = DEFAULTTHUMBSIZE; protected ScaleContributionItem(String id, int min, int max) { super(id); this.min = min; this.max = max; } @Override protected Control createControl(Composite parent) { Composite comp = new Composite(parent, SWT.NONE); RowLayout layout = new RowLayout(); layout.spacing = layout.marginBottom = layout.marginTop = 0; comp.setLayout(layout); Button button = new Button(comp, SWT.NONE); button.setImage(Icons.refresh.getImage()); button.setToolTipText(Messages.getString("AbstractGalleryView.return_to_previous_thumbnail_size")); //$NON-NLS-1$ button.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { int s = thumbsize; thumbsize = lastThumbSize; lastThumbSize = s; scale.setSelection(thumbsize); fireSizeChanged(); } }); scale = new Scale(comp, SWT.NONE); scale.setLayoutData(new RowData(100, SWT.DEFAULT)); scale.setMinimum(min); scale.setMaximum(max); scale.setSelection(thumbsize); setTooltipText(); scale.addSelectionListener(new SelectionAdapter() { @Override public void widgetSelected(SelectionEvent e) { thumbsize = scale.getSelection(); if (e.time - lastTime > 1000) lastThumbSize = thumbsize; lastTime = e.time; setFocussedItem(null); setTooltipText(); fireSizeChanged(); } }); return comp; } public int getSelection() { return scale.getSelection(); } public boolean isDisposed() { return scale.isDisposed(); } public void setSelection(int selection) { thumbsize = selection; long time = System.currentTimeMillis(); if (time - lastTime > 1000) lastThumbSize = thumbsize; lastTime = time; scale.setSelection(selection); setTooltipText(); fireSizeChanged(); } private void setTooltipText() { int thumbnailWidth = ImportState .computeThumbnailWidth(Core.getCore().getDbManager().getMeta(true).getThumbnailResolution()); scale.setToolTipText(NLS.bind(Messages.getString("LightboxView.adjust_size_of_thumbnails"), //$NON-NLS-1$ (scale.getSelection() * 100 / thumbnailWidth))); } public void increment(int incr) { thumbsize += incr; setSelection(thumbsize + incr); } public void increment() { increment(scale.getPageIncrement()); } public void decrement() { increment(-scale.getPageIncrement()); } } protected static final String THUMBNAIL_SIZE = "com.bdaum.zoom.currentThumbnailSize"; //$NON-NLS-1$ protected static final int MAXTHUMBSIZE = 512; protected static final int MINTHUMBSIZE = 48; private static final List<Asset> EMPTYLIST = new ArrayList<>(0); private static final String LAST_SELECTION = "com.bdaum.zoom.lastSelection"; //$NON-NLS-1$ protected IStructuredSelection selection; private IAction removeFromAlbumAction; private IAction selectRatingAction; private IAction selectFileTypeAction; private IAction saveQueryAction; private String initialSelection; protected int thumbsize = DEFAULTTHUMBSIZE; // protected GalleryMouseWheelListener mouseWheelListener; protected IScoreFormatter scoreFormatter; protected int refreshing; protected IAction collapseAction; protected Set<Asset> expandedSet = new HashSet<Asset>(); protected int[] foldingIndex; protected int foldingHw = 0; protected boolean folding = false; private IAction retargetAction; private Action selectColorCodeAction; protected IAction configureCollapseAction; private IAction renameAction; private IAction stackAction; private IAction splitCatAction; protected SelectionActionCluster selectionActionCluster; private long lastActivated; public IAssetProvider getAssetProvider() { return Core.getCore().getAssetProvider(); } public void setFocussedItem(MouseEvent ev) { // do nothing } protected void fireSizeChanged() { // do nothing } @Override public void keyReleased(KeyEvent e) { switch (e.character) { case '+': if (scaleContributionItem != null) scaleContributionItem.increment(); return; case '-': if (scaleContributionItem != null) scaleContributionItem.decrement(); return; } super.keyReleased(e); } @Override public void init(IViewSite site, IMemento memento) throws PartInitException { super.init(site, memento); if (memento != null) { IAssetProvider assetProvider = getAssetProvider(); if (assetProvider == null || assetProvider.getLastSelection() == null) initialSelection = memento.getString(LAST_SELECTION); Integer thsize = memento.getInteger(THUMBNAIL_SIZE); if (thsize != null) thumbsize = thsize; } } @Override public void saveState(IMemento memento) { if (memento != null) { IAssetProvider assetProvider = getAssetProvider(); if (assetProvider != null) { String lastSelection = assetProvider.getLastSelection(); if (lastSelection != null) memento.putString(LAST_SELECTION, lastSelection); } memento.putInteger(THUMBNAIL_SIZE, thumbsize); } } protected void createScaleContributionItem(int min, int max) { scaleContributionItem = new ScaleContributionItem("scale", min, max); //$NON-NLS-1$ } protected void addDragDropSupport() { addDragDropSupport(true, true, true); } @Override protected void makeActions(IActionBars bars) { super.makeActions(bars); saveQueryAction = new Action(Messages.getString("AbstractGalleryView.save_query_as_collection"), //$NON-NLS-1$ Icons.tableSave.getDescriptor()) { @Override public void run() { IAssetProvider assetProvider = getAssetProvider(); final SmartCollectionImpl currentCollection = assetProvider == null ? null : assetProvider.getCurrentCollection(); if (currentCollection != null && currentCollection.getAdhoc()) { final SmartCollection parent = currentCollection.getSmartCollection_subSelection_parent(); ZInputDialog dialog = new ZInputDialog(getSite().getShell(), parent != null ? NLS.bind(Messages.getString("AbstractGalleryView.save_as_subcollection"), //$NON-NLS-1$ parent.getName()) : Messages.getString("AbstractGalleryView.save_as_collection"), //$NON-NLS-1$ Messages.getString("AbstractGalleryView.collection_name"), currentCollection.getName(), //$NON-NLS-1$ new IInputValidator() { public String isValid(String newText) { if (newText != null && !newText.isEmpty()) return null; return Messages.getString("AbstractGalleryView.please_specify_a_name"); //$NON-NLS-1$ } }, false); if (dialog.open() == Window.OK) { String name = dialog.getValue(); currentCollection.setName(name); currentCollection.setAdhoc(false); final IDbManager dbManager = Core.getCore().getDbManager(); dbManager.safeTransaction(() -> { if (parent != null) { parent.addSubSelection(currentCollection); dbManager.store(parent); } else { GroupImpl user = UiUtilities.obtainUserGroup(dbManager); user.addRootCollection(currentCollection.getStringId()); currentCollection.setGroup_rootCollection_parent(user.getStringId()); dbManager.store(user); } dbManager.store(currentCollection); }); try { CatalogView catalogView = (CatalogView) getSite().getPage().showView(CatalogView.ID); catalogView.refresh(); catalogView.setSelection(new StructuredSelection(currentCollection)); } catch (PartInitException e) { // should never happen } updateActions(false); } } } }; saveQueryAction.setToolTipText(Messages.getString("AbstractGalleryView.adds_the_current_query")); //$NON-NLS-1$ removeFromAlbumAction = addAction(ZoomActionFactory.REMOVEFROMALBUM.create(bars, this)); selectRatingAction = new Action(Messages.getString("AbstractGalleryView.show_all_images"), //$NON-NLS-1$ Icons.ratingAll.getDescriptor()) { @Override public void runWithEvent(Event event) { IRatingFilter oldFilter = null; IAssetFilter[] filters = getNavigationHistory().getFilters(); int rating = QueryField.SELECTALL; if (filters != null) for (IAssetFilter filter : filters) { if (filter instanceof IRatingFilter) { oldFilter = ((IRatingFilter) filter); rating = oldFilter.getRating(); break; } } RatingDialog dialog = new RatingDialog(getSite().getShell(), rating); dialog.create(); Widget widget = event.widget; if (widget instanceof ToolItem) { Rectangle bounds = ((ToolItem) widget).getBounds(); dialog.getShell().setLocation( ((ToolItem) widget).getParent().toDisplay(bounds.x, bounds.y + bounds.height)); } int newRating = dialog.open(); if (newRating != RatingDialog.SELECTABORT && (newRating != rating)) { IRatingFilter newFilter = newRating != QueryField.SELECTALL ? Core.getCore().getDbFactory().createRatingFilter(newRating) : null; getNavigationHistory().updateFilters(oldFilter, newFilter); String tooltip = newRating <= 0 ? null : NLS.bind(Messages.getString("AbstractGalleryView.show_only_image_or_better"), //$NON-NLS-1$ QueryField.RATING.getEnumLabels()[newRating + 1]); Icon icon; switch (newRating) { case QueryField.SELECTALL: tooltip = Messages.getString("AbstractGalleryView.show_all_images"); //$NON-NLS-1$ icon = Icons.ratingAll; break; case 0: icon = Icons.rating0; break; case 1: icon = Icons.rating1; break; case 2: icon = Icons.rating2; break; case 3: icon = Icons.rating3; break; case 4: icon = Icons.rating4; break; case 5: icon = Icons.rating5; break; default: tooltip = Messages.getString("AbstractGalleryView.show_unrated_images"); //$NON-NLS-1$ icon = Icons.rating_undef; break; } setToolTipText(tooltip); setImageDescriptor(icon.getDescriptor()); } } }; selectRatingAction.setToolTipText(Messages.getString("AbstractGalleryView.show_images_with_rating")); //$NON-NLS-1$ selectColorCodeAction = new Action(Messages.getString("AbstractGalleryView.indepent_of_color_code"), //$NON-NLS-1$ Icons.dashed.getDescriptor()) { @Override public void runWithEvent(Event event) { IColorCodeFilter oldFilter = null; IAssetFilter[] filters = getNavigationHistory().getFilters(); int colorCode = QueryField.SELECTALL; if (filters != null) for (IAssetFilter filter : filters) { if (filter instanceof IColorCodeFilter) { oldFilter = ((IColorCodeFilter) filter); colorCode = oldFilter.getColorCode(); break; } } ColorCodeDialog dialog = new ColorCodeDialog(getSite().getShell(), colorCode); dialog.create(); Widget widget = event.widget; if (widget instanceof ToolItem) { Rectangle bounds = ((ToolItem) widget).getBounds(); dialog.getShell().setLocation( ((ToolItem) widget).getParent().toDisplay(bounds.x, bounds.y + bounds.height)); } int newColorCode = dialog.open(); if (newColorCode != ColorCodeDialog.SELECTABORT && (newColorCode != colorCode)) { IColorCodeFilter newFilter = newColorCode != Constants.COLOR_UNDEFINED ? Core.getCore().getDbFactory().createColorCodeFilter(newColorCode) : null; getNavigationHistory().updateFilters(oldFilter, newFilter); String tooltip = newColorCode <= 0 ? null : NLS.bind(Messages.getString("AbstractGalleryView.with_color_code"), //$NON-NLS-1$ QueryField.COLORCODELABELS[newColorCode + 1]); Icon icon; switch (newColorCode) { case Constants.COLOR_BLACK: icon = Icons.black; break; case Constants.COLOR_WHITE: icon = Icons.white; break; case Constants.COLOR_RED: icon = Icons.red; break; case Constants.COLOR_GREEN: icon = Icons.green; break; case Constants.COLOR_BLUE: icon = Icons.blue; break; case Constants.COLOR_CYAN: icon = Icons.cyan; break; case Constants.COLOR_MAGENTA: icon = Icons.magenta; break; case Constants.COLOR_YELLOW: icon = Icons.yellow; break; case Constants.COLOR_ORANGE: icon = Icons.orange; break; case Constants.COLOR_PINK: icon = Icons.pink; break; case Constants.COLOR_VIOLET: icon = Icons.violet; break; default: tooltip = Messages.getString("AbstractGalleryView.indepent_of_color_code"); //$NON-NLS-1$ icon = Icons.dashed; break; } setToolTipText(tooltip); setImageDescriptor(icon.getDescriptor()); } } }; selectColorCodeAction.setToolTipText(Messages.getString("AbstractGalleryView.with_selected_color_code")); //$NON-NLS-1$ selectFileTypeAction = new Action(Messages.getString("AbstractGalleryView.select_file_type"), //$NON-NLS-1$ Icons.format.getDescriptor()) { @Override public void runWithEvent(Event event) { int formats = ITypeFilter.ALLFORMATS; ITypeFilter oldFilter = null; IAssetFilter[] filters = getNavigationHistory().getFilters(); if (filters != null) for (IAssetFilter filter : filters) if (filter instanceof ITypeFilter) { oldFilter = ((ITypeFilter) filter); formats = oldFilter.getFormats(); break; } FileFormatDialog dialog = new FileFormatDialog(getSite().getShell(), formats); dialog.create(); Widget widget = event.widget; if (widget instanceof ToolItem) { Rectangle bounds = ((ToolItem) widget).getBounds(); dialog.getShell().setLocation( ((ToolItem) widget).getParent().toDisplay(bounds.x, bounds.y + bounds.height)); } int newFormats = dialog.open(); if (newFormats >= 0 && newFormats != formats) { ITypeFilter newFilter = newFormats == ITypeFilter.ALLFORMATS ? null : Core.getCore().getDbFactory().createTypeFilter(newFormats); getNavigationHistory().updateFilters(oldFilter, newFilter); String tooltip; Icon icon; if (newFormats == ITypeFilter.ALLFORMATS) { tooltip = Messages.getString("AbstractGalleryView.show_all_images_independent_of_format"); //$NON-NLS-1$ icon = Icons.format; } else { icon = Icons.formatSelect; StringBuffer sb = new StringBuffer(); if ((newFormats & ITypeFilter.RAW) != 0) sb.append("Raw"); //$NON-NLS-1$ if ((newFormats & ITypeFilter.DNG) != 0) { if (sb.length() > 0) sb.append(", "); //$NON-NLS-1$ sb.append("DNG"); //$NON-NLS-1$ } if ((newFormats & ITypeFilter.JPEG) != 0) { if (sb.length() > 0) sb.append(", "); //$NON-NLS-1$ sb.append("JPEG"); //$NON-NLS-1$ } if ((newFormats & ITypeFilter.TIFF) != 0) { if (sb.length() > 0) sb.append(", "); //$NON-NLS-1$ sb.append("TIFF"); //$NON-NLS-1$ } if ((newFormats & ITypeFilter.OTHER) != 0) { if (sb.length() > 0) sb.append(", "); //$NON-NLS-1$ sb.append(Messages.getString("AbstractGalleryView.Other")); //$NON-NLS-1$ } if ((newFormats & ITypeFilter.MEDIA) != 0) { if (sb.length() > 0) sb.append(", "); //$NON-NLS-1$ sb.append(Messages.getString("AbstractGalleryView.other_media")); //$NON-NLS-1$ } tooltip = NLS.bind( Messages.getString("AbstractGalleryView.show_only_images_with_selected_formats"), //$NON-NLS-1$ sb); } setToolTipText(tooltip); setImageDescriptor(icon.getDescriptor()); } } }; selectFileTypeAction .setToolTipText(Messages.getString("AbstractGalleryView.show_all_images_independent_of_format")); //$NON-NLS-1$ retargetAction = new Action(Messages.getString("AbstractGalleryView.retarget")) { //$NON-NLS-1$ @Override public void runWithEvent(Event event) { AssetSelection sel = (AssetSelection) getSelection(); AssetImpl asset = (AssetImpl) sel.getFirstElement(); URI uri = Core.getCore().getVolumeManager().findFile(asset); File file = new File(uri); DirectoryDialog dialog = new DirectoryDialog(getSite().getShell()); dialog.setText(Messages.getString("AbstractGalleryView.retarget_title")); //$NON-NLS-1$ dialog.setFilterPath(file.getParent()); String oldPath = file.getPath(); String folderPath = dialog.open(); if (folderPath != null) { File folder = new File(folderPath); File newFile = new File(folder, file.getName()); if (!newFile.exists()) { List<File> files = new ArrayList<File>(); collectFiles(folder, file.getName(), files); if (files.isEmpty()) { AcousticMessageDialog.openInformation(getSite().getShell(), Messages.getString("AbstractGalleryView.retarget_title"), //$NON-NLS-1$ NLS.bind(Messages.getString("AbstractGalleryView.target_file_not_found"), //$NON-NLS-1$ file.getName(), folder)); return; } SelectTargetDialog selectDialog = new SelectTargetDialog(getSite().getShell(), files, folder); if (selectDialog.open() != SelectTargetDialog.OK) return; newFile = selectDialog.getFile(); } if (newFile.getName().equals(file.getName())) { RetargetDialog retargetDialog = new RetargetDialog(getSite().getShell(), oldPath, newFile.getAbsolutePath()); if (retargetDialog.open() == RetargetDialog.OK) OperationJob .executeOperation( new RetargetOperation(asset, newFile, retargetDialog.getResult(), retargetDialog.getRetargetVoiceNote()), AbstractGalleryView.this); } else AcousticMessageDialog.openInformation(getSite().getShell(), Messages.getString("AbstractGalleryView.retarget_impossible"), //$NON-NLS-1$ Messages.getString("AbstractGalleryView.file_names_do_not_match")); //$NON-NLS-1$ } } private void collectFiles(File folder, String name, List<File> files) { File[] members = folder.listFiles(); if (members != null) for (File file : members) if (file.isDirectory()) collectFiles(file, name, files); else if (file.getName().equals(name)) files.add(file); } }; retargetAction.setToolTipText(Messages.getString("AbstractGalleryView.retarget_tooltip")); //$NON-NLS-1$ renameAction = addAction(ZoomActionFactory.BULKRENAME.create(bars, this)); stackAction = addAction(ZoomActionFactory.STACK.create(bars, this)); splitCatAction = addAction(ZoomActionFactory.SPLITCATALOG.create(null, this)); selectionActionCluster = ZoomActionFactory.createSelectionActionCluster(this, this); } public SelectionActionCluster getSelectActionCluster() { return selectionActionCluster; } @Override protected void fillLocalPullDown(IMenuManager manager) { manager.add(viewImageAction); manager.add(new Separator()); manager.add(editAction); manager.add(editWithAction); manager.add(new Separator()); if (collapseAction != null) manager.add(collapseAction); if (configureCollapseAction != null) manager.add(configureCollapseAction); selectionActionCluster.addToMenuManager(manager); manager.add(new Separator()); manager.add(addBookmarkAction); manager.add(saveQueryAction); } @Override protected void fillContextMenu(IMenuManager manager) { boolean readOnly = dbIsReadonly(); fillEditAndSearchGroup(manager, readOnly); fillVoiceNote(manager, readOnly); fillMetaData(manager, readOnly); fillRelationsGroup(manager); manager.add(new Separator(IZoomActionConstants.MB_SUBMENUS)); fillShowAndDeleteGroup(manager, readOnly); fillBulkGroup(manager, readOnly); super.fillAdditions(manager); } private void fillBulkGroup(IMenuManager manager, boolean readOnly) { if (!readOnly) { manager.add(new Separator()); manager.add(categorizeAction); } } @Override protected void fillShowAndDeleteGroup(IMenuManager manager, boolean readOnly) { manager.add(showInFolderAction); manager.add(showInTimeLineAction); manager.add(new Separator()); if (!readOnly) { // manager.add(getSelectAllAction()); manager.add(addBookmarkAction); manager.add(addToAlbumAction); IAssetProvider assetProvider = getAssetProvider(); if (assetProvider != null && assetProvider.getCurrentCollection().getAlbum()) manager.add(removeFromAlbumAction); ISelection sel = getSelection(); if (sel instanceof AssetSelection && !sel.isEmpty()) { if (((AssetSelection) sel).size() == 1 && Core.getCore().getVolumeManager() .findExistingFile(((AssetSelection) sel).getAssets().get(0), false) == null) manager.add(retargetAction); else manager.add(refreshAction); } manager.add(renameAction); manager.add(ratingAction); manager.add(stackAction); manager.add(deleteAction); } } @Override protected void fillLocalToolBar(IToolBarManager manager) { if (collapseAction != null) manager.add(collapseAction); if (scaleContributionItem != null) manager.add(scaleContributionItem); manager.add(selectFileTypeAction); manager.add(selectRatingAction); manager.add(selectColorCodeAction); manager.add(new Separator()); manager.add(viewImageAction); manager.add(new Separator()); manager.add(editAction); manager.add(editWithAction); manager.add(new Separator()); manager.add(addBookmarkAction); manager.add(saveQueryAction); manager.add(new Separator()); } protected IActionBars contributeToActionBars() { IActionBars bars = super.contributeToActionBars(); bars.setGlobalActionHandler(ActionFactory.SELECT_ALL.getId(), selectionActionCluster.getAction(SelectionActionCluster.SELECTALL)); return bars; } public ISelection getSelection() { return (selection != null) ? selection : StructuredSelection.EMPTY; } @Override public boolean collectionChanged() { INavigationHistory navigationHistory = getNavigationHistory(); if (navigationHistory != null) { IAssetProvider assetProvider = getAssetProvider(); if (assetProvider != null) { assetProvider.setCurrentCollection(navigationHistory.getSelectedCollection()); assetProvider.setCurrentFilters(navigationHistory.getFilters()); assetProvider.setCurrentSort(navigationHistory.getCustomSort()); } } return true; } @Override public boolean assetsChanged() { return true; } @Override public boolean selectionChanged() { return false; } @Override public Object getContent() { IAssetProvider assetProvider = getAssetProvider(); if (assetProvider != null) return assetProvider.getCurrentCollection(); return super.getContent(); } @Override public void selectAll() { BusyIndicator.showWhile(getSite().getShell().getDisplay(), () -> setAssetSelection(new AssetSelection(getAssetProvider()))); } @Override public void selectNone() { setAssetSelection(AssetSelection.EMPTY); } @Override public void revertSelection() { IAssetProvider assetProvider = getAssetProvider(); if (assetProvider != null) { Set<Asset> allAssets = new HashSet<>(assetProvider.getAssets()); allAssets.removeAll(getAssetSelection().getAssets()); setSelection(new AssetSelection(new ArrayList<>(allAssets))); } } @Override public void select(int type, boolean shift, boolean alt) { if (alt || shift) { Set<Asset> currentSelection = new HashSet<>(getAssetSelection().getAssets()); if (alt) currentSelection.removeAll(select(type)); else currentSelection.addAll(select(type)); setAssetSelection(new AssetSelection(new ArrayList<>(currentSelection))); } else setAssetSelection(new AssetSelection(select(type))); } private List<Asset> select(int type) { List<Asset> result = EMPTYLIST; IAssetProvider assetProvider = getAssetProvider(); if (assetProvider != null) { List<Asset> assets = assetProvider.getAssets(); result = new ArrayList<>(assets.size()); for (Asset asset : assets) if (testAsset(type, asset)) result.add(asset); } return result; } protected boolean testAsset(int type, Asset asset) { boolean selected = false; switch (type) { case SelectionActionCluster.UNRATED: selected = asset.getRating() < 0; break; case SelectionActionCluster.RATED0: case SelectionActionCluster.RATED1: case SelectionActionCluster.RATED2: case SelectionActionCluster.RATED3: case SelectionActionCluster.RATED4: case SelectionActionCluster.RATED5: selected = asset.getRating() == type; break; case SelectionActionCluster.UNCODED: selected = asset.getColorCode() < 0; break; case SelectionActionCluster.CODEDBLACK: selected = asset.getColorCode() == Constants.COLOR_BLACK; break; case SelectionActionCluster.CODEDBLUE: selected = asset.getColorCode() == Constants.COLOR_BLUE; break; case SelectionActionCluster.CODEDCYAN: selected = asset.getColorCode() == Constants.COLOR_CYAN; break; case SelectionActionCluster.CODEGREEN: selected = asset.getColorCode() == Constants.COLOR_GREEN; break; case SelectionActionCluster.CODEDMAGENTA: selected = asset.getColorCode() == Constants.COLOR_MAGENTA; break; case SelectionActionCluster.CODEDORANGE: selected = asset.getColorCode() == Constants.COLOR_ORANGE; break; case SelectionActionCluster.CODEDPINK: selected = asset.getColorCode() == Constants.COLOR_PINK; break; case SelectionActionCluster.CODEDRED: selected = asset.getColorCode() == Constants.COLOR_RED; break; case SelectionActionCluster.CODEDVIOLET: selected = asset.getColorCode() == Constants.COLOR_VIOLET; break; case SelectionActionCluster.CODEDWHITE: selected = asset.getColorCode() == Constants.COLOR_WHITE; break; case SelectionActionCluster.CODEDYELLOW: selected = asset.getColorCode() == Constants.COLOR_YELLOW; break; case SelectionActionCluster.NOTGEODED: selected = Double.isNaN(asset.getGPSLatitude()) || Double.isNaN(asset.getGPSLongitude()); break; case SelectionActionCluster.GEOCODED: selected = !Double.isNaN(asset.getGPSLatitude()) && !Double.isNaN(asset.getGPSLongitude()); break; case SelectionActionCluster.LOCAL: selected = asset.getFileState() != IVolumeManager.PEER; break; case SelectionActionCluster.PEER: selected = asset.getFileState() == IVolumeManager.PEER; break; case SelectionActionCluster.ORPHAN: selected = asset.getFileState() != IVolumeManager.PEER && Core.getCore().getVolumeManager().determineFileState(asset) == IVolumeManager.OFFLINE; break; } return selected; } @Override public void assetsModified(final BagChange<Asset> changes, final QueryField node) { Shell shell = getSite().getShell(); if (!shell.isDisposed()) shell.getDisplay().asyncExec(() -> { if (!shell.isDisposed()) { refresh(); updateActions(false); } }); } public boolean redrawCollection(Collection<? extends Asset> assets, QueryField node) { ++refreshing; try { launchDecorator(); return doRedrawCollection(assets, node); } finally { --refreshing; } } public int getRefreshing() { return refreshing; } protected abstract boolean doRedrawCollection(Collection<? extends Asset> assets, QueryField node); protected boolean fetchAssets() { IAssetProvider assetProvider = getAssetProvider(); if (assetProvider == null) return false; final SmartCollectionImpl currentCollection = assetProvider.getCurrentCollection(); assetProvider.setCurrentFilters(getNavigationHistory().getFilters()); assetProvider.setCurrentSort(getNavigationHistory().getCustomSort()); assetProvider.selectAssets(); if (currentCollection != null) { setPartName(currentCollection.getName()); StringBuilder des = new StringBuilder(128); if (currentCollection.getAdhoc()) des.append(UiUtilities.composeContentDescription(currentCollection, " - ", false, true)); //$NON-NLS-1$ SortCriterion currentSort = assetProvider.getCurrentSort(); if (currentSort != null) { QueryField qfield = QueryField.findQueryField(currentSort.getField()); if (qfield != null) { if (des.length() > 0) des.append(" - "); //$NON-NLS-1$ des.append(NLS.bind(Messages.getString("AbstractGalleryView.forced_sort"), qfield.getLabel())); //$NON-NLS-1$ } } setContentDescription(des.toString()); } else { setDefaultPartName(); setContentDescription(""); //$NON-NLS-1$ } updateActions(false); updateStatusLine(); return assetProvider.canProvideAssets(); } protected abstract void setDefaultPartName(); @Override protected void updateStatusLine() { IAssetProvider assetProvider = getAssetProvider(); if (assetProvider == null || assetProvider.getCurrentCollection() == null) setStatusMessage(Messages.getString("AbstractGalleryView.no_collection"), false); //$NON-NLS-1$ else if (assetProvider.isEmpty()) setStatusMessage(assetProvider.getCurrentCollection().getAdhoc() ? Messages.getString("AbstractGalleryView.no_results") //$NON-NLS-1$ : Messages.getString("AbstractGalleryView.collection_empty"), false); //$NON-NLS-1$ else setStatusMessage(NLS.bind(Messages.getString("AbstractGalleryView.n_images"), //$NON-NLS-1$ String.valueOf(getAssetProvider().getAssetCount()), String.valueOf(selection == null ? 0 : selection.size())), false); } @Override public void filterChanged() { redrawCollection(null, null); fireSelection(); } @Override public void refresh() { redrawCollection(null, null); if (initialSelection != null) { IAssetProvider assetProvider = getAssetProvider(); if (assetProvider != null) { SmartCollectionImpl coll = assetProvider.loadCollection(initialSelection); if (coll != null) Ui.getUi().getNavigationHistory(getSite().getWorkbenchWindow()) .selectionChanged(new SelectionChangedEvent(this, new StructuredSelection(coll))); initialSelection = null; } } } @Override protected void registerCommands() { registerCommand(selectionActionCluster.getAction(SelectionActionCluster.SELECTALL), IWorkbenchCommandConstants.EDIT_SELECT_ALL); registerCommand(selectionActionCluster.getAction(SelectionActionCluster.SELECTNONE), IZoomCommandIds.Deselect); registerCommand(selectionActionCluster.getAction(SelectionActionCluster.REVERT), IZoomCommandIds.Revert); registerCommand(removeFromAlbumAction, IZoomCommandIds.RemoveFromAlbum); registerCommand(splitCatAction, IZoomCommandIds.SplitCatalogCommand); super.registerCommands(); } @Override public void updateActions(boolean force) { if (removeFromAlbumAction != null && (isVisible() || force)) { super.updateActions(force); boolean writable = !dbIsReadonly(); int localCount = getSelectionCount(true); boolean localSel = localCount > 0 && writable; removeFromAlbumAction.setEnabled(localSel); renameAction.setEnabled(localSel); stackAction.setEnabled(localSel && localCount > 1); splitCatAction.setEnabled(true); IAssetProvider assetProvider = getAssetProvider(); boolean hasProvider = assetProvider != null; selectionActionCluster.updateActions(); SmartCollectionImpl currentCollection = hasProvider ? assetProvider.getCurrentCollection() : null; boolean canSave = false; if (currentCollection != null) { if (currentCollection.getAdhoc() && !currentCollection.getSystem()) canSave = true; SmartCollection parent = currentCollection.getSmartCollection_subSelection_parent(); if (parent != null && (parent.getAdhoc() || parent.getCriterion().size() == 1 && parent.getCriterion(0).getField().startsWith("*"))) //$NON-NLS-1$ canSave = false; } saveQueryAction.setEnabled(canSave && writable); } } protected void addCueListener() { getControl().addMouseMoveListener(new MouseMoveListener() { private Object cue; public void mouseMove(MouseEvent e) { Object ob = findObject(e.x, e.y); if (ob != null) { if (!ob.equals(cue)) getNavigationHistory().postCueChanged(cue = ob); } else if (cue != null) getNavigationHistory().postCueChanged(cue = ob); } }); } protected void setAppStarting(final Control control) { if (UiActivator.getDefault().addStartListener(this)) setSystemCursor(control, SWT.CURSOR_APPSTARTING); } public void hasStarted() { setSystemCursor(getControl(), SWT.CURSOR_ARROW); } private static void setSystemCursor(Control control, int format) { if (control != null && !control.isDisposed()) control.setCursor(control.getDisplay().getSystemCursor(format)); } protected void stopAudio() { UiActivator.getDefault().stopAudio(); } protected void editRegionName(ImageRegion foundRegion) { Asset asset = foundRegion.owner; String regionId = foundRegion.regionId; IDbManager dbManager = Core.getCore().getDbManager(); List<RegionImpl> set = dbManager.obtainObjects(RegionImpl.class, false, Constants.OID, regionId, QueryField.EQUALS, "asset_person_parent", //$NON-NLS-1$ asset.getStringId(), QueryField.EQUALS); String assignedAlbums = null; RegionImpl region; if (!set.isEmpty()) { region = set.get(0); String albumId = region.getAlbum(); if (dbManager.exists(SmartCollectionImpl.class, albumId)) assignedAlbums = albumId; } else { region = new RegionImpl(false, null, null, "", Region.type_face, null); //$NON-NLS-1$ region.setStringId(regionId); region.setAsset_person_parent(asset.getStringId()); } SetPersonDialog dialog = new SetPersonDialog(getSite().getShell(), assignedAlbums, asset.getStringId()); if (dialog.open() == AlbumSelectionDialog.OK) { boolean deleteRegion = dialog.isDeleteRegion(); boolean deleteAll = dialog.isDeleteAllRegions(); OperationJob.executeOperation(new AddAlbumOperation(deleteAll ? null : dialog.getResult(), Collections.singletonList(asset), deleteAll ? null : region, deleteRegion || deleteAll), this); } } @Override protected void setVisible(boolean visible) { if (isVisible() != visible) { super.setVisible(visible); if (visible) lastActivated = System.currentTimeMillis(); } } public long getLastActivated() { return lastActivated; } }