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-2017 Berthold Daum */ package com.bdaum.zoom.core.internal; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileFilter; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.commands.operations.IOperationHistory; import org.eclipse.core.commands.operations.IOperationHistoryListener; import org.eclipse.core.commands.operations.IUndoableOperation; import org.eclipse.core.commands.operations.OperationHistoryEvent; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.core.runtime.IConfigurationElement; import org.eclipse.core.runtime.IExtension; import org.eclipse.core.runtime.IExtensionPoint; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.ListenerList; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Platform; import org.eclipse.core.runtime.Plugin; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.custom.BusyIndicator; import org.eclipse.swt.widgets.Shell; import org.eclipse.ui.IWorkbench; import org.eclipse.ui.IWorkbenchWindow; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.operations.IWorkbenchOperationSupport; import org.osgi.framework.BundleContext; import org.osgi.framework.ServiceReference; import com.bdaum.aoModeling.runtime.IdentifiableObject; import com.bdaum.aoModeling.runtime.UUIDgenerator; import com.bdaum.zoom.batch.internal.BatchActivator; import com.bdaum.zoom.cat.model.asset.Asset; import com.bdaum.zoom.cat.model.asset.AssetImpl; import com.bdaum.zoom.cat.model.asset.MediaExtension; import com.bdaum.zoom.cat.model.meta.LastDeviceImport; import com.bdaum.zoom.cat.model.meta.Meta; import com.bdaum.zoom.cat.model.meta.WatchedFolder; import com.bdaum.zoom.cat.model.meta.WatchedFolderImpl; import com.bdaum.zoom.core.AbstractRecipeDetector; import com.bdaum.zoom.core.BagChange; import com.bdaum.zoom.core.CatalogListener; import com.bdaum.zoom.core.Constants; import com.bdaum.zoom.core.Core; import com.bdaum.zoom.core.IAssetProvider; import com.bdaum.zoom.core.ICore; import com.bdaum.zoom.core.IRecipeDetector; import com.bdaum.zoom.core.IVolumeManager; import com.bdaum.zoom.core.IRecipeDetector.IRecipeParameter; import com.bdaum.zoom.core.QueryField; import com.bdaum.zoom.core.db.IDbErrorHandler; import com.bdaum.zoom.core.db.IDbFactory; import com.bdaum.zoom.core.db.IDbManager; import com.bdaum.zoom.core.internal.ai.IAiService; import com.bdaum.zoom.core.internal.db.CatalogConverter; import com.bdaum.zoom.core.internal.db.NullDbManager; import com.bdaum.zoom.core.internal.lire.Algorithm; import com.bdaum.zoom.core.internal.lucene.ILuceneService; import com.bdaum.zoom.core.internal.peer.IPeerService; import com.bdaum.zoom.core.trash.HistoryItem; import com.bdaum.zoom.core.trash.Trash; import com.bdaum.zoom.image.ImageConstants; import com.bdaum.zoom.image.ImageStore; import com.bdaum.zoom.image.internal.ImageActivator; import com.bdaum.zoom.image.internal.ImageCache; import com.bdaum.zoom.program.BatchConstants; import com.bdaum.zoom.program.BatchUtilities; import com.bdaum.zoom.program.IRawConverter; /** * The activator class controls the plug-in life cycle */ @SuppressWarnings("restriction") public class CoreActivator extends Plugin implements ICore, IAdaptable { public static final NullDbManager NULLDBMANAGER = new NullDbManager(); private static final String LOCK = ".lock"; //$NON-NLS-1$ private static final String SHOW = ".show"; //$NON-NLS-1$ private static final String CAT_OPID = "$$cat$$"; //$NON-NLS-1$ public static final String PLUGIN_ID = "com.bdaum.zoom.core"; //$NON-NLS-1$ public static final boolean DEBUG = Boolean.parseBoolean(System.getProperty("com.bdaum.zoom.debug")); //$NON-NLS-1$ private static CoreActivator plugin; private IDbManager dbManager = NULLDBMANAGER; private ListenerList<CatalogListener> listeners = new ListenerList<CatalogListener>(); private VolumeManager volumeManager; private IWorkbenchOperationSupport operationSupport; private IOperationHistory operationHistory; private int backupInterval = 7; private AssetProvider assetProvider; private ImageCache imageCache; private File catFile; private Map<String, WatchedFolder> observedFolders = Collections .synchronizedMap(new HashMap<String, WatchedFolder>()); private LinkedList<CatLocation> recentCats = new LinkedList<CatLocation>(); private IDbFactory dbFactory; private ServiceReference<?> dbfactoryRef; private List<IRecipeDetector> activeRecipeProcessors; private FileWatchManager fileWatchManager; private boolean noProgress; private int backupGenerations; private ArrayList<ICatalogContributor> catalogContributors; private HashMap<String, IMediaSupport> mediaSupportMap; private FileNameExtensionFilter filenameExtensionFilter; private IMediaSupport[] mediaSupports; private boolean processRecipes; private com.bdaum.zoom.core.internal.Locker locker; private File showfile; private HighresImageLoader highresImageLoader; private ServiceReference<IGeoService> geoServiceRef; private ServiceReference<IAiService> aiServiceRef; private int aiUsers; private Map<String, String> mediaMimeMap; private Map<String, Theme> themes; private boolean tetheredShooting; @Override public void start(BundleContext context) throws Exception { super.start(context); plugin = this; IdentifiableObject.setIdentifierGenerator(new UUIDgenerator()); IPath stateLocation = getStateLocation(); showfile = stateLocation.append(SHOW).toFile(); File file = stateLocation.append(LOCK).toFile(); locker = new Locker(file); try { if (!locker.lock()) { logInfo(Messages.CoreActivator_workspace_locked); try { showfile.createNewFile(); String[] commandLineArgs = Platform.getApplicationArgs(); if (commandLineArgs.length > 0) try (BufferedWriter writer = new BufferedWriter(new FileWriter(showfile))) { writer.write(Core.toStringList(commandLineArgs, "\n")); //$NON-NLS-1$ } } catch (Exception e) { // ignore } plugin = null; System.exit(0); } else logInfo(NLS.bind(Messages.CoreActivator_session_started, getBundle().getVersion().toString())); } catch (IOException e) { // don't lock if we can't } if (Constants.WIN32) ImageActivator.getDefault().deleteFileAfterShutdown(file); volumeManager = new VolumeManager(); ImageActivator.getDefault().registerImageIOPlugins(); } /* * (non-Javadoc) * * @see org.eclipse.core.runtime.Plugin#stop(org.osgi.framework.BundleContext) */ @Override public void stop(BundleContext context) throws Exception { try { logInfo(Messages.CoreActivator_session_closed); if (fileWatchManager != null) fileWatchManager.dispose(); if (dbfactoryRef != null) getBundle().getBundleContext().ungetService(dbfactoryRef); if (aiServiceRef != null) context.ungetService(aiServiceRef); if (geoServiceRef != null) context.ungetService(geoServiceRef); if (imageCache != null) { imageCache.dispose(); imageCache = null; } if (volumeManager != null) volumeManager.dispose(); dbManager.close(CatalogListener.SHUTDOWN); } finally { if (locker != null) locker.release(); plugin = null; super.stop(context); } } public void deleteTrashCan() { if (dbManager.hasTrash()) { IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { List<Trash> set = dbManager.obtainTrashToDelete(true); monitor.beginTask(Messages.CoreActivator_Cleaning_up, set.size() + 1); for (Trash t : set) { t.deleteFiles(); monitor.worked(1); } dbManager.closeTrash(); monitor.done(); } }; try { IWorkbenchWindow workbenchWindow = PlatformUI.getWorkbench().getActiveWorkbenchWindow(); if (workbenchWindow != null) new ProgressMonitorDialog(workbenchWindow.getShell()).run(false, true, runnable); else runnable.run(new NullProgressMonitor()); } catch (InvocationTargetException e) { // ignore } catch (InterruptedException e) { // ignore } } } /** * Returns the shared instance * * @return the shared instance */ public static CoreActivator getDefault() { return plugin; } /* * (non-Javadoc) * * @see com.bdaum.zoom.core.ICore#logError(java.lang.String, * java.lang.Throwable) */ public void logError(String message, Throwable e) { getLog().log(new Status(IStatus.ERROR, PLUGIN_ID, message, e)); } /* * (non-Javadoc) * * @see com.bdaum.zoom.core.ICore#logWarning(java.lang.String, * java.lang.Exception) */ public void logWarning(String message, Throwable e) { getLog().log(new Status(IStatus.WARNING, PLUGIN_ID, message, e)); } /* * (non-Javadoc) * * @see com.bdaum.zoom.core.ICore#logInfo(java.lang.String) */ public void logInfo(String message) { getLog().log(new Status(IStatus.INFO, PLUGIN_ID, message)); } public static void logDebug(String message, Object parm) { if (DEBUG) getDefault().getLog().log(new Status(IStatus.INFO, PLUGIN_ID, "Debug: " + (parm == null ? message : NLS.bind(message, parm)))); //$NON-NLS-1$ } /* * (non-Javadoc) * * @see com.bdaum.zoom.core.ICore#openDatabase(java.lang.String, boolean) */ public IDbManager openDatabase(final String fileName) { return openDatabase(fileName, false, null); } public IDbManager openDatabase(final String fileName, final boolean newDb, final Meta meta) { BusyIndicator.showWhile(null, () -> doOpenDatabase(fileName, newDb, meta)); return dbManager; } private void doOpenDatabase(String fileName, boolean newDb, Meta oldMeta) { closeDatabase(); File cfile = new File(fileName); getFileWatchManager().ignore(cfile, CAT_OPID); if (newDb || cfile.exists()) { List<Object> toBeStored = new ArrayList<Object>(); List<Object> toBeDeleted = new ArrayList<Object>(); IDbFactory factory = getDbFactory(); dbManager = factory.createDbManager(fileName, newDb, false, true); Meta newMeta = dbManager.getMeta(true); toBeStored.add(newMeta); if (newDb && oldMeta != null) copyMeta(oldMeta, cfile, toBeStored, newMeta); else if (newDb) { String property = System.getProperty("com.bdaum.zoom.userFields"); //$NON-NLS-1$ if (property != null && !property.isEmpty()) { int p = property.indexOf(','); if (p >= 0) { newMeta.setUserFieldLabel1(property.substring(0, p).trim()); newMeta.setUserFieldLabel2(property.substring(p + 1).trim()); } else newMeta.setUserFieldLabel1(property.trim()); } } if (!toBeStored.isEmpty() || !toBeDeleted.isEmpty()) dbManager.safeTransaction(toBeDeleted, toBeStored); if (newDb) { Utilities.initSystemCollections(dbManager); dbManager.storeAndCommit(newMeta); fireStructureModified(); } else if (newMeta != null && !dbManager.isReadOnly()) { if (dbManager.isEmbedded()) convertDatabase(newMeta); resumeIndexing(newMeta); for (IResumeHandler handler : getResumeHandlers()) handler.resumeWork(newMeta); } } } public void copyMeta(Meta oldMeta, File cfile, List<Object> toBeStored, Meta newMeta) { Utilities.copyMeta(oldMeta, newMeta); Date creationDate = new Date(); newMeta.setCreationDate(creationDate); newMeta.setLastImport(new Date(0L)); newMeta.setCategory(Utilities.cloneCategories(oldMeta.getCategory())); newMeta.setReadonly(false); newMeta.setLastSequenceNo(0); newMeta.setLastYearSequenceNo(0); newMeta.setLastBackup(creationDate); newMeta.setLastBackupFolder(null); String backupLocation = oldMeta.getBackupLocation(); if (backupLocation != null) { int p = backupLocation.lastIndexOf(BatchConstants.CATEXTENSION); if (p >= 0) { int q = backupLocation.lastIndexOf('/', p); if (q < 0) q = backupLocation.lastIndexOf('\\', p); if (q >= 0) backupLocation = backupLocation.substring(0, q + 1) + cfile.getName() + backupLocation.substring(p + BatchConstants.CATEXTENSION.length()); newMeta.setBackupLocation(backupLocation); } } newMeta.setLastSessionEnd(creationDate); newMeta.setLastSelection(null); newMeta.setLastExpansion(new ArrayList<String>(0)); newMeta.setLastCollection(null); newMeta.setPauseFolderWatch(false); newMeta.setCleaned(false); newMeta.setPostponed(new ArrayList<String>(0)); newMeta.setPostponedNaming(new ArrayList<String>(0)); newMeta.setReadonly(false); newMeta.setPlatform(Platform.getOS()); newMeta.setLastPicasaScan(null); newMeta.setPicasaScannerVersion(Constants.PICASASCANNERVERSION); Map<String, LastDeviceImport> lastDeviceImports = newMeta.getLastDeviceImport(); if (lastDeviceImports != null) for (LastDeviceImport deviceImport : lastDeviceImports.values()) { deviceImport.setTimestamp(-1); toBeStored.add(deviceImport); } } public void closeDatabase() { IDbManager old = dbManager; dbManager = NULLDBMANAGER; File file = old.getFile(); if (file != null) try { if (fileWatchManager != null) fileWatchManager.ignore(file, null); old.close(CatalogListener.NORMAL); } catch (Exception e) { logError(Messages.CoreActivator_error_closing_database, e); } } public Set<String> getCbirAlgorithms() { Set<String> cbirAlgorithms = dbManager.getMeta(true).getCbirAlgorithms(); if (cbirAlgorithms != null && !cbirAlgorithms.isEmpty()) return cbirAlgorithms; cbirAlgorithms = new HashSet<String>(); for (Algorithm algorithm : dbFactory.getLireService(true).getSupportedSimilarityAlgorithms()) if (!(algorithm.isAi()) && algorithm.isEssential()) cbirAlgorithms.add(algorithm.getName()); return cbirAlgorithms; } public Algorithm getDefaultCbirAlgorithm() { Set<String> cbirAlgorithms = getCbirAlgorithms(); for (Algorithm algo : dbFactory.getLireService(true).getSupportedSimilarityAlgorithms()) if (cbirAlgorithms.contains(algo.getName())) return algo; return null; } public Set<String> getIndexedTextFields() { return getIndexedTextFields(getDbManager().getMeta(true)); } public Set<String> getIndexedTextFields(Meta meta) { Set<String> fields = meta.getIndexedTextFields(); if (fields != null && !fields.isEmpty()) return fields; fields = new HashSet<String>(); for (QueryField qfield : QueryField.getQueryFields()) if (qfield.isFullTextBase()) fields.add(qfield.getId()); fields.add(ILuceneService.INDEX_SLIDE_TITLE); fields.add(ILuceneService.INDEX_SLIDE_DESCR); fields.add(ILuceneService.INDEX_EXH_TITLE); fields.add(ILuceneService.INDEX_EXH_DESCR); fields.add(ILuceneService.INDEX_EXH_CREDITS); fields.add(ILuceneService.INDEX_WEBGAL_TITLE); fields.add(ILuceneService.INDEX_WEBGAL_DESCR); fields.add(ILuceneService.INDEX_WEBGAL_ALT); fields.add(ILuceneService.INDEX_PERSON_SHOWN); fields.add(ILuceneService.INDEX_FILENAME); return fields; } private IResumeHandler[] getResumeHandlers() { List<IResumeHandler> result = new ArrayList<IResumeHandler>(3); for (IExtension ext : Platform.getExtensionRegistry().getExtensionPoint(PLUGIN_ID, "resumeHandler") //$NON-NLS-1$ .getExtensions()) for (IConfigurationElement conf : ext.getConfigurationElements()) try { result.add((IResumeHandler) conf.createExecutableExtension("class")); //$NON-NLS-1$ } catch (CoreException e) { logError(NLS.bind(Messages.CoreActivator_internal_error_handler_instantiation, conf.getAttribute("name")), e); //$NON-NLS-1$ } return result.toArray(new IResumeHandler[result.size()]); } private void resumeIndexing(Meta meta) { int lireServiceVersion = dbFactory.getLireServiceVersion(); if (lireServiceVersion < 0 || meta.getNoIndex()) { meta.clearPostponed(); dbManager.store(meta.getPostponed()); dbManager.storeAndCommit(meta); return; } // Check if index exists File indexPath = dbManager.getIndexPath(); if (indexPath != null) { Set<String> postponed = meta.getPostponed(); Job job = null; if (indexPath.exists()) { if (meta.getRelevantLireVersion() != lireServiceVersion) { meta.setRelevantLireVersion(lireServiceVersion); IDbErrorHandler errorHandler = getErrorHandler(); if (errorHandler != null) errorHandler.showInformation(Constants.APPLICATION_NAME, NLS.bind(Messages.CoreActivator_wrong_index_version, indexPath), this); deleteOutdatedIndexBackups(meta); job = dbFactory.getLireService(true).createIndexingJob(); } else if (postponed != null && !postponed.isEmpty()) job = dbFactory.getLireService(true) .createIndexingJob(postponed.toArray(new String[postponed.size()])); } else { IDbErrorHandler errorHandler = getErrorHandler(); if (errorHandler != null) errorHandler.showInformation(Constants.APPLICATION_NAME, NLS.bind(Messages.CoreActivator_index_file_does_not_exist, indexPath), this); // String lastBackupFolder = meta.getLastBackupFolder(); // if (lastBackupFolder != null) { // File indexBackup = new File(lastBackupFolder, indexPath.getName()); // if (indexBackup.isDirectory() && !new File(indexBackup, "write.lock") //$NON-NLS-1$ // .exists()) // job = dbFactory.getLireService(true).createIndexingJob(indexBackup, meta.getLastBackup()); // } if (job == null) job = dbFactory.getLireService(true).createIndexingJob(); } if (job != null) { if (postponed != null && !postponed.isEmpty()) { meta.clearPostponed(); dbManager.store(postponed); dbManager.storeAndCommit(meta); } job.schedule(); } } } private void deleteOutdatedIndexBackups(Meta meta) { String backupLocation = meta.getBackupLocation(); String[] result = Utilities.computeBackupLocation(catFile, backupLocation); backupLocation = result[0]; String generationFolder = result[1]; if (generationFolder != null) { final String generationPattern = result[2]; File gFolder = new File(generationFolder); if (gFolder.exists()) { File[] children = gFolder.listFiles(new FileFilter() { public boolean accept(File child) { return (child.isDirectory() && child.getName().matches(generationPattern)); } }); if (children != null) { File indexPath = dbManager.getIndexPath(); if (indexPath != null) { String indexFolderName = indexPath.getName(); for (File folder : children) { File indexFolder = new File(folder, indexFolderName); if (indexFolder.exists()) BatchUtilities.deleteFileOrFolder(indexFolder); } } } } } } @SuppressWarnings({ "unchecked", "rawtypes" }) public Object getAdapter(Class adapter) { return null; } public IDbFactory getDbFactory() { if (dbFactory == null) { BundleContext bundleContext = getBundle().getBundleContext(); dbfactoryRef = bundleContext.getServiceReference(IDbFactory.class.getName()); if (dbfactoryRef != null) dbFactory = (IDbFactory) bundleContext.getService(dbfactoryRef); } return dbFactory; } public IDbErrorHandler getErrorHandler() { IDbFactory factory = getDbFactory(); return factory == null ? null : factory.getErrorHandler(); } public IMediaSupport getMediaSupport(String format) { return getMediaSupportMap().get(format); } public Set<String> getMediaFormats() { return getMediaMimeMap().keySet(); } public Map<String, String> getMediaMimeMap() { if (mediaMimeMap == null) { mediaMimeMap = new HashMap<String, String>(30); for (IExtension extension : Platform.getExtensionRegistry().getExtensionPoint(PLUGIN_ID, "mediaSupport") //$NON-NLS-1$ .getExtensions()) for (IConfigurationElement conf : extension.getConfigurationElements()) { StringTokenizer st = new StringTokenizer(conf.getAttribute("formats")); //$NON-NLS-1$ StringTokenizer stm = new StringTokenizer(conf.getAttribute("mimetypes")); //$NON-NLS-1$ while (st.hasMoreTokens() && stm.hasMoreTokens()) mediaMimeMap.put(st.nextToken(), stm.nextToken()); } } return mediaMimeMap; } public Map<String, IMediaSupport> getMediaSupportMap() { if (mediaSupportMap == null) { mediaSupportMap = new HashMap<String, IMediaSupport>(5); for (IExtension extension : Platform.getExtensionRegistry().getExtensionPoint(PLUGIN_ID, "mediaSupport") //$NON-NLS-1$ .getExtensions()) for (IConfigurationElement conf : extension.getConfigurationElements()) { String name = conf.getAttribute("name"); //$NON-NLS-1$ String plural = conf.getAttribute("plural"); //$NON-NLS-1$ String collectionID = conf.getAttribute("collectionID"); //$NON-NLS-1$ try { IMediaSupport mediaSupport = (IMediaSupport) conf.createExecutableExtension("class"); //$NON-NLS-1$ mediaSupport.setName(name); mediaSupport.setPlural(plural); mediaSupport.setCollectionId(collectionID); Map<String, String> mimeMap = new HashMap<String, String>(30); StringTokenizer st = new StringTokenizer(conf.getAttribute("formats")); //$NON-NLS-1$ StringTokenizer stm = new StringTokenizer(conf.getAttribute("mimetypes")); //$NON-NLS-1$ while (st.hasMoreTokens() && stm.hasMoreTokens()) { String ext = st.nextToken(); mimeMap.put(ext, stm.nextToken()); mediaSupportMap.put(ext, mediaSupport); } mediaSupport.setMimeMap(mimeMap); } catch (CoreException e) { logError(NLS.bind(Messages.CoreActivator_internal_error_instantiating_media_support, name), e); } } } return mediaSupportMap; } private void convertDatabase(final Meta meta) { final IDbManager db = getDbManager(); int catVersion = meta.getVersion(); int supportedVersion = db.getVersion(); if (catVersion > supportedVersion) Core.getCore().getDbFactory().getErrorHandler().fatalError(Messages.CoreActivator_unsupported_version, NLS.bind(Messages.CoreActivator_use_newer_version, Constants.APPLICATION_NAME, db.getFileName()), (IAdaptable) db); else if (catVersion < supportedVersion) { IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) { monitor.beginTask(Messages.CoreActivator_converting_cat, IProgressMonitor.UNKNOWN); monitor.subTask(Messages.CoreActivator_backing_up_cat); db.performBackup(0L, -1L, true); monitor.subTask(Messages.CoreActivator_converting_to_new_version); CatalogConverter.convert(db, monitor); logInfo(NLS.bind(Messages.CoreActivator_catalog_converted, db.getVersion())); monitor.done(); } }; IWorkbench workbench = PlatformUI.getWorkbench(); Shell shell = workbench.getWorkbenchWindowCount() > 0 ? workbench.getWorkbenchWindows()[0].getShell() : null; if (shell != null) { shell.getDisplay().syncExec(() -> { try { new ProgressMonitorDialog(shell).run(true, false, runnable); } catch (InvocationTargetException e1) { logError(NLS.bind(Messages.CoreActivator_error_when_updating_to_version_n, db.getVersion()), e1); } catch (InterruptedException e2) { // should never happen } }); } else try { runnable.run(new NullProgressMonitor()); } catch (InvocationTargetException e) { logError(NLS.bind(Messages.CoreActivator_error_when_updating_to_version_n, db.getVersion()), e); } catch (InterruptedException e) { // should never happen } } } /* * (non-Javadoc) * * @see com.bdaum.zoom.core.ICore#getDbManager() */ public IDbManager getDbManager() { return dbManager; } /* * (non-Javadoc) * * @see com.bdaum.zoom.core.ICore#getImageCache() */ public ImageStore getImageCache() { if (imageCache == null) imageCache = new ImageCache(new AssetImageProvider(), 257); return imageCache; } /* * (non-Javadoc) * * @see com.bdaum.zoom.core.ICore#getAssetProvider() */ public AssetProvider getAssetProvider() { if (assetProvider == null) assetProvider = new AssetProvider(dbManager); return assetProvider; } /* * (non-Javadoc) * * @see com.bdaum.zoom.core.ICore#addCatalogListener(com.bdaum.zoom.core. * CatalogListener) */ public void addCatalogListener(CatalogListener l) { listeners.add(l); if (dbManager != NULLDBMANAGER) { l.catalogOpened(false); l.assetsModified(null, null); } } /* * (non-Javadoc) * * @see com.bdaum.zoom.core.ICore#removeCatalogListener(com.bdaum.zoom.core. * CatalogListener) */ public void removeCatalogListener(CatalogListener l) { listeners.remove(l); } public void fireCatalogClosed(int mode) { if (dbManager.getFile() != null) { if (mode != CatalogListener.EMERGENCY) { for (CatalogListener listener : listeners) listener.catalogClosed(mode); resetInfrastructure(); System.setProperty(Constants.PROP_CATACCESS, Constants.PROP_CATACCESS_NONE); } catFile = dbManager.getFile(); dbManager.close(mode); dbManager = NULLDBMANAGER; } if (catFile != null && mode != CatalogListener.EMERGENCY) { if (fileWatchManager != null) fileWatchManager.ignore(catFile, null); addToRecentCats(catFile); } } private void addToRecentCats(File f) { CatLocation loc = new CatLocation(f); recentCats.remove(loc); if (recentCats.size() > 3) recentCats.remove(recentCats.size() - 1); recentCats.add(0, loc); } public void fireCatalogOpened(boolean newDb) { System.setProperty(Constants.PROP_CATACCESS, dbManager.isReadOnly() ? Constants.PROP_CATACCESS_READ : Constants.PROP_CATACCESS_WRITE); resetInfrastructure(); for (CatalogListener listener : listeners) listener.catalogOpened(newDb); fireAssetsModified(null, null); } private void resetInfrastructure() { assetProvider = null; if (imageCache != null) { imageCache.dispose(); imageCache = null; } } public void fireApplyRules(Collection<? extends Asset> assets, QueryField node) { for (CatalogListener listener : listeners) listener.applyRules(assets, node); } /* * (non-Javadoc) * * @see com.bdaum.zoom.core.ICore#fireAssetsModified(java.util.List, * com.bdaum.zoom.core.QueryField) */ public void fireAssetsModified(BagChange<Asset> changes, QueryField node) { if (resetInfrastructure(assetProvider, changes == null ? null : changes.getChanged(), node)) for (CatalogListener listener : listeners) listener.assetsModified(null, null); else for (CatalogListener listener : listeners) listener.assetsModified(changes, node); } public boolean resetInfrastructure(IAssetProvider provider, Collection<? extends Asset> assets, Object node) { if (provider != null) { if (node instanceof QueryField && provider.invalidate((QueryField) node)) // forced redraw return true; if (node == null && imageCache != null) // image has changed imageCache.invalidateImages(assets); } return false; } /* * (non-Javadoc) * * @see com.bdaum.zoom.core.ICore#fireStructureModified() */ public void fireStructureModified() { if (assetProvider != null) assetProvider.resetProcessor(); for (CatalogListener listener : listeners) listener.structureModified(); } /* * (nicht-Javadoc) * * @see com.bdaum.zoom.core.ICore#fireCatalogSelection(org.eclipse.jface.viewers * .IStructuredSelection) */ public void fireCatalogSelection(IStructuredSelection selection, boolean forceUpdate) { for (CatalogListener listener : listeners) listener.setCatalogSelection(selection, forceUpdate); } /* * (non-Javadoc) * * @see com.bdaum.zoom.core.ICore#fireHierarchyModified() */ public void fireHierarchyModified() { for (CatalogListener listener : listeners) listener.hierarchyModified(); } public void fireBookmarksModified() { for (CatalogListener listener : listeners) listener.bookmarksModified(); } /* * (non-Javadoc) * * @see com.bdaum.zoom.core.ICore#performOperation(org.eclipse.core.commands. * operations.IUndoableOperation, org.eclipse.core.runtime.IProgressMonitor, * org.eclipse.core.runtime.IAdaptable) */ public IStatus performOperation(IUndoableOperation op, IProgressMonitor monitor, IAdaptable info) { if (operationHistory == null) { operationSupport = PlatformUI.getWorkbench().getOperationSupport(); operationHistory = operationSupport.getOperationHistory(); operationHistory.addOperationHistoryListener(new IOperationHistoryListener() { public void historyNotification(OperationHistoryEvent event) { if (event.getEventType() == OperationHistoryEvent.OPERATION_REMOVED && event.getOperation() instanceof HistoryItem) { getDbManager().deleteAllTrash(dbManager.getTrash(HistoryItem.class, ((HistoryItem) event.getOperation()).getOpId())); } } }); } op.addContext(operationSupport.getUndoContext()); try { return operationHistory.execute(op, monitor, info); } catch (ExecutionException e) { return new Status(IStatus.ERROR, PLUGIN_ID, NLS.bind(Messages.CoreActivator_Cannot_execute_operation, op.getLabel()), e); } } public IVolumeManager getVolumeManager() { return volumeManager; } public void putObservedFolder(WatchedFolder folder) { observedFolders.put(folder.getStringId(), folder); } public void removeObservedFolder(WatchedFolder folder) { observedFolders.remove(folder.getStringId()); } public WatchedFolder getObservedFolder(String id) { WatchedFolder observedFolder = doGetObservedFolder(id); if (observedFolder == null) { WatchedFolder obj = dbManager.obtainById(WatchedFolderImpl.class, id); if (obj != null) putObservedFolder(observedFolder = obj); } return observedFolder; } private WatchedFolder doGetObservedFolder(String id) { return observedFolders.get(id); } public void purgeObsoleteWatchedFolderEntries() { List<Object> toBeDeleted = new ArrayList<Object>(); for (WatchedFolderImpl wf : dbManager.obtainObjects(WatchedFolderImpl.class)) if (!observedFolders.containsKey(wf.getStringId())) toBeDeleted.add(wf); dbManager.safeTransaction(toBeDeleted, null); } public WatchedFolder getObservedSubfolder(WatchedFolder observedFolder, File subFolder) { if (!observedFolder.getRecursive()) return null; String volume = getVolumeManager().getVolumeForFile(subFolder); String id = Utilities.computeWatchedFolderId(subFolder, volume); WatchedFolderImpl observedMember = (WatchedFolderImpl) getObservedFolder(id); if (observedMember == null) { observedMember = new WatchedFolderImpl(subFolder.toURI().toString(), volume, 0L, true, observedFolder.getTransfer() ? null : getFileWatchManager().getDefaultFilters(), observedFolder.getTransfer(), observedFolder.getArtist(), observedFolder.getSkipDuplicates(), observedFolder.getSkipPolicy(), observedFolder.getTargetDir(), observedFolder.getSubfolderPolicy(), observedFolder.getSelectedTemplate(), observedFolder.getCue(), observedFolder.getFileSource(), observedFolder.getTethered()); observedMember.setStringId(id); putObservedFolder(observedMember); } return observedMember; } public void setBackupInterval(int backupInterval) { this.backupInterval = backupInterval; } public void setCatFile(File catFile) { this.catFile = catFile; } public File getCatFile() { return catFile; } public void saveFolderStates() { dbManager.safeTransaction(null, observedFolders.values()); } public int getBackupInterval() { return backupInterval; } public LinkedList<CatLocation> getRecentCats() { return recentCats; } public void setRecentCats(LinkedList<CatLocation> recentCats) { this.recentCats = recentCats; } public boolean isNetworked() { return getPeerService() != null; } public IPeerService getPeerService() { return getDbFactory().getPeerService(); } public IAiService getAiService() { BundleContext bundleContext = getBundle().getBundleContext(); if (aiServiceRef == null) aiUsers = 0; if (aiUsers > 0) { ++aiUsers; return bundleContext.getService(aiServiceRef); } aiServiceRef = bundleContext.getServiceReference(IAiService.class); if (aiServiceRef != null) { ++aiUsers; return bundleContext.getService(aiServiceRef); } return null; } public void ungetAiService(IAiService service, String providerId) { --aiUsers; if (aiUsers <= 0 && aiServiceRef != null) { service.dispose(providerId); getBundle().getBundleContext().ungetService(aiServiceRef); aiServiceRef = null; } } public List<IRecipeDetector> getRecipeDetectors() { List<IRecipeDetector> recipeProcessors = new ArrayList<IRecipeDetector>(); for (IExtension extension : Platform.getExtensionRegistry().getExtensionPoint(PLUGIN_ID, "recipeDetector") //$NON-NLS-1$ .getExtensions()) for (IConfigurationElement conf : extension.getConfigurationElements()) { String name = conf.getAttribute("name"); //$NON-NLS-1$ try { IRecipeDetector processor = (IRecipeDetector) conf.createExecutableExtension("class"); //$NON-NLS-1$ processor.setName(name); processor.setId(conf.getAttribute("id")); //$NON-NLS-1$ for (IConfigurationElement parameter : conf.getChildren()) { IRecipeParameter parm = new AbstractRecipeDetector.RecipeParameter( parameter.getAttribute("name"), //$NON-NLS-1$ parameter.getAttribute("id"), parameter.getAttribute("default")); //$NON-NLS-1$ //$NON-NLS-2$ processor.addParameter(parm); for (IConfigurationElement value : parameter.getChildren()) parm.addValueDescriptor(new AbstractRecipeDetector.RecipeParameter.RecipeParameterValue( value.getAttribute("label"), //$NON-NLS-1$ value.getAttribute("id"))); //$NON-NLS-1$ } recipeProcessors.add(processor); } catch (CoreException e) { logError(NLS.bind(Messages.CoreActivator_cannot_create_recipe_processor, name), e); } } return recipeProcessors; } public List<IRecipeDetector> getActiveRecipeDetectors() { return activeRecipeProcessors; } public void configureActiveRecipeDetectors(String[] detectorIds, boolean processRecipes) { this.processRecipes = processRecipes; List<IRecipeDetector> recipeDetectors = getRecipeDetectors(); if (detectorIds != null) { activeRecipeProcessors = new ArrayList<IRecipeDetector>(detectorIds.length); for (String id : detectorIds) for (IRecipeDetector detector : recipeDetectors) if (id.equals(detector.getId())) activeRecipeProcessors.add(detector); } else activeRecipeProcessors = null; } public List<IRecipeDetector> getDetectors(String[] detectorIds) { if (detectorIds == null) return activeRecipeProcessors; if (!processRecipes) return null; List<IRecipeDetector> detectors = new ArrayList<IRecipeDetector>(detectorIds.length); for (IRecipeDetector detector : getRecipeDetectors()) for (String id : detectorIds) if (id.equals(detector.getId())) { detectors.add(detector); break; } return detectors; } public FileWatchManager getFileWatchManager() { if (fileWatchManager == null) fileWatchManager = new FileWatchManager(); return fileWatchManager; } public boolean containsRawImage(List<Asset> assets, boolean includeDng) { for (Asset asset : assets) if (ImageConstants.isRaw(asset.getUri(), includeDng)) return true; return false; } public void setNoProgress(boolean noProgress) { this.noProgress = noProgress; } /** * @return the noProgress */ public boolean isNoProgress() { return noProgress; } public void setBackupGenerations(int backupGenerations) { this.backupGenerations = backupGenerations; } /** * @return the backUpGenerations */ public int getBackupGenerations() { return backupGenerations; } /** * @return registered catalog contributors */ public Collection<ICatalogContributor> getCatalogContributors() { if (catalogContributors == null) { catalogContributors = new ArrayList<ICatalogContributor>(3); for (IExtension extension : Platform.getExtensionRegistry() .getExtensionPoint(PLUGIN_ID, "catalogContributor").getExtensions()) //$NON-NLS-1$ for (IConfigurationElement conf : extension.getConfigurationElements()) try { catalogContributors.add((ICatalogContributor) conf.createExecutableExtension("class")); //$NON-NLS-1$ } catch (CoreException e) { logError(NLS.bind(Messages.CoreActivator_error_instantiating_catalog_contributor, conf.getAttribute("name")), e); //$NON-NLS-1$ } } return catalogContributors; } /** * Stops all indexing jobs and recreates the index from scratch */ public void recreateIndex() { Job.getJobManager().cancel(Constants.INDEXING); Core.waitOnJobCanceled(Constants.INDEXING); dbFactory.getLuceneService().releaseAllIndexReadersAndWriters(); Job job = dbFactory.getLireService(true).createIndexingJob(); if (job != null) job.schedule(); } public FileNameExtensionFilter getFilenameExtensionFilter() { if (filenameExtensionFilter == null) { String[] imageExtensions = ImageConstants.getSupportedImageFileExtensionsGroups(true); Set<String> mediaFormats = getMediaFormats(); String[] extensions = new String[imageExtensions.length + mediaFormats.size()]; System.arraycopy(imageExtensions, 0, extensions, 0, imageExtensions.length); int i = imageExtensions.length; for (String f : mediaFormats) extensions[i++] = f; filenameExtensionFilter = new FileNameExtensionFilter(extensions, true); } return filenameExtensionFilter; } public IMediaSupport[] getMediaSupport() { if (mediaSupports == null) { Set<IMediaSupport> values = new HashSet<IMediaSupport>(getMediaSupportMap().values()); mediaSupports = values.toArray(new IMediaSupport[values.size()]); Arrays.sort(mediaSupports, new Comparator<IMediaSupport>() { public int compare(IMediaSupport o1, IMediaSupport o2) { return o1.getName().compareTo(o2.getName()); } }); } return mediaSupports; } public String[] testOnShow() { if (showfile.exists()) { List<String> parms = new ArrayList<String>(); try (BufferedReader reader = new BufferedReader(new FileReader(showfile))) { while (true) { String line = reader.readLine(); if (line == null) break; parms.add(line); } } catch (IOException e) { // do nothing } showfile.delete(); return parms.toArray(new String[parms.size()]); } return null; } public long getFreeSpace(File targetFile) { return getFileWatchManager().getFreeSpace(getVolumeManager().getRootFile(targetFile)); } public void classifyFile(File member, List<File> newFiles, List<File> outdatedFiles, Map<String, File> xmpMap, List<IRecipeDetector> activeRecipeDetectors, long lastScan) { long filedate = member.lastModified(); if (filedate > 0L) { long xmpdate = Long.MIN_VALUE, recipeModified = Long.MIN_VALUE; if (xmpMap != null) { String filename = member.getName(); int p = filename.lastIndexOf('.'); File sidecar = xmpMap.get(p >= 0 ? filename.substring(0, p) : filename); if (sidecar != null) xmpdate = sidecar.lastModified(); } URI uri = member.toURI(); if (activeRecipeDetectors != null) { IRawConverter currentRawConverter = BatchActivator.getDefault().getCurrentRawConverter(false); if (currentRawConverter != null) { long timestamp = currentRawConverter.getLastRecipeModification(uri.toString(), 0L, null); if (timestamp > 0) recipeModified = timestamp; } } if (filedate >= lastScan || xmpdate >= lastScan || recipeModified >= lastScan) { Iterator<AssetImpl> ait = dbManager.obtainAssetsForFile(uri).iterator(); if (ait.hasNext()) { AssetImpl asset = ait.next(); Date lastModification = asset.getLastModification(); Date xmpModifiedAt = asset.getXmpModifiedAt(); long lastmod = lastModification != null ? lastModification.getTime() : Long.MIN_VALUE; if (lastmod < filedate || xmpModifiedAt == null && lastmod < xmpdate || xmpModifiedAt != null && xmpModifiedAt.getTime() < xmpdate || recipeModified > lastmod) outdatedFiles.add(member); } else if (dbManager.obtainTrashForFile(uri).isEmpty() && dbManager.obtainGhostsForFile(uri).isEmpty()) newFiles.add(member); } } } public HighresImageLoader getHighresImageLoader() { if (highresImageLoader == null) highresImageLoader = new HighresImageLoader(); return highresImageLoader; } public IGeoService getGeoService() { BundleContext bundleContext = getBundle().getBundleContext(); geoServiceRef = bundleContext.getServiceReference(IGeoService.class); return geoServiceRef != null ? bundleContext.getService(geoServiceRef) : null; } public Map<String, Theme> getThemes() { if (themes == null) { themes = new HashMap<>(6); IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(PLUGIN_ID, "catalogTheme"); //$NON-NLS-1$ for (IExtension iExtension : extensionPoint.getExtensions()) for (IConfigurationElement conf : iExtension.getConfigurationElements()) { String id = conf.getAttribute("id"); //$NON-NLS-1$ themes.put(id, new Theme(id, conf.getAttribute("name"), conf.getAttribute("keywords"), //$NON-NLS-1$ //$NON-NLS-2$ conf.getAttribute("categories"), Boolean.parseBoolean(conf.getAttribute("default")))); //$NON-NLS-1$ //$NON-NLS-2$ } } return themes; } public Theme getCurrentTheme() { String themeID = dbManager.getMeta(true).getThemeID(); Map<String, Theme> themes = getThemes(); if (themeID == null || themeID.isEmpty()) for (Theme theme : themes.values()) if (theme.isDefault()) return theme; return themes.get(themeID); } @Override public boolean isTetheredShootingActive() { return tetheredShooting; } public void setTetheredShooting(boolean tetheredShooting) { this.tetheredShooting = tetheredShooting; } @Override public boolean isMultiMedia(Collection<Asset> assets) { for (Asset asset : assets) { MediaExtension[] mediaExtension = asset.getMediaExtension(); if (mediaExtension != null && mediaExtension.length > 0) return true; } return false; } }