diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionRegistry.cpp b/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionRegistry.cpp index bd600d2bcc..360ee8568c 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionRegistry.cpp +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionRegistry.cpp @@ -1,1340 +1,1340 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "berryExtensionRegistry.h" #include "berryCombinedEventDelta.h" #include "berryConfigurationElement.h" #include "berryConfigurationElementAttribute.h" #include "berryConfigurationElementDescription.h" #include "berryExtension.h" #include "berryExtensionHandle.h" #include "berryExtensionPoint.h" #include "berryExtensionPointHandle.h" #include "berryExtensionsParser.h" #include "berryIConfigurationElement.h" #include "berryIExtension.h" #include "berryIExtensionPoint.h" #include "berrySimpleExtensionPointFilter.h" #include "berryMultiStatus.h" #include "berryRegistryConstants.h" #include "berryRegistryContribution.h" #include "berryRegistryContributor.h" #include "berryRegistryMessages.h" #include "berryRegistryObjectFactory.h" #include "berryRegistryObjectManager.h" #include "berryRegistryProperties.h" #include "berryRegistryStrategy.h" #include "berryStatus.h" #include -#include +#include namespace berry { struct ExtensionRegistry::ListenerInfo { IExtensionPointFilter filter; IRegistryEventListener* listener; ListenerInfo(IRegistryEventListener* listener, const IExtensionPointFilter& filter) : filter(filter), listener(listener) { } /** * Used by ListenerList to ensure uniqueness. */ bool operator==(const ListenerInfo& another) const { return another.listener == this->listener; } }; void ExtensionRegistry::Add(const SmartPointer &element) { QWriteLocker l(&access); eventDelta = CombinedEventDelta::RecordAddition(); BasicAdd(element, true); FireRegistryChangeEvent(); eventDelta.Reset(); } QString ExtensionRegistry::AddExtension(int extension) { Extension::Pointer addedExtension = registryObjects->GetObject(extension, RegistryObjectManager::EXTENSION).Cast(); QString extensionPointToAddTo = addedExtension->GetExtensionPointIdentifier(); ExtensionPoint::Pointer extPoint = registryObjects->GetExtensionPointObject(extensionPointToAddTo); //orphan extension if (extPoint.IsNull()) { registryObjects->AddOrphan(extensionPointToAddTo, extension); return QString(); } // otherwise, link them QList newExtensions = extPoint->GetRawChildren(); newExtensions.push_back(extension); Link(extPoint, newExtensions); if (!eventDelta.IsNull()) eventDelta.RememberExtension(extPoint, extension); return extPoint->GetNamespace(); //return RecordChange(extPoint, extension, ExtensionDelta::ADDED); } QString ExtensionRegistry::AddExtensionPoint(int extPoint) { ExtensionPoint::Pointer extensionPoint = registryObjects->GetObject(extPoint, RegistryObjectManager::EXTENSION_POINT).Cast(); if (!eventDelta.IsNull()) eventDelta.RememberExtensionPoint(extensionPoint); QList orphans = registryObjects->RemoveOrphans(extensionPoint->GetUniqueIdentifier()); if (orphans.empty()) return QString(); Link(extensionPoint, orphans); if (!eventDelta.IsNull()) eventDelta.RememberExtensions(extensionPoint, orphans); return extensionPoint->GetNamespace(); //return RecordChange(extensionPoint, orphans, ExtensionDelta::ADDED); } QSet ExtensionRegistry::AddExtensionsAndExtensionPoints(const SmartPointer& element) { // now add and resolve extensions and extension points QSet affectedNamespaces; QList extPoints = element->GetExtensionPoints(); for (int i = 0; i < extPoints.size(); i++) { QString namespaze = this->AddExtensionPoint(extPoints[i]); if (!namespaze.isEmpty()) affectedNamespaces.insert(namespaze); } QList extensions = element->GetExtensions(); for (int i = 0; i < extensions.size(); i++) { QString namespaze = this->AddExtension(extensions[i]); if (!namespaze.isEmpty()) affectedNamespaces.insert(namespaze); } return affectedNamespaces; } void ExtensionRegistry::AddListenerInternal(IRegistryEventListener* listener, const IExtensionPointFilter& filter) { listeners.Add(ListenerInfo(listener, filter)); } void ExtensionRegistry::BasicAdd(const SmartPointer& element, bool link) { registryObjects->AddContribution(element); if (!link) return; AddExtensionsAndExtensionPoints(element); SetObjectManagers(registryObjects->CreateDelegatingObjectManager( registryObjects->GetAssociatedObjects(element->GetContributorId()))); } void ExtensionRegistry::SetObjectManagers(const SmartPointer& manager) { if (!eventDelta.IsNull()) eventDelta.SetObjectManager(manager); } void ExtensionRegistry::BasicRemove(const QString& contributorId) { // ignore anonymous namespaces RemoveExtensionsAndExtensionPoints(contributorId); QHash associatedObjects = registryObjects->GetAssociatedObjects(contributorId); registryObjects->RemoveObjects(associatedObjects); registryObjects->AddNavigableObjects(associatedObjects); // put the complete set of navigable objects SetObjectManagers(registryObjects->CreateDelegatingObjectManager(associatedObjects)); registryObjects->RemoveContribution(contributorId); registryObjects->RemoveContributor(contributorId); } void ExtensionRegistry::FireRegistryChangeEvent() { // if there is nothing to say, just bail out if (listeners.IsEmpty()) { return; } // for thread safety, create tmp collections QList tmpListeners = listeners.GetListeners(); // do the notification asynchronously //strategy->ScheduleChangeEvent(tmpListeners, tmpDeltas, this); this->ScheduleChangeEvent(tmpListeners, eventDelta); } //RegistryDelta ExtensionRegistry::GetDelta(const QString& namespaze) const //{ // // is there a delta for the plug-in? // RegistryDelta existingDelta = deltas.value(namespaze); // if (existingDelta != null) // return existingDelta; // //if not, create one // RegistryDelta delta = new RegistryDelta(); // deltas.put(namespace, delta); // return delta; //} void ExtensionRegistry::Link(const SmartPointer& extPoint, const QList& extensions) { extPoint->SetRawChildren(extensions); registryObjects->Add(extPoint, true); } //QString ExtensionRegistry::RecordChange(const SmartPointer& extPoint, int extension, int kind) //{ // // avoid computing deltas when there are no listeners // if (listeners.isEmpty()) // return QString(); // ExtensionDelta extensionDelta = new ExtensionDelta(); // extensionDelta.setExtension(extension); // extensionDelta.setExtensionPoint(extPoint.getObjectId()); // extensionDelta.setKind(kind); // getDelta(extPoint.getNamespace()).addExtensionDelta(extensionDelta); // return extPoint.getNamespace(); //} //QString ExtensionRegistry::RecordChange(const SmartPointer& extPoint, const QList& extensions, int kind) //{ // if (listeners.isEmpty()) // return null; // QString namespace = extPoint.getNamespace(); // if (extensions == null || extensions.length == 0) // return namespace; // RegistryDelta pluginDelta = getDelta(extPoint.getNamespace()); // for (int i = 0; i < extensions.length; i++) { // ExtensionDelta extensionDelta = new ExtensionDelta(); // extensionDelta.setExtension(extensions[i]); // extensionDelta.setExtensionPoint(extPoint.getObjectId()); // extensionDelta.setKind(kind); // pluginDelta.addExtensionDelta(extensionDelta); // } // return namespace; //} QString ExtensionRegistry::RemoveExtension(int extensionId) { Extension::Pointer extension = registryObjects->GetObject(extensionId, RegistryObjectManager::EXTENSION).Cast(); registryObjects->RemoveExtensionFromNamespaceIndex(extensionId, extension->GetNamespaceIdentifier()); QString xptName = extension->GetExtensionPointIdentifier(); ExtensionPoint::Pointer extPoint = registryObjects->GetExtensionPointObject(xptName); if (extPoint.IsNull()) { registryObjects->RemoveOrphan(xptName, extensionId); return QString(); } // otherwise, unlink the extension from the extension point QList existingExtensions = extPoint->GetRawChildren(); QList newExtensions; if (existingExtensions.size() > 1) { for (int i = 0; i < existingExtensions.size(); ++i) if (existingExtensions[i] != extension->GetObjectId()) newExtensions.push_back(existingExtensions[i]); } Link(extPoint, newExtensions); if (!eventDelta.IsNull()) eventDelta.RememberExtension(extPoint, extensionId); return extPoint->GetNamespace(); //return recordChange(extPoint, extension.getObjectId(), IExtensionDelta.REMOVED); } QString ExtensionRegistry::RemoveExtensionPoint(int extPoint) { ExtensionPoint::Pointer extensionPoint = registryObjects->GetObject( extPoint, RegistryObjectManager::EXTENSION_POINT).Cast(); registryObjects->RemoveExtensionPointFromNamespaceIndex(extPoint, extensionPoint->GetNamespace()); QList existingExtensions = extensionPoint->GetRawChildren(); if (!existingExtensions.empty()) { registryObjects->AddOrphans(extensionPoint->GetUniqueIdentifier(), existingExtensions); Link(extensionPoint, QList()); } if (!eventDelta.IsNull()) { eventDelta.RememberExtensionPoint(extensionPoint); eventDelta.RememberExtensions(extensionPoint, existingExtensions); } return extensionPoint->GetNamespace(); //return recordChange(extensionPoint, existingExtensions, IExtensionDelta.REMOVED); } QSet ExtensionRegistry::RemoveExtensionsAndExtensionPoints(const QString& contributorId) { QSet affectedNamespaces; QList extensions = registryObjects->GetExtensionsFrom(contributorId); for (int i = 0; i < extensions.size(); i++) { QString namespaze = this->RemoveExtension(extensions[i]); if (!namespaze.isEmpty()) affectedNamespaces.insert(namespaze); } // remove extension points QList extPoints = registryObjects->GetExtensionPointsFrom(contributorId); for (int i = 0; i < extPoints.size(); i++) { QString namespaze = this->RemoveExtensionPoint(extPoints[i]); if (!namespaze.isEmpty()) affectedNamespaces.insert(namespaze); } return affectedNamespaces; } struct ExtensionRegistry::QueueElement { QList listenerInfos; CombinedEventDelta scheduledDelta; QueueElement() { } QueueElement(const QList& infos, const CombinedEventDelta& delta) : listenerInfos(infos), scheduledDelta(delta) { } }; class ExtensionRegistry::RegistryEventThread : public QThread { private: QAtomicInt stop; ExtensionRegistry* registry; Queue& queue; public: RegistryEventThread(ExtensionRegistry* registry, Queue& queue) : stop(0), registry(registry), queue(queue) { this->setObjectName("Extension Registry Event Dispatcher"); } void interrupt() { stop.fetchAndStoreOrdered(1); } void run() override { while (!stop.fetchAndAddOrdered(0)) { QueueElement element; { Queue::Locker l(&queue); while (queue.empty()) queue.wait(); element = queue.takeFirst(); } registry->ProcessChangeEvent(element.listenerInfos, element.scheduledDelta); } } }; bool ExtensionRegistry::CheckReadWriteAccess(QObject* key, bool persist) const { if (masterToken == key) return true; if (userToken == key && !persist) return true; return false; } void ExtensionRegistry::LogError(const QString& owner, const QString& contributionName, const ctkException& e) { QString message = QString("Could not parse XML contribution for \"%1\". Any contributed extensions " "and extension points will be ignored.").arg(QString(owner) + "/" + contributionName); IStatus::Pointer status(new Status(IStatus::ERROR_TYPE, RegistryMessages::OWNER_NAME, 0, message, e, BERRY_STATUS_LOC)); Log(status); } void ExtensionRegistry::CreateExtensionData(const QString& contributorId, const ConfigurationElementDescription& description, const SmartPointer& parent, bool persist) { ConfigurationElement::Pointer currentConfigurationElement = GetElementFactory()->CreateConfigurationElement(persist); currentConfigurationElement->SetContributorId(contributorId); currentConfigurationElement->SetName(description.GetName()); QList descriptionProperties = description.GetAttributes(); QList properties; if (!descriptionProperties.empty()) { for (int i = 0; i < descriptionProperties.size(); i++) { properties.push_back(descriptionProperties[i].GetName()); properties.push_back(Translate(descriptionProperties[i].GetValue(), nullptr)); } } currentConfigurationElement->SetProperties(properties); QString value = description.GetValue(); if (!value.isEmpty()) currentConfigurationElement->SetValue(value); GetObjectManager()->Add(currentConfigurationElement, true); // process children QList children = description.GetChildren(); if (!children.empty()) { for (int i = 0; i < children.size(); i++) { CreateExtensionData(contributorId, children[i], currentConfigurationElement, persist); } } QList newValues = parent->GetRawChildren(); newValues.push_back(currentConfigurationElement->GetObjectId()); parent->SetRawChildren(newValues); currentConfigurationElement->SetParentId(parent->GetObjectId()); currentConfigurationElement->SetParentType(parent.Cast() ? RegistryObjectManager::CONFIGURATION_ELEMENT : RegistryObjectManager::EXTENSION); } bool ExtensionRegistry::RemoveObject(const SmartPointer& registryObject, bool isExtensionPoint, QObject* token) { if (!CheckReadWriteAccess(token, registryObject->ShouldPersist())) throw ctkInvalidArgumentException("Unauthorized access to the ExtensionRegistry.removeExtension() method. Check if proper access token is supplied."); int id = registryObject->GetObjectId(); QWriteLocker l(&access); eventDelta = CombinedEventDelta::RecordRemoval(); if (isExtensionPoint) { RemoveExtensionPoint(id); } else { RemoveExtension(id); } QHash removed; removed.insert(id, registryObject); // There is some asymmetry between extension and extension point removal. Removing extension point makes // extensions "orphans" but does not remove them. As a result, only extensions needs to be processed. if (!isExtensionPoint) { registryObjects->AddAssociatedObjects(removed, registryObject); } registryObjects->RemoveObjects(removed); registryObjects->AddNavigableObjects(removed); IObjectManager::Pointer manager = registryObjects->CreateDelegatingObjectManager(removed); //GetDelta(namespaze)->SetObjectManager(manager); //eventDelta->SetObjectManager(manager); registryObjects->UnlinkChildFromContributions(id); FireRegistryChangeEvent(); eventDelta.Reset(); return true; } void ExtensionRegistry::SetFileManager(const QString& /*cacheBase*/, bool /*isCacheReadOnly*/) { // if (cacheStorageManager != nullptr) // cacheStorageManager->Close(); // close existing file manager first // if (cacheBase != null) { // cacheStorageManager = new StorageManager(cacheBase, isCacheReadOnly ? "none" : null, isCacheReadOnly); //$NON-NLS-1$ // try { // cacheStorageManager.open(!isCacheReadOnly); // } catch (IOException e) { // // Ignore the exception. The registry will be rebuilt from source. // } // } } void ExtensionRegistry::EnterRead() { access.lockForRead(); } void ExtensionRegistry::ExitRead() { access.unlock(); } void ExtensionRegistry::SetElementFactory() { if (isMultiLanguage) { throw ctkRuntimeException("Multi-language registry not supported yet."); //theRegistryObjectFactory = new RegistryObjectFactoryMulti(this); } else { theRegistryObjectFactory.reset(new RegistryObjectFactory(this)); } } //TableReader ExtensionRegistry::getTableReader() const //{ // return theTableReader; //} bool ExtensionRegistry::CheckCache() { // for (int index = 0; index < strategy.getLocationsLength(); index++) { // File possibleCacheLocation = strategy.getStorage(index); // if (possibleCacheLocation == null) // break; // bail out on the first null // setFileManager(possibleCacheLocation, strategy.isCacheReadOnly(index)); // if (cacheStorageManager != null) { // // check this new location: // File cacheFile = null; // try { // cacheFile = cacheStorageManager.lookup(TableReader.getTestFileName(), false); // } catch (IOException e) { // //Ignore the exception. The registry will be rebuilt from the xml files. // } // if (cacheFile != null && cacheFile.isFile()) // return true; // found the appropriate location // } // } return false; } void ExtensionRegistry::StopChangeEventScheduler() { if (!eventThread.isNull()) { Queue::Locker l(&queue); eventThread->interrupt(); eventThread->wait(); eventThread.reset(); } } SmartPointer ExtensionRegistry::GetObjectManager() const { return registryObjects; } void ExtensionRegistry::AddListener(IRegistryEventListener* listener, const QString& extensionPointId) { AddListenerInternal(listener, extensionPointId.isEmpty() ? IExtensionPointFilter(nullptr) : IExtensionPointFilter(new SimpleExtensionPointFilter(extensionPointId))); } void ExtensionRegistry::AddListener(IRegistryEventListener* listener, const IExtensionPointFilter& filter) { this->AddListenerInternal(listener, filter); } QList > ExtensionRegistry::GetConfigurationElementsFor(const QString& extensionPointId) const { // this is just a convenience API - no need to do any sync'ing here int lastdot = extensionPointId.lastIndexOf('.'); if (lastdot == -1) { QList(); } return GetConfigurationElementsFor(extensionPointId.left(lastdot), extensionPointId.mid(lastdot + 1)); } QList > ExtensionRegistry::GetConfigurationElementsFor(const QString& pluginId, const QString& extensionPointSimpleId) const { // this is just a convenience API - no need to do any sync'ing here IExtensionPoint::Pointer extPoint = this->GetExtensionPoint(pluginId, extensionPointSimpleId); if (extPoint.IsNull()) return QList(); return extPoint->GetConfigurationElements(); } QList > ExtensionRegistry::GetConfigurationElementsFor(const QString& pluginId, const QString& extensionPointName, const QString& extensionId) const { // this is just a convenience API - no need to do any sync'ing here IExtension::Pointer extension = this->GetExtension(pluginId, extensionPointName, extensionId); if (extension.IsNull()) return QList(); return extension->GetConfigurationElements(); } SmartPointer ExtensionRegistry::GetExtension(const QString& extensionId) const { if (extensionId.isEmpty()) return IExtension::Pointer(); int lastdot = extensionId.lastIndexOf('.'); if (lastdot == -1) return IExtension::Pointer(); QString namespaze = extensionId.left(lastdot); QList extensions; { QReadLocker l(&access); extensions = registryObjects->GetExtensionsFromNamespace(namespaze); } for (int i = 0; i < extensions.size(); i++) { ExtensionHandle::Pointer suspect = extensions[i]; if (extensionId == suspect->GetUniqueIdentifier()) return suspect; } return IExtension::Pointer(); } SmartPointer ExtensionRegistry::GetExtension(const QString& extensionPointId, const QString& extensionId) const { // this is just a convenience API - no need to do any sync'ing here int lastdot = extensionPointId.lastIndexOf('.'); if (lastdot == -1) return IExtension::Pointer(); return GetExtension(extensionPointId.left(lastdot), extensionPointId.mid(lastdot + 1), extensionId); } SmartPointer ExtensionRegistry::GetExtension(const QString& pluginId, const QString& extensionPointName, const QString& extensionId) const { // this is just a convenience API - no need to do any sync'ing here IExtensionPoint::Pointer extPoint = GetExtensionPoint(pluginId, extensionPointName); if (extPoint.IsNotNull()) return extPoint->GetExtension(extensionId); return IExtension::Pointer(); } SmartPointer ExtensionRegistry::GetExtensionPoint(const QString& xptUniqueId) const { QReadLocker l(&access); return registryObjects->GetExtensionPointHandle(xptUniqueId); } SmartPointer ExtensionRegistry::GetExtensionPoint(const QString& elementName, const QString& xpt) const { QReadLocker l(&access); return registryObjects->GetExtensionPointHandle(elementName + '.' + xpt); } QList > ExtensionRegistry::GetExtensionPoints() const { QList handles; { QReadLocker l(&access); handles = registryObjects->GetExtensionPointsHandles(); } QList result; foreach(ExtensionPointHandle::Pointer handle, handles) { result.push_back(handle); } return result; } QList > ExtensionRegistry::GetExtensionPoints(const QString& namespaceName) const { QList handles; { QReadLocker l(&access); handles = registryObjects->GetExtensionPointsFromNamespace(namespaceName); } QList result; foreach(ExtensionPointHandle::Pointer handle, handles) { result.push_back(handle); } return result; } QList > ExtensionRegistry::GetExtensions(const QString& namespaceName) const { QList handles; { QReadLocker l(&access); handles = registryObjects->GetExtensionsFromNamespace(namespaceName); } QList result; foreach (ExtensionHandle::Pointer handle, handles) { result.push_back(handle); } return result; } QList > ExtensionRegistry::GetExtensions(const SmartPointer& contributor) const { RegistryContributor::Pointer regContributor = contributor.Cast(); if (regContributor.IsNull()) throw ctkInvalidArgumentException("Contributor must be a RegistryContributor."); // should never happen QString contributorId = regContributor->GetActualId(); QList handles; { QReadLocker l(&access); handles = registryObjects->GetExtensionsFromContributor(contributorId); } QList result; foreach (ExtensionHandle::Pointer handle, handles) { result.push_back(handle); } return result; } QList > ExtensionRegistry::GetExtensionPoints(const SmartPointer& contributor) const { RegistryContributor::Pointer regContributor = contributor.Cast(); if (regContributor.IsNull()) throw ctkInvalidArgumentException("Contributor must be a RegistryContributor."); // should never happen QString contributorId = regContributor->GetActualId(); QList handles; { QReadLocker l(&access); handles = registryObjects->GetExtensionPointsFromContributor(contributorId); } QList result; foreach (ExtensionPointHandle::Pointer handle, handles) { result.push_back(handle); } return result; } QList ExtensionRegistry::GetNamespaces() const { QReadLocker l(&access); QList namespaceElements = registryObjects->GetNamespacesIndex().Elements(); QList namespaceNames; for (int i = 0; i < namespaceElements.size(); i++) { namespaceNames.push_back(namespaceElements[i]->GetKey()); } return namespaceNames; } bool ExtensionRegistry::HasContributor(const SmartPointer& contributor) const { RegistryContributor::Pointer regContributor = contributor.Cast(); if (regContributor.IsNull()) throw ctkInvalidArgumentException("Contributor must be a RegistryContributor."); // should never happen QString contributorId = regContributor->GetActualId(); return HasContributor(contributorId); } bool ExtensionRegistry::HasContributor(const QString& contributorId) const { QReadLocker l(&access); return registryObjects->HasContribution(contributorId); } void ExtensionRegistry::Remove(const QString& removedContributorId, long timestamp) { Remove(removedContributorId); if (timestamp != 0) aggregatedTimestamp.Remove(timestamp); } void ExtensionRegistry::RemoveContributor(const SmartPointer& contributor, QObject* key) { RegistryContributor::Pointer regContributor = contributor.Cast(); if (regContributor.IsNull()) throw ctkInvalidArgumentException("Contributor must be a RegistryContributor."); // should never happen if (!CheckReadWriteAccess(key, true)) throw ctkInvalidArgumentException("Unauthorized access to the ExtensionRegistry.removeContributor() method. Check if proper access token is supplied."); QString contributorId = regContributor->GetActualId(); Remove(contributorId); } void ExtensionRegistry::Remove(const QString& removedContributorId) { QWriteLocker l(&access); eventDelta = CombinedEventDelta::RecordRemoval(); BasicRemove(removedContributorId); FireRegistryChangeEvent(); eventDelta.Reset(); } void ExtensionRegistry::RemoveListener(IRegistryEventListener* listener) { listeners.Remove(ListenerInfo(listener, IExtensionPointFilter(nullptr))); } ExtensionRegistry::ExtensionRegistry(RegistryStrategy* registryStrategy, QObject* masterToken, QObject* userToken) : registryObjects(nullptr), isMultiLanguage(false), mlErrorLogged(false), eventThread(nullptr) { isMultiLanguage = RegistryProperties::GetProperty(RegistryConstants::PROP_REGISTRY_MULTI_LANGUAGE) == "true"; if (registryStrategy != nullptr) strategy.reset(registryStrategy); else strategy.reset(new RegistryStrategy(QList(), QList(), nullptr)); this->masterToken = masterToken; this->userToken = userToken; registryObjects = new RegistryObjectManager(this); bool isRegistryFilledFromCache = false; // indicates if registry was able to use cache to populate it's content if (strategy->CacheUse()) { // Try to read the registry from the cache first. If that fails, create a new registry - QTime timer; + QElapsedTimer timer; if (Debug()) timer.start(); //The cache is made of several files, find the real names of these other files. If all files are found, try to initialize the objectManager if (CheckCache()) { // TODO Registry Cache // try { // theTableReader.setTableFile(cacheStorageManager.lookup(TableReader.TABLE, false)); // theTableReader.setExtraDataFile(cacheStorageManager.lookup(TableReader.EXTRA, false)); // theTableReader.setMainDataFile(cacheStorageManager.lookup(TableReader.MAIN, false)); // theTableReader.setContributionsFile(cacheStorageManager.lookup(TableReader.CONTRIBUTIONS, false)); // theTableReader.setContributorsFile(cacheStorageManager.lookup(TableReader.CONTRIBUTORS, false)); // theTableReader.setNamespacesFile(cacheStorageManager.lookup(TableReader.NAMESPACES, false)); // theTableReader.setOrphansFile(cacheStorageManager.lookup(TableReader.ORPHANS, false)); // long timestamp = strategy.getContributionsTimestamp(); // isRegistryFilledFromCache = registryObjects.init(timestamp); // if (isRegistryFilledFromCache) // aggregatedTimestamp.set(timestamp); // } catch (IOException e) { // // The registry will be rebuilt from the xml files. Make sure to clear anything filled // // from cache so that we won't have partially filled items. // isRegistryFilledFromCache = false; // clearRegistryCache(); // log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, 0, RegistryMessages.registry_bad_cache, e)); // } } // if (!isRegistryFilledFromCache) // { // // set cache storage manager to a first writable location // for (int index = 0; index < strategy.getLocationsLength(); index++) { // if (!strategy.isCacheReadOnly(index)) { // setFileManager(strategy.getStorage(index), false); // break; // } // } // } if (Debug() && isRegistryFilledFromCache) BERRY_INFO << "Reading registry cache: " << timer.elapsed() << "ms"; if (Debug()) { if (!isRegistryFilledFromCache) BERRY_INFO << "Reloading registry from manifest files..."; else BERRY_INFO << "Using registry cache..."; } } if (DebugEvents()) { struct DebugRegistryListener : public IRegistryEventListener { void Added(const QList& extensions) override { BERRY_INFO << "Registry extensions ADDED:"; foreach(IExtension::Pointer extension, extensions) { BERRY_INFO << "\t" << extension->GetExtensionPointUniqueIdentifier() << " - " << extension->GetNamespaceIdentifier() << "." << extension->GetSimpleIdentifier(); } } void Removed(const QList& extensions) override { BERRY_INFO << "Registry extensions REMOVED:"; foreach(IExtension::Pointer extension, extensions) { BERRY_INFO << "\t" << extension->GetExtensionPointUniqueIdentifier() << " - " << extension->GetNamespaceIdentifier() << "." << extension->GetSimpleIdentifier(); } } void Added(const QList& extensionPoints) override { BERRY_INFO << "Registry extension-points ADDED:"; foreach(IExtensionPoint::Pointer extensionPoint, extensionPoints) { BERRY_INFO << "\t" << extensionPoint->GetUniqueIdentifier(); } } void Removed(const QList& extensionPoints) override { BERRY_INFO << "Registry extension-points REMOVED:"; foreach(IExtensionPoint::Pointer extensionPoint, extensionPoints) { BERRY_INFO << "\t" << extensionPoint->GetUniqueIdentifier(); } } }; debugRegistryListener.reset(new DebugRegistryListener()); AddListener(debugRegistryListener.data()); } // Do extra start processing if specified in the registry strategy strategy->OnStart(this, isRegistryFilledFromCache); } ExtensionRegistry::~ExtensionRegistry() { } void ExtensionRegistry::Stop(QObject* /*key*/) { // If the registry creator specified a key token, check that the key mathches it // (it is assumed that registry owner keeps the key to prevent unautorized access). if (masterToken != nullptr && masterToken != nullptr) { throw ctkInvalidArgumentException("Unauthorized access to the ExtensionRegistry.stop() method. Check if proper access token is supplied."); //$NON-NLS-1$ } // Do extra stop processing if specified in the registry strategy strategy->OnStop(this); StopChangeEventScheduler(); // if (cacheStorageManager == nullptr) // return; // if (!registryObjects.isDirty() || cacheStorageManager.isReadOnly()) { // cacheStorageManager.close(); // theTableReader.close(); // return; // } // File tableFile = null; // File mainFile = null; // File extraFile = null; // File contributionsFile = null; // File contributorsFile = null; // File namespacesFile = null; // File orphansFile = null; // TableWriter theTableWriter = new TableWriter(this); // try { // cacheStorageManager.lookup(TableReader.TABLE, true); // cacheStorageManager.lookup(TableReader.MAIN, true); // cacheStorageManager.lookup(TableReader.EXTRA, true); // cacheStorageManager.lookup(TableReader.CONTRIBUTIONS, true); // cacheStorageManager.lookup(TableReader.CONTRIBUTORS, true); // cacheStorageManager.lookup(TableReader.NAMESPACES, true); // cacheStorageManager.lookup(TableReader.ORPHANS, true); // tableFile = File.createTempFile(TableReader.TABLE, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // mainFile = File.createTempFile(TableReader.MAIN, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // extraFile = File.createTempFile(TableReader.EXTRA, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // contributionsFile = File.createTempFile(TableReader.CONTRIBUTIONS, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // contributorsFile = File.createTempFile(TableReader.CONTRIBUTORS, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // namespacesFile = File.createTempFile(TableReader.NAMESPACES, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // orphansFile = File.createTempFile(TableReader.ORPHANS, ".new", cacheStorageManager.getBase()); //$NON-NLS-1$ // theTableWriter.setTableFile(tableFile); // theTableWriter.setExtraDataFile(extraFile); // theTableWriter.setMainDataFile(mainFile); // theTableWriter.setContributionsFile(contributionsFile); // theTableWriter.setContributorsFile(contributorsFile); // theTableWriter.setNamespacesFile(namespacesFile); // theTableWriter.setOrphansFile(orphansFile); // } catch (IOException e) { // cacheStorageManager.close(); // return; //Ignore the exception since we can recompute the cache // } // try { // long timestamp; // // A bit of backward compatibility: if registry was modified, but timestamp was not, // // it means that the new timestamp tracking mechanism was not used. In this case // // explicitly obtain timestamps for all contributions. Note that this logic // // maintains a problem described in the bug 104267 for contributions that // // don't use the timestamp tracking mechanism. // if (aggregatedTimestamp.isModifed()) // timestamp = aggregatedTimestamp.getContentsTimestamp(); // use timestamp tracking // else // timestamp = strategy.getContributionsTimestamp(); // use legacy approach // if (theTableWriter.saveCache(registryObjects, timestamp)) // cacheStorageManager.update(new QString[] {TableReader.TABLE, TableReader.MAIN, TableReader.EXTRA, TableReader.CONTRIBUTIONS, TableReader.CONTRIBUTORS, TableReader.NAMESPACES, TableReader.ORPHANS}, new QString[] {tableFile.getName(), mainFile.getName(), extraFile.getName(), contributionsFile.getName(), contributorsFile.getName(), namespacesFile.getName(), orphansFile.getName()}); // } catch (IOException e) { // //Ignore the exception since we can recompute the cache // } // theTableReader.close(); // cacheStorageManager.close(); } void ExtensionRegistry::ClearRegistryCache() { // QString[] keys = new QString[] {TableReader.TABLE, TableReader.MAIN, TableReader.EXTRA, TableReader.CONTRIBUTIONS, TableReader.ORPHANS}; // for (int i = 0; i < keys.length; i++) // try { // cacheStorageManager.remove(keys[i]); // } catch (IOException e) { // log(new Status(IStatus.ERROR, RegistryMessages.OWNER_NAME, IStatus.ERROR, RegistryMessages.meta_registryCacheReadProblems, e)); // } aggregatedTimestamp.Reset(); } RegistryObjectFactory* ExtensionRegistry::GetElementFactory() { if (theRegistryObjectFactory.isNull()) SetElementFactory(); return theRegistryObjectFactory.data(); } void ExtensionRegistry::Log(const SmartPointer& status) const { strategy->Log(status); } QString ExtensionRegistry::Translate(const QString& key, QTranslator* resources) const { if (isMultiLanguage) return key; return strategy->Translate(key, resources); } bool ExtensionRegistry::Debug() const { return strategy->Debug(); } bool ExtensionRegistry::DebugEvents() const { return strategy->DebugRegistryEvents(); } bool ExtensionRegistry::UseLazyCacheLoading() const { return strategy->CacheLazyLoading(); } long ExtensionRegistry::ComputeState() const { return strategy->GetContainerTimestamp(); } QObject* ExtensionRegistry::CreateExecutableExtension(const SmartPointer& defaultContributor, const QString& className, const QString& requestedContributorName) { return strategy->CreateExecutableExtension(defaultContributor, className, requestedContributorName); } void ExtensionRegistry::ProcessChangeEvent( const QList& listenerInfos, const CombinedEventDelta& scheduledDelta) { for (int i = 0; i < listenerInfos.size(); i++) { const ListenerInfo& listenerInfo = listenerInfos[i]; IRegistryEventListener* extensionListener = listenerInfo.listener; QList extensions = scheduledDelta.GetExtensions(listenerInfo.filter); QList extensionPoints = scheduledDelta.GetExtensionPoints(listenerInfo.filter); // notification order - on addition: extension points; then extensions if (scheduledDelta.IsAddition()) { if (!extensionPoints.empty()) extensionListener->Added(extensionPoints); if (!extensions.empty()) extensionListener->Added(extensions); } else { // on removal: extensions; then extension points if (!extensions.empty()) extensionListener->Removed(extensions); if (!extensionPoints.empty()) extensionListener->Removed(extensionPoints); } } IObjectManager::Pointer manager = scheduledDelta.GetObjectManager(); if (manager.IsNotNull()) manager->Close(); } void ExtensionRegistry::ScheduleChangeEvent(const QList& listenerInfos, const CombinedEventDelta& scheduledDelta) { QueueElement newElement(listenerInfos, scheduledDelta); if (eventThread.isNull()) { eventThread.reset(new RegistryEventThread(this, queue)); eventThread->start(); } { Queue::Locker l(&queue); queue.push_back(newElement); queue.notify(); } } bool ExtensionRegistry::AddContribution(QIODevice* is, const SmartPointer& contributor, bool persist, const QString& contributionName, QTranslator* translationBundle, QObject* key, long timestamp) { bool result = AddContribution(is, contributor, persist, contributionName, translationBundle, key); if (timestamp != 0) aggregatedTimestamp.Add(timestamp); return result; } bool ExtensionRegistry::AddContribution(QIODevice* is, const SmartPointer& contributor, bool persist, const QString& contributionName, QTranslator* translationBundle, QObject* key) { if (!CheckReadWriteAccess(key, persist)) throw ctkInvalidArgumentException("Unauthorized access to the ExtensionRegistry::AddContribution() method. Check if proper access token is supplied."); RegistryContributor::Pointer internalContributor = contributor.Cast(); registryObjects->AddContributor(internalContributor); // only adds a contributor if it is not already present QString ownerName = internalContributor->GetActualName(); QString message = QString("Problems parsing plug-in manifest for: \"%1\".").arg(ownerName); MultiStatus::Pointer problems(new MultiStatus(RegistryMessages::OWNER_NAME, ExtensionsParser::PARSE_PROBLEM, message, BERRY_STATUS_LOC)); ExtensionsParser parser(problems, this); RegistryContribution::Pointer contribution = GetElementFactory()->CreateContribution(internalContributor->GetActualId(), persist); try { QXmlInputSource xmlInput(is); bool success = parser.parseManifest(strategy->GetXMLParser(), &xmlInput, contributionName, GetObjectManager().GetPointer(), contribution, translationBundle); int status = problems->GetSeverity(); if (status != IStatus::OK_TYPE || !success) { Log(problems); if (status == IStatus::ERROR_TYPE || status == IStatus::CANCEL_TYPE || !success) return false; } } catch (const ctkException& e) { LogError(ownerName, contributionName, e); return false; } Add(contribution); // the add() method does synchronization return true; } bool ExtensionRegistry::AddExtensionPoint(const QString& identifier, const SmartPointer& contributor, bool persist, const QString& label, const QString& schemaReference, QObject* token) { if (!CheckReadWriteAccess(token, persist)) throw ctkInvalidArgumentException("Unauthorized access to the ExtensionRegistry::AddExtensionPoint() method. Check if proper access token is supplied."); RegistryContributor::Pointer internalContributor = contributor.Cast(); registryObjects->AddContributor(internalContributor); // only adds a contributor if it is not already present QString contributorId = internalContributor->GetActualId(); // Extension point Id might not be null if (identifier.isEmpty()) { QString message = QString("Missing ID for the extension point \"%1\". Element ignored.").arg(label); IStatus::Pointer status(new Status(IStatus::ERROR_TYPE, RegistryMessages::OWNER_NAME, 0, message, BERRY_STATUS_LOC)); Log(status); } // addition wraps in a contribution RegistryContribution::Pointer contribution = GetElementFactory()->CreateContribution(contributorId, persist); ExtensionPoint::Pointer currentExtPoint = GetElementFactory()->CreateExtensionPoint(persist); QString uniqueId; QString namespaceName; int simpleIdStart = identifier.lastIndexOf('.'); if (simpleIdStart == -1) { namespaceName = contribution->GetDefaultNamespace(); uniqueId = namespaceName + '.' + identifier; } else { namespaceName = identifier.left(simpleIdStart); uniqueId = identifier; } currentExtPoint->SetUniqueIdentifier(uniqueId); currentExtPoint->SetNamespace(namespaceName); QString labelNLS = Translate(label, nullptr); currentExtPoint->SetLabel(labelNLS); currentExtPoint->SetSchema(schemaReference); if (!GetObjectManager()->AddExtensionPoint(currentExtPoint, true)) { if (Debug()) { QString msg = QString("Ignored duplicate extension point \"%1\" supplied by \"%2\".").arg(uniqueId).arg(contribution->GetDefaultNamespace()); IStatus::Pointer status(new Status(IStatus::ERROR_TYPE, RegistryMessages::OWNER_NAME, 0, msg, BERRY_STATUS_LOC)); Log(status); } return false; } currentExtPoint->SetContributorId(contributorId); // array format: {Number of extension points, Number of extensions, Extension Id} QList contributionChildren; // Put the extension points into this namespace contributionChildren.push_back(1); contributionChildren.push_back(0); contributionChildren.push_back(currentExtPoint->GetObjectId()); contribution->SetRawChildren(contributionChildren); Add(contribution); return true; } bool ExtensionRegistry::AddExtension(const QString& identifier, const SmartPointer& contributor, bool persist, const QString& label, const QString& extensionPointId, const ConfigurationElementDescription& configurationElements, QObject* token) { if (!CheckReadWriteAccess(token, persist)) throw ctkInvalidArgumentException("Unauthorized access to the ExtensionRegistry::AddExtensionPoint() method. Check if proper access token is supplied."); // prepare namespace information RegistryContributor::Pointer internalContributor = contributor.Cast(); registryObjects->AddContributor(internalContributor); // only adds a contributor if it is not already present QString contributorId = internalContributor->GetActualId(); // addition wraps in a contribution RegistryContribution::Pointer contribution = GetElementFactory()->CreateContribution(contributorId, persist); Extension::Pointer currentExtension = GetElementFactory()->CreateExtension(persist); QString simpleId; QString namespaceName; int simpleIdStart = identifier.lastIndexOf('.'); if (simpleIdStart != -1) { simpleId = identifier.mid(simpleIdStart + 1); namespaceName = identifier.left(simpleIdStart); } else { simpleId = identifier; namespaceName = contribution->GetDefaultNamespace(); } currentExtension->SetSimpleIdentifier(simpleId); currentExtension->SetNamespaceIdentifier(namespaceName); QString extensionLabelNLS = Translate(label, nullptr); currentExtension->SetLabel(extensionLabelNLS); QString targetExtensionPointId; if (extensionPointId.indexOf('.') == -1) // No dots -> namespace name added at the start targetExtensionPointId = contribution->GetDefaultNamespace() + '.' + extensionPointId; else targetExtensionPointId = extensionPointId; currentExtension->SetExtensionPointIdentifier(targetExtensionPointId); // if we have an Id specified, check for duplicates. Only issue warning if duplicate found // as it might still work fine - depending on the access pattern. if (!simpleId.isNull() && Debug()) { QString uniqueId = namespaceName + '.' + simpleId; IExtension::Pointer existingExtension = GetExtension(uniqueId); if (existingExtension.IsNotNull()) { QString currentSupplier = contribution->GetDefaultNamespace(); QString existingSupplier = existingExtension->GetContributor()->GetName(); QString msg = QString("Extensions supplied by \"%1\" and \"%2\" have the same Id: \"%3\".") .arg(currentSupplier).arg(existingSupplier).arg(uniqueId); IStatus::Pointer status(new Status(IStatus::WARNING_TYPE, RegistryMessages::OWNER_NAME, 0, msg, BERRY_STATUS_LOC)); Log(status); return false; } } GetObjectManager()->Add(currentExtension, true); CreateExtensionData(contributorId, configurationElements, currentExtension, persist); currentExtension->SetContributorId(contributorId); QList contributionChildren; contributionChildren.push_back(0); contributionChildren.push_back(1); contributionChildren.push_back(currentExtension->GetObjectId()); contribution->SetRawChildren(contributionChildren); Add(contribution); return true; } bool ExtensionRegistry::RemoveExtension(const SmartPointer& extension, QObject* token) { ExtensionHandle::Pointer handle = extension.Cast(); if (handle.IsNull()) return false; return RemoveObject(handle->GetObject(), false, token); } bool ExtensionRegistry::RemoveExtensionPoint(const SmartPointer& extensionPoint, QObject* token) { ExtensionPointHandle::Pointer handle = extensionPoint.Cast(); if (handle.IsNull()) return false; return RemoveObject(handle->GetObject(), true, token); } QList > ExtensionRegistry::GetAllContributors() const { QList result; QReadLocker l(&access); foreach(RegistryContributor::Pointer contributor, registryObjects->GetContributors().values()) { result.push_back(contributor); } return result; } bool ExtensionRegistry::IsMultiLanguage() const { return isMultiLanguage; } QList ExtensionRegistry::Translate(const QList& nonTranslated, const SmartPointer& contributor, const QLocale& locale) const { return strategy->Translate(nonTranslated, contributor, locale); } QLocale ExtensionRegistry::GetLocale() const { return strategy->GetLocale(); } void ExtensionRegistry::LogMultiLangError() const { if (mlErrorLogged) // only log this error ones return; IStatus::Pointer status(new Status(IStatus::ERROR_TYPE, RegistryMessages::OWNER_NAME, 0, QString("The requested multi-language operation is not enabled. See runtime option \"") + RegistryConstants::PROP_REGISTRY_MULTI_LANGUAGE + "\".", ctkInvalidArgumentException(""), BERRY_STATUS_LOC)); Log(status); mlErrorLogged = true; } } diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionsParser.cpp b/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionsParser.cpp index 145430f5eb..39274c7718 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionsParser.cpp +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryExtensionsParser.cpp @@ -1,639 +1,639 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "berryExtensionsParser.h" #include "berryConfigurationElement.h" #include "berryExtension.h" #include "berryExtensionPoint.h" #include "berryExtensionRegistry.h" #include "berryIContributor.h" #include "berryIExtension.h" #include "berryLog.h" #include "berryMultiStatus.h" #include "berryRegistryContribution.h" #include "berryRegistryMessages.h" #include "berryRegistryObject.h" #include "berryRegistryObjectFactory.h" #include "berryRegistryObjectManager.h" -#include +#include namespace berry { long ExtensionsParser::cumulativeTime = 0; // Valid States const int ExtensionsParser::IGNORED_ELEMENT_STATE = 0; const int ExtensionsParser::INITIAL_STATE = 1; const int ExtensionsParser::PLUGIN_STATE = 2; const int ExtensionsParser::PLUGIN_EXTENSION_POINT_STATE = 5; const int ExtensionsParser::PLUGIN_EXTENSION_STATE = 6; const int ExtensionsParser::CONFIGURATION_ELEMENT_STATE = 10; const int ExtensionsParser::EXTENSION_POINT_INDEX = 0; const int ExtensionsParser::EXTENSION_INDEX = 1; const int ExtensionsParser::LAST_INDEX = 1; const int ExtensionsParser::PARSE_PROBLEM = 1; const QString ExtensionsParser::PLUGIN = "plugin"; const QString ExtensionsParser::PLUGIN_ID = "id"; const QString ExtensionsParser::PLUGIN_NAME = "name"; const QString ExtensionsParser::BUNDLE_UID = "id"; const QString ExtensionsParser::EXTENSION_POINT = "extension-point"; const QString ExtensionsParser::EXTENSION_POINT_NAME = "name"; const QString ExtensionsParser::EXTENSION_POINT_ID = "id"; const QString ExtensionsParser::EXTENSION_POINT_SCHEMA = "schema"; const QString ExtensionsParser::EXTENSION = "extension"; const QString ExtensionsParser::EXTENSION_NAME = "name"; const QString ExtensionsParser::EXTENSION_ID = "id"; const QString ExtensionsParser::EXTENSION_TARGET = "point"; const QString ExtensionsParser::ELEMENT = "element"; const QString ExtensionsParser::ELEMENT_NAME = "name"; const QString ExtensionsParser::ELEMENT_VALUE = "value"; const QString ExtensionsParser::PROPERTY = "property"; const QString ExtensionsParser::PROPERTY_NAME = "name"; const QString ExtensionsParser::PROPERTY_VALUE = "value"; ExtensionsParser::ExtensionsParser(const SmartPointer& status, ExtensionRegistry* registry) : locator(nullptr), extractNamespaces(true), status(status), registry(registry), resources(nullptr), objectManager(nullptr) { } void ExtensionsParser::setDocumentLocator(QXmlLocator* locator) { this->locator = locator; } bool ExtensionsParser::characters(const QString& ch) { int state = stateStack.back(); if (state != CONFIGURATION_ELEMENT_STATE) return true; if (state == CONFIGURATION_ELEMENT_STATE) { // Accept character data within an element, is when it is // part of a configuration element (i.e. an element within an EXTENSION element ConfigurationElement::Pointer currentConfigElement = objectStack.back().Cast(); if (configurationElementValue.isNull()) { if (!ch.trimmed().isEmpty()) { configurationElementValue = ch; } } else { configurationElementValue.append(ch); } if (!configurationElementValue.isEmpty()) currentConfigElement->SetValue(configurationElementValue); } return true; } bool ExtensionsParser::endElement(const QString& /*uri*/, const QString& elementName, const QString& /*qName*/) { switch (stateStack.back()) { case IGNORED_ELEMENT_STATE : { stateStack.pop(); return true; } case INITIAL_STATE : { // shouldn't get here internalError(QString("Element/end element mismatch for element \"%1\".").arg(elementName)); return false; } case PLUGIN_STATE : { stateStack.pop(); QList& extensionPoints = scratchVectors[EXTENSION_POINT_INDEX]; QList& extensions = scratchVectors[EXTENSION_INDEX]; QList namespaceChildren; namespaceChildren.push_back(0); namespaceChildren.push_back(0); // Put the extension points into this namespace if (extensionPoints.size() > 0) { namespaceChildren[RegistryContribution::EXTENSION_POINT] = extensionPoints.size(); for (int i = 0; i < extensionPoints.size(); ++i) { namespaceChildren.push_back(extensionPoints[i]->GetObjectId()); } extensionPoints.clear(); } // Put the extensions into this namespace too if (extensions.size() > 0) { namespaceChildren[RegistryContribution::EXTENSION] = extensions.size(); for (int i = 0; i < extensions.size(); ++i) { namespaceChildren.push_back(extensions[i]->GetObjectId()); } extensions.clear(); } contribution->SetRawChildren(namespaceChildren); return true; } case PLUGIN_EXTENSION_POINT_STATE : { if (elementName == EXTENSION_POINT) { stateStack.pop(); } return true; } case PLUGIN_EXTENSION_STATE : { if (elementName == EXTENSION) { stateStack.pop(); // Finish up extension object Extension::Pointer currentExtension = objectStack.pop().Cast(); if (currentExtension->GetNamespaceIdentifier().isEmpty()) currentExtension->SetNamespaceIdentifier(contribution->GetDefaultNamespace()); currentExtension->SetContributorId(contribution->GetContributorId()); scratchVectors[EXTENSION_INDEX].push_back(currentExtension); } return true; } case CONFIGURATION_ELEMENT_STATE : { // We don't care what the element name was stateStack.pop(); // Now finish up the configuration element object configurationElementValue.clear(); ConfigurationElement::Pointer currentConfigElement = objectStack.pop().Cast(); QString value = currentConfigElement->GetValueAsIs(); if (!value.isEmpty()) { currentConfigElement->SetValue(translate(value).trimmed()); } RegistryObject::Pointer parent = objectStack.back().Cast(); // Want to add this configuration element to the subelements of an extension QList newValues = parent->GetRawChildren(); newValues.push_back(currentConfigElement->GetObjectId()); parent->SetRawChildren(newValues); currentConfigElement->SetParentId(parent->GetObjectId()); currentConfigElement->SetParentType(parent.Cast() ? RegistryObjectManager::CONFIGURATION_ELEMENT : RegistryObjectManager::EXTENSION); return true; } default: // should never get here return false; } } bool ExtensionsParser::error(const QXmlParseException& ex) { logStatus(ex); return true; } bool ExtensionsParser::fatalError(const QXmlParseException& ex) { cleanup(); logStatus(ex); return false; } bool ExtensionsParser::parseManifest(QXmlReader* reader, QXmlInputSource* in, const QString& manifestName, RegistryObjectManager* registryObjects, const SmartPointer& currentNamespace, QTranslator* translator) { - QTime start; + QElapsedTimer timer; this->resources = translator; this->objectManager = registryObjects; //initialize the parser with this object this->contribution = currentNamespace; if (registry->Debug()) - start.start(); + timer.start(); if (reader == nullptr) { - cumulativeTime += start.elapsed(); + cumulativeTime += timer.elapsed(); throw ctkInvalidArgumentException("XML Reader not available"); } locationName = manifestName; reader->setContentHandler(this); reader->setDeclHandler(this); reader->setDTDHandler(this); reader->setEntityResolver(this); reader->setErrorHandler(this); reader->setLexicalHandler(this); bool success = reader->parse(in); if (registry->Debug()) { - cumulativeTime += start.elapsed(); + cumulativeTime += timer.elapsed(); BERRY_INFO << "Cumulative parse time so far : " << cumulativeTime; } return success; } bool ExtensionsParser::startDocument() { stateStack.push(INITIAL_STATE); for (int i = 0; i <= LAST_INDEX; i++) { scratchVectors[i].clear(); } return true; } bool ExtensionsParser::startElement(const QString& /*uri*/, const QString& elementName, const QString& /*qName*/, const QXmlAttributes& attributes) { switch (stateStack.back()) { case INITIAL_STATE : handleInitialState(elementName, attributes); break; case PLUGIN_STATE : handlePluginState(elementName, attributes); break; case PLUGIN_EXTENSION_POINT_STATE : handleExtensionPointState(elementName); break; case PLUGIN_EXTENSION_STATE : case CONFIGURATION_ELEMENT_STATE : handleExtensionState(elementName, attributes); break; default : stateStack.push(IGNORED_ELEMENT_STATE); internalError(QString("Unknown element \"%1\", found at the top level, ignored.").arg(elementName)); } return true; } bool ExtensionsParser::warning(const QXmlParseException& ex) { logStatus(ex); return true; } void ExtensionsParser::error(const SmartPointer& error) { status->Add(error); } void ExtensionsParser::cleanup() { foreach (RegistryObject::Pointer object, addedRegistryObjects) { if (ExtensionPoint::Pointer extPoint = object.Cast()) { QString id = extPoint->GetUniqueIdentifier(); objectManager->RemoveExtensionPoint(id); } else { objectManager->Remove(object->GetObjectId(), true); } } } void ExtensionsParser::handleExtensionPointState(const QString& elementName) { // We ignore all elements under extension points (if there are any) stateStack.push(IGNORED_ELEMENT_STATE); unknownElement(EXTENSION_POINT, elementName); } void ExtensionsParser::handleExtensionState(const QString& elementName, const QXmlAttributes& attributes) { // You need to change the state here even though we will be executing the same // code for ExtensionState and ConfigurationElementState. We ignore the name // of the element for ConfigurationElements. When we are wrapping up, we will // want to add each configuration element object to the subElements vector of // its parent configuration element object. However, the first configuration // element object we created (the last one we pop off the stack) will need to // be added to a vector in the extension object called _configuration. stateStack.push(CONFIGURATION_ELEMENT_STATE); configurationElementValue.clear(); // create a new Configuration Element and push it onto the object stack ConfigurationElement::Pointer currentConfigurationElement = registry->GetElementFactory()->CreateConfigurationElement(contribution->ShouldPersist()); currentConfigurationElement->SetContributorId(contribution->GetContributorId()); objectStack.push(currentConfigurationElement); currentConfigurationElement->SetName(elementName); // Processing the attributes of a configuration element involves creating // a new configuration property for each attribute and populating the configuration // property with the name/value pair of the attribute. Note there will be one // configuration property for each attribute parseConfigurationElementAttributes(attributes); objectManager->Add(currentConfigurationElement, true); addedRegistryObjects.push_back(currentConfigurationElement); } void ExtensionsParser::handleInitialState(const QString& /*elementName*/, const QXmlAttributes& /*attributes*/) { // new manifests should have the plugin (or fragment) element empty stateStack.push(PLUGIN_STATE); objectStack.push(contribution); } void ExtensionsParser::handlePluginState(const QString& elementName, const QXmlAttributes& attributes) { if (elementName == EXTENSION_POINT) { stateStack.push(PLUGIN_EXTENSION_POINT_STATE); parseExtensionPointAttributes(attributes); return; } if (elementName == EXTENSION) { stateStack.push(PLUGIN_EXTENSION_STATE); parseExtensionAttributes(attributes); return; } // If we get to this point, the element name is one we don't currently accept. // Set the state to indicate that this element will be ignored stateStack.push(IGNORED_ELEMENT_STATE); unknownElement(PLUGIN, elementName); } void ExtensionsParser::logStatus(const QXmlParseException& ex) { QString name = ex.systemId(); if (name.isEmpty()) name = locationName; if (!name.isEmpty()) name = name.mid(1 + name.lastIndexOf("/")); QString msg; if (name.isEmpty()) msg = QString("Parsing error: \"%1\"").arg(ex.message()); else msg = QString("Parsing error in \"%1\" [line %2, column %3]: \"%4\".").arg(name) .arg(ex.lineNumber()).arg(ex.columnNumber()).arg(ex.message()); IStatus::Pointer status(new Status(IStatus::WARNING_TYPE, RegistryMessages::OWNER_NAME, PARSE_PROBLEM, msg, BERRY_STATUS_LOC)); error(status); } void ExtensionsParser::parseConfigurationElementAttributes(const QXmlAttributes& attributes) { ConfigurationElement::Pointer parentConfigurationElement = objectStack.back().Cast(); // process attributes int len = attributes.length(); if (len == 0) { parentConfigurationElement->SetProperties(QList()); return; } QList properties; for (int i = 0; i < len; i++) { properties.push_back(attributes.localName(i)); properties.push_back(translate(attributes.value(i))); } parentConfigurationElement->SetProperties(properties); } void ExtensionsParser::parseExtensionAttributes(const QXmlAttributes& attributes) { Extension::Pointer currentExtension = registry->GetElementFactory()->CreateExtension(contribution->ShouldPersist()); objectStack.push(currentExtension); QString simpleId; QString namespaceName; // Process Attributes int len = attributes.length(); for (int i = 0; i < len; i++) { QString attrName = attributes.localName(i); QString attrValue = attributes.value(i).trimmed(); if (attrName == EXTENSION_NAME) currentExtension->SetLabel(translate(attrValue)); else if (attrName == EXTENSION_ID) { int simpleIdStart = attrValue.lastIndexOf('.'); if ((simpleIdStart != -1) && extractNamespaces) { simpleId = attrValue.mid(simpleIdStart + 1); namespaceName = attrValue.left(simpleIdStart); } else { simpleId = attrValue; namespaceName = contribution->GetDefaultNamespace(); } currentExtension->SetSimpleIdentifier(simpleId); currentExtension->SetNamespaceIdentifier(namespaceName); } else if (attrName == EXTENSION_TARGET) { // check if point is specified as a simple or qualified name QString targetName; if (attrValue.lastIndexOf('.') == -1) { QString baseId = contribution->GetDefaultNamespace(); targetName = baseId + '.' + attrValue; } else { targetName = attrValue; } currentExtension->SetExtensionPointIdentifier(targetName); } else { unknownAttribute(attrName, EXTENSION); } } if (currentExtension->GetExtensionPointIdentifier().isEmpty()) { missingAttribute(EXTENSION_TARGET, EXTENSION); stateStack.pop(); stateStack.push(IGNORED_ELEMENT_STATE); objectStack.pop(); return; } // if we have an Id specified, check for duplicates. Only issue warning (not error) if duplicate found // as it might still work fine - depending on the access pattern. if (!simpleId.isEmpty() && registry->Debug()) { QString uniqueId = namespaceName + '.' + simpleId; IExtension::Pointer existingExtension = registry->GetExtension(uniqueId); if (existingExtension.IsNotNull()) { QString currentSupplier = contribution->GetDefaultNamespace(); QString existingSupplier = existingExtension->GetContributor()->GetName(); QString msg = QString("Extensions supplied by \"%1\" and \"%2\" have the same Id: \"%3\".") .arg(currentSupplier).arg(existingSupplier).arg(uniqueId); IStatus::Pointer status(new Status(IStatus::WARNING_TYPE, RegistryMessages::OWNER_NAME, 0, msg, BERRY_STATUS_LOC)); registry->Log(status); } else if (!processedExtensionIds.isEmpty()) { // check elements in this contribution foreach (QString processedId, processedExtensionIds) { if (uniqueId == processedId) { QString currentSupplier = contribution->GetDefaultNamespace(); QString existingSupplier = currentSupplier; QString msg = QString("Extensions supplied by \"%1\" and \"%2\" have the same Id: \"%3\".") .arg(currentSupplier).arg(existingSupplier).arg(uniqueId); IStatus::Pointer status(new Status(IStatus::WARNING_TYPE, RegistryMessages::OWNER_NAME, 0, msg, BERRY_STATUS_LOC)); registry->Log(status); break; } } } processedExtensionIds.push_back(uniqueId); } objectManager->Add(currentExtension, true); addedRegistryObjects.push_back(currentExtension); } void ExtensionsParser::missingAttribute(const QString& attribute, const QString& element) { if (locator == nullptr) internalError(QString("Missing \"%1\" attribute in \"%2\" element. Element ignored.").arg(attribute).arg(element)); else internalError(QString("Missing \"%1\" attribute in \"%2\" element (line: %3). Element ignored.") .arg(attribute).arg(element).arg(locator->lineNumber())); } void ExtensionsParser::unknownAttribute(const QString& attribute, const QString& element) { if (locator == nullptr) internalError(QString("Unknown attribute \"%1\" for element \"%2\" ignored.").arg(attribute).arg(element)); else internalError(QString("Unknown attribute \"%1\" for element \"%2\" ignored (line: %3).") .arg(attribute).arg(element).arg(locator->lineNumber())); } void ExtensionsParser::unknownElement(const QString& parent, const QString& element) { if (locator == nullptr) internalError(QString("Unknown element \"%1\", found within a \"%2\", ignored.").arg(element).arg(parent)); else internalError(QString("Unknown element \"%1\", found within a \"%2\", ignored (line: %3).") .arg(element).arg(parent).arg(locator->lineNumber())); } void ExtensionsParser::parseExtensionPointAttributes(const QXmlAttributes& attributes) { ExtensionPoint::Pointer currentExtPoint = registry->GetElementFactory()->CreateExtensionPoint(contribution->ShouldPersist()); // Process Attributes int len = attributes.length(); for (int i = 0; i < len; i++) { QString attrName = attributes.localName(i); QString attrValue = attributes.value(i).trimmed(); if (attrName == EXTENSION_POINT_NAME) currentExtPoint->SetLabel(translate(attrValue)); else if (attrName == EXTENSION_POINT_ID) { QString uniqueId; QString namespaceName; int simpleIdStart = attrValue.lastIndexOf('.'); if (simpleIdStart != -1 && extractNamespaces) { namespaceName = attrValue.left(simpleIdStart); uniqueId = attrValue; } else { namespaceName = contribution->GetDefaultNamespace(); uniqueId = namespaceName + '.' + attrValue; } currentExtPoint->SetUniqueIdentifier(uniqueId); currentExtPoint->SetNamespace(namespaceName); } else if (attrName == EXTENSION_POINT_SCHEMA) currentExtPoint->SetSchema(attrValue); else unknownAttribute(attrName, EXTENSION_POINT); } if (currentExtPoint->GetSimpleIdentifier().isEmpty() || currentExtPoint->GetLabel().isEmpty()) { QString attribute = currentExtPoint->GetSimpleIdentifier().isEmpty() ? EXTENSION_POINT_ID : EXTENSION_POINT_NAME; missingAttribute(attribute, EXTENSION_POINT); stateStack.pop(); stateStack.push(IGNORED_ELEMENT_STATE); return; } if (!objectManager->AddExtensionPoint(currentExtPoint, true)) { // avoid adding extension point second time as it might cause // extensions associated with the existing extension point to // become inaccessible. if (registry->Debug()) { QString msg = QString("Ignored duplicate extension point \"%1\" supplied by \"%2\".") .arg(currentExtPoint->GetUniqueIdentifier()).arg(contribution->GetDefaultNamespace()); IStatus::Pointer status(new Status(IStatus::ERROR_TYPE, RegistryMessages::OWNER_NAME, 0, msg, BERRY_STATUS_LOC)); registry->Log(status); } stateStack.pop(); stateStack.push(IGNORED_ELEMENT_STATE); return; } if (currentExtPoint->GetNamespace().isEmpty()) currentExtPoint->SetNamespace(contribution->GetDefaultNamespace()); currentExtPoint->SetContributorId(contribution->GetContributorId()); addedRegistryObjects.push_back(currentExtPoint); // Now populate the the vector just below us on the objectStack with this extension point scratchVectors[EXTENSION_POINT_INDEX].push_back(currentExtPoint); } void ExtensionsParser::internalError(const QString& message) { IStatus::Pointer status(new Status(IStatus::WARNING_TYPE, RegistryMessages::OWNER_NAME, PARSE_PROBLEM, message, BERRY_STATUS_LOC)); error(status); } QString ExtensionsParser::translate(const QString& key) const { return registry->Translate(key, resources); } } diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryStrategy.cpp b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryStrategy.cpp index 663db3296c..ec4eb443af 100644 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryStrategy.cpp +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryRegistryStrategy.cpp @@ -1,269 +1,269 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "berryRegistryStrategy.h" #include "berryCoreException.h" #include "berryCTKPluginListener.h" #include "berryExtensionRegistry.h" #include "berryExtensionType.h" #include "berryRegistryConstants.h" #include "berryRegistryContributor.h" #include "berryRegistryMessages.h" #include "berryRegistrySupport.h" #include "berryStatus.h" #include "berryLog.h" #include "berryCTKPluginActivator.h" #include "berryCTKPluginUtils.h" #include #include #include #include #include #include namespace berry { RegistryStrategy::RegistryStrategy(const QList& storageDirs, const QList& cacheReadOnly, QObject* key) : storageDirs(storageDirs), cacheReadOnly(cacheReadOnly), token(key), trackTimestamp(false) { // Only do timestamp calculations if osgi.checkConfiguration is set to "true" (typically, // this implies -dev mode) ctkPluginContext* context = org_blueberry_core_runtime_Activator::getPluginContext(); if (context) { trackTimestamp = context->getProperty(RegistryConstants::PROP_CHECK_CONFIG).toString().compare("true", Qt::CaseInsensitive) == 0; } } RegistryStrategy::~RegistryStrategy() { } int RegistryStrategy::GetLocationsLength() const { return storageDirs.size(); } QString RegistryStrategy::GetStorage(int index) const { return storageDirs[index]; } bool RegistryStrategy::IsCacheReadOnly(int index) const { if (!cacheReadOnly.empty()) return cacheReadOnly[index]; return true; } void RegistryStrategy::Log(const SmartPointer& status) { RegistrySupport::Log(status, QString()); } QString RegistryStrategy::Translate(const QString& key, QTranslator* resources) { return RegistrySupport::Translate(key, resources); } void RegistryStrategy::OnStart(IExtensionRegistry* reg, bool loadedFromCache) { ExtensionRegistry* registry = dynamic_cast(reg); if (registry == nullptr) return; // register a listener to catch new plugin installations/resolutions. pluginListener.reset(new CTKPluginListener(registry, token, this)); org_blueberry_core_runtime_Activator::getPluginContext()->connectPluginListener( pluginListener.data(), SLOT(PluginChanged(ctkPluginEvent)), Qt::DirectConnection); // populate the registry with all the currently installed plugins. // There is a small window here while ProcessPlugins is being // called where the pluginListener may receive a ctkPluginEvent // to add/remove a plugin from the registry. This is ok since // the registry is a synchronized object and will not add the // same bundle twice. if (!loadedFromCache) pluginListener->ProcessPlugins(org_blueberry_core_runtime_Activator::getPluginContext()->getPlugins()); } void RegistryStrategy::OnStop(IExtensionRegistry* /*registry*/) { if (!pluginListener.isNull()) { org_blueberry_core_runtime_Activator::getPluginContext()->disconnectPluginListener(pluginListener.data()); } } QObject* RegistryStrategy::CreateExecutableExtension(const SmartPointer& contributor, const QString& className, const QString& /*overridenContributorName*/) { QObject* result = nullptr; QSharedPointer plugin = CTKPluginUtils::GetDefault()->GetPlugin(contributor->GetName()); if (!plugin.isNull()) { // immediately start the plugin but do not change the plugins autostart setting plugin->start(ctkPlugin::START_TRANSIENT); } else { QString message = QString("Unable to find plugin \"%1\" for contributor \"%2\".") .arg(contributor->GetName()).arg(contributor->GetActualName()); IStatus::Pointer status(new Status(IStatus::ERROR_TYPE, RegistryMessages::OWNER_NAME, RegistryConstants::PLUGIN_ERROR, message, BERRY_STATUS_LOC)); throw CoreException(status); } //QString typeName = contributor->GetActualName() + "_" + className; QString typeName = className; int extensionTypeId = ExtensionType::type(typeName.toLatin1().data()); if (extensionTypeId == 0) { QString message = QString("Unable to find class \"%1\" from contributor \"%2\"." " The class was either not registered via " "BERRY_REGISTER_EXTENSION_CLASS(type, pluginContext) " "or you forgot to run Qt's moc on the header file.") .arg(className).arg(contributor->GetActualName()); IStatus::Pointer status(new Status(IStatus::ERROR_TYPE, RegistryMessages::OWNER_NAME, RegistryConstants::PLUGIN_ERROR, message, BERRY_STATUS_LOC)); throw CoreException(status); } else { try { result = ExtensionType::construct(extensionTypeId); } catch (const ctkException& e) { QString message = QString("Contributor \"%1\" was unable to instantiate class \"%2\".") .arg(contributor->GetActualName()).arg(className); IStatus::Pointer status(new Status(IStatus::ERROR_TYPE, RegistryMessages::OWNER_NAME, RegistryConstants::PLUGIN_ERROR, message, e, BERRY_STATUS_LOC)); throw CoreException(status); } catch (const std::exception& e) { QString message = QString("Contributor \"%1\" was unable to instantiate class \"%2\". Error: \"%3\"") .arg(contributor->GetActualName()).arg(className).arg(QString(e.what())); IStatus::Pointer status(new Status(IStatus::ERROR_TYPE, RegistryMessages::OWNER_NAME, RegistryConstants::PLUGIN_ERROR, message, BERRY_STATUS_LOC)); throw CoreException(status); } } return result; } //void RegistryStrategy::ScheduleChangeEvent(const QList& listeners, // const QHash& deltas, // IExtensionRegistry* registry) //{ // if (ExtensionRegistry* extRegistry = dynamic_cast(registry)) // extRegistry->ScheduleChangeEvent(listeners, deltas); //} //SmartPointer RegistryStrategy::ProcessChangeEvent(const QList& listeners, // const QHash& deltas, // IExtensionRegistry* registry) //{ // if (ExtensionRegistry* extRegistry = dynamic_cast(registry)) // return extRegistry->ProcessChangeEvent(listeners, deltas); // return IStatus::Pointer(); //} bool RegistryStrategy::Debug() const { return false; } bool RegistryStrategy::DebugRegistryEvents() const { return false; } bool RegistryStrategy::CacheUse() const { return true; } bool RegistryStrategy::CacheLazyLoading() const { return true; } long RegistryStrategy::GetContainerTimestamp() const { return 0; } long RegistryStrategy::GetContributionsTimestamp() const { return 0; } bool RegistryStrategy::CheckContributionsTimestamp() const { return trackTimestamp; } long RegistryStrategy::GetExtendedTimestamp(const QSharedPointer& plugin, const QString& pluginManifest) const { if (pluginManifest.isEmpty()) return 0; // The plugin manifest does not have a timestamp as it is embedded into // the plugin itself. Try to get the timestamp of the plugin instead. QFileInfo pluginInfo(QUrl(plugin->getLocation()).toLocalFile()); if (pluginInfo.exists()) { - return ctk::msecsTo(QDateTime::fromTime_t(0), pluginInfo.lastModified()) + plugin->getPluginId(); + return ctk::msecsTo(QDateTime::fromSecsSinceEpoch(0), pluginInfo.lastModified()) + plugin->getPluginId(); //return pluginManifest.openConnection().getLastModified() + bundle.getBundleId(); } else { if (Debug()) { BERRY_DEBUG << "Unable to obtain timestamp for the plugin " << plugin->getSymbolicName(); } return 0; } } QXmlReader* RegistryStrategy::GetXMLParser() const { if (theXMLParser.isNull()) { theXMLParser.reset(new QXmlSimpleReader()); } return theXMLParser.data(); } QList RegistryStrategy::Translate(const QList& nonTranslated, const SmartPointer& /*contributor*/, const QLocale& /*locale*/) { return nonTranslated; } QLocale RegistryStrategy::GetLocale() const { return QLocale(); } } diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryHandlerAuthority.cpp b/Plugins/org.blueberry.ui.qt/src/internal/berryHandlerAuthority.cpp index c5d902ecfb..8fbbb5b273 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryHandlerAuthority.cpp +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryHandlerAuthority.cpp @@ -1,505 +1,505 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #include "berryHandlerAuthority.h" #include "berryISources.h" #include "berryIServiceLocator.h" #include "berryIEvaluationService.h" #include "berryIEvaluationContext.h" #include "berryIEvaluationReference.h" #include "berryICommandService.h" #include "berryIHandler.h" #include "berryISourceProvider.h" #include "services/berryISourceProviderService.h" #include "berryObjects.h" #include "berryHandlerActivation.h" #include "berryMultiStatus.h" #include "berryPlatformUI.h" #include "berryWorkbenchPlugin.h" #include "berryCommandTracing.h" #include "berryCommand.h" #include "berryEvaluationContext.h" #include "berryExpression.h" #include namespace berry { bool HandlerAuthority::DEBUG = false; // = Policy.DEBUG_HANDLERS; bool HandlerAuthority::DEBUG_PERFORMANCE = false; // = Policy.DEBUG_HANDLERS_PERFORMANCE; bool HandlerAuthority::DEBUG_VERBOSE = false; // = Policy.DEBUG_HANDLERS && Policy.DEBUG_HANDLERS_VERBOSE; QString HandlerAuthority::DEBUG_VERBOSE_COMMAND_ID; // = Policy.DEBUG_HANDLERS_VERBOSE_COMMAND_ID; const QString HandlerAuthority::TRACING_COMPONENT = "HANDLERS"; const QList HandlerAuthority::SELECTION_VARIABLES = QList() << ISources::ACTIVE_CURRENT_SELECTION_NAME() << ISources::ACTIVE_FOCUS_CONTROL_ID_NAME() << ISources::ACTIVE_FOCUS_CONTROL_NAME() << ISources::ACTIVE_MENU_EDITOR_INPUT_NAME() << ISources::ACTIVE_MENU_NAME() << ISources::ACTIVE_MENU_SELECTION_NAME(); class HandlerAuthority::HandlerPropertyListener : public IPropertyChangeListener { private: HandlerAuthority* authority; HandlerActivation::Pointer handler; public: HandlerPropertyListener(HandlerAuthority* authority, const HandlerActivation::Pointer& activation) : authority(authority) , handler(activation) { handler->SetListener(this); } using IPropertyChangeListener::PropertyChange; void PropertyChange(const PropertyChangeEvent::Pointer& event) override { if (handler->GetCommandId() == event->GetProperty()) { bool val = false; if (ObjectBool::Pointer boolObj = event->GetNewValue().Cast()) { val = boolObj->GetValue(); } handler->SetResult(val); authority->changedCommandIds.insert(handler->GetCommandId()); } } }; IEvaluationService* HandlerAuthority::GetEvaluationService() const { if (evalService == nullptr) { evalService = locator->GetService(); evalService->AddServiceListener(GetServiceListener()); } return evalService; } IPropertyChangeListener* HandlerAuthority::GetServiceListener() const { return const_cast(this); } void HandlerAuthority::PropertyChange(const PropertyChangeEvent::Pointer& event) { if (IEvaluationService::PROP_NOTIFYING == event->GetProperty()) { if (ObjectBool::Pointer boolObj = event->GetNewValue().Cast()) { bool startNotifying = boolObj->GetValue(); if (startNotifying) { changedCommandIds.clear(); } else { ProcessChangedCommands(); } } } } HandlerAuthority::HandlerAuthority(ICommandService* commandService, IServiceLocator* locator) : commandService(commandService) , locator(locator) , evalService(nullptr) { if (commandService == nullptr) { throw ctkInvalidArgumentException("The handler authority needs a command service"); } } HandlerAuthority::~HandlerAuthority() { GetEvaluationService()->RemoveServiceListener(GetServiceListener()); } void HandlerAuthority::ActivateHandler(const SmartPointer& activation) { const HandlerActivation::Pointer handler = activation.Cast(); // First we update the handlerActivationsByCommandId map. const QString commandId = handler->GetCommandId(); MultiStatus::Pointer conflicts( new MultiStatus(PlatformUI::PLUGIN_ID(), 0, "A handler conflict occurred. This may disable some commands.", BERRY_STATUS_LOC) ); IdToHandlerActivationMap::mapped_type& handlerActivations = handlerActivationsByCommandId[commandId]; handlerActivations.insert(handler, Empty()); if (handler->GetExpression().IsNotNull()) { auto l = new HandlerPropertyListener(this, handler); handler->SetReference(GetEvaluationService()->AddEvaluationListener( handler->GetExpression(), l, handler->GetCommandId())); } if (handlerActivations.size() > 1) { UpdateCommand(commandId, ResolveConflicts(commandId, handlerActivations, conflicts)); } else { UpdateCommand(commandId, (Evaluate(handler) ? handler : HandlerActivation::Pointer(nullptr))); } if (conflicts->GetSeverity() != IStatus::OK_TYPE) { WorkbenchPlugin::Log(conflicts); } } void HandlerAuthority::DeactivateHandler(const SmartPointer& activation) { const HandlerActivation::Pointer handler = activation.Cast(); // First we update the handlerActivationsByCommandId map. const QString commandId = handler->GetCommandId(); MultiStatus::Pointer conflicts( new MultiStatus("org.blueberry.ui", 0, "A handler conflict occurred. This may disable some commands.", BERRY_STATUS_LOC)); IdToHandlerActivationMap::iterator value = handlerActivationsByCommandId.find(commandId); if (value != handlerActivationsByCommandId.end()) { IdToHandlerActivationMap::mapped_type& handlerActivations = value.value(); if (handlerActivations.remove(handler) > 0) { if (handler->GetReference().IsNotNull()) { GetEvaluationService()->RemoveEvaluationListener(handler->GetReference()); handler->SetReference(IEvaluationReference::Pointer(nullptr)); handler->SetListener(nullptr); } if (handlerActivations.isEmpty()) { handlerActivationsByCommandId.remove(commandId); UpdateCommand(commandId, IHandlerActivation::Pointer(nullptr)); } else if (handlerActivations.size() == 1) { IHandlerActivation::Pointer remainingActivation = handlerActivations.begin().key(); UpdateCommand(commandId, (Evaluate(remainingActivation) ? remainingActivation : IHandlerActivation::Pointer(nullptr))); } else { UpdateCommand(commandId, ResolveConflicts(commandId, handlerActivations, conflicts)); } } } if (conflicts->GetSeverity() != IStatus::OK_TYPE) { WorkbenchPlugin::Log(conflicts); } } SmartPointer HandlerAuthority::ResolveConflicts( const QString& commandId, const QMap,Empty>& activations, SmartPointer conflicts) { // If we don't have any, then there is no match. if (activations.isEmpty()) { return IHandlerActivation::Pointer(nullptr); } // Cycle over the activations, remembered the current best. QMapIterator activationItr(activations); HandlerActivation::Pointer bestActivation; HandlerActivation::Pointer currentActivation; bool conflict = false; while (activationItr.hasNext()) { currentActivation = activationItr.next().key(); if (!Evaluate(currentActivation)) { continue; // only consider potentially active handlers } // Check to see if we haven't found a potentially active handler yet if ((DEBUG_VERBOSE) && ((DEBUG_VERBOSE_COMMAND_ID.isNull()) || (DEBUG_VERBOSE_COMMAND_ID == commandId))) { CommandTracing::PrintTrace(TRACING_COMPONENT, " resolveConflicts: eval: " + currentActivation->ToString()); } if (bestActivation.IsNull()) { bestActivation = currentActivation; conflict = false; continue; } // Compare the two handlers. int comparison = bestActivation->CompareTo(currentActivation.GetPointer()); if (comparison < 0) { bestActivation = currentActivation; conflict = false; } else if (comparison == 0) { if (currentActivation->GetHandler() != bestActivation->GetHandler()) { conflict = true; break; } } else { break; } } // If we are logging information, now is the time to do it. if (DEBUG) { if (conflict) { CommandTracing::PrintTrace(TRACING_COMPONENT, "Unresolved conflict detected for '" + commandId + '\''); } else if ((bestActivation.IsNotNull()) && (DEBUG_VERBOSE) && ((DEBUG_VERBOSE_COMMAND_ID.isNull()) || (DEBUG_VERBOSE_COMMAND_ID == commandId))) { CommandTracing::PrintTrace(TRACING_COMPONENT, "Resolved conflict detected. The following activation won: "); CommandTracing::PrintTrace(TRACING_COMPONENT, " " + bestActivation->ToString()); } } // Return the current best. if (conflict) { if (!previousLogs.contains(commandId)) { previousLogs.insert(commandId); QString str; QDebug dbg(&str); dbg << "Conflict for" << commandId << ":"; dbg << bestActivation->ToString(); dbg << currentActivation->ToString(); IStatus::Pointer s(new Status(IStatus::WARNING_TYPE, "org.blueberry.ui", str, BERRY_STATUS_LOC)); conflicts->Add(s); } return IHandlerActivation::Pointer(nullptr); } return bestActivation; } void HandlerAuthority::UpdateCommand(const QString& commandId, const SmartPointer& activation) { const Command::Pointer command = commandService->GetCommand(commandId); if (activation.IsNull()) { command->SetHandler(IHandler::Pointer(nullptr)); } else { command->SetHandler(activation->GetHandler()); commandService->RefreshElements(commandId, QHash()); } } SmartPointer HandlerAuthority::FindHandler(const QString& commandId, IEvaluationContext* context) { IdToHandlerActivationMap::mapped_type activations = handlerActivationsByCommandId.value(commandId); IHandlerActivation::Pointer lastActivation; IHandlerActivation::Pointer currentActivation; QMapIterator i(activations); while (i.hasNext() && lastActivation.IsNull()) { HandlerActivation::Pointer activation = i.next().key(); try { if (Eval(context, activation)) { lastActivation = currentActivation; currentActivation = activation; } } catch (const CoreException&) { // OK, this one is out of the running } } if (currentActivation.IsNotNull()) { if (lastActivation.IsNull()) { return currentActivation->GetHandler(); } if (lastActivation->GetSourcePriority() != currentActivation->GetSourcePriority()) { return lastActivation->GetHandler(); } } return IHandler::Pointer(nullptr); } IEvaluationContext::Pointer HandlerAuthority::CreateContextSnapshot(bool includeSelection) { IEvaluationContext::Pointer tmpContext = GetCurrentState(); EvaluationContext::Pointer context; if (includeSelection) { context = new EvaluationContext(nullptr, tmpContext->GetDefaultVariable()); for (int i = 0; i < SELECTION_VARIABLES.size(); i++) { CopyVariable(context.GetPointer(), tmpContext.GetPointer(), SELECTION_VARIABLES[i]); } } else { context = new EvaluationContext(nullptr, Object::Pointer(nullptr)); } ISourceProviderService* sp = locator->GetService(); QList providers = sp->GetSourceProviders(); for (int i = 0; i < providers.size(); i++) { QList names = providers[i]->GetProvidedSourceNames(); for (int j = 0; j < names.size(); j++) { if (!IsSelectionVariable(names[j])) { CopyVariable(context.GetPointer(), tmpContext.GetPointer(), names[j]); } } } return context; } bool HandlerAuthority::Eval(IEvaluationContext* context, const SmartPointer& activation) { Expression::Pointer expression = activation->GetExpression(); if (expression.IsNull()) { return true; } return expression->Evaluate(context) == EvaluationResult::TRUE_EVAL; } bool HandlerAuthority::IsSelectionVariable(const QString& name) { for (int i = 0; i < SELECTION_VARIABLES.size(); i++) { if (SELECTION_VARIABLES[i] == name) { return true; } } return false; } void HandlerAuthority::CopyVariable(IEvaluationContext* context, IEvaluationContext* tmpContext, const QString& var) { Object::ConstPointer o = tmpContext->GetVariable(var); if (o.IsNotNull()) { context->AddVariable(var, o); } } void HandlerAuthority::ProcessChangedCommands() { // If tracing, then track how long it takes to process the activations. - QTime startTime; + QElapsedTimer timer; if (DEBUG_PERFORMANCE) { - startTime.start(); + timer.start(); } MultiStatus::Pointer conflicts( new MultiStatus("org.blueberry.ui", 0, "A handler conflict occurred. This may disable some commands.", BERRY_STATUS_LOC)); /* * For every command identifier with a changed activation, we resolve * conflicts and trigger an update. */ const QSet changedIds = changedCommandIds; changedCommandIds.clear(); foreach(const QString& commandId, changedIds) { IdToHandlerActivationMap::mapped_type activations = handlerActivationsByCommandId.value(commandId); if (activations.size() == 1) { const IHandlerActivation::Pointer activation = activations.begin().key(); UpdateCommand(commandId, (Evaluate(activation) ? activation : IHandlerActivation::Pointer(nullptr))); } else { const IHandlerActivation::Pointer activation = ResolveConflicts( commandId, activations, conflicts); UpdateCommand(commandId, activation); } } if (conflicts->GetSeverity() != IStatus::OK_TYPE) { WorkbenchPlugin::Log(conflicts); } // If tracing performance, then print the results. if (DEBUG_PERFORMANCE) { - const int elapsedTime = startTime.elapsed(); + const int elapsedTime = timer.elapsed(); const int size = changedCommandIds.size(); if (size > 0) { CommandTracing::PrintTrace(TRACING_COMPONENT, QString::number(size) + " command ids changed in " + elapsedTime + "ms"); } } } bool HandlerAuthority::Evaluate(const SmartPointer& expression) { IEvaluationContext::Pointer contextWithDefaultVariable = GetCurrentState(); return expression->Evaluate(contextWithDefaultVariable.GetPointer()); } SmartPointer HandlerAuthority::GetCurrentState() const { return GetEvaluationService()->GetCurrentState(); } //void HandlerAuthority::UpdateShellKludge() //{ // ((EvaluationService) getEvaluationService()).updateShellKludge(); //} //void HandlerAuthority::UpdateShellKludge(const SmartPointer& shell) //{ // ((EvaluationService) getEvaluationService()).updateShellKludge(shell); //} } diff --git a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/QmitkUltrasoundSupport.h b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/QmitkUltrasoundSupport.h index cfc051fc7a..4dc07dd1f1 100644 --- a/Plugins/org.mitk.gui.qt.ultrasound/src/internal/QmitkUltrasoundSupport.h +++ b/Plugins/org.mitk.gui.qt.ultrasound/src/internal/QmitkUltrasoundSupport.h @@ -1,181 +1,181 @@ /*============================================================================ The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center (DKFZ) All rights reserved. Use of this source code is governed by a 3-clause BSD license that can be found in the LICENSE file. ============================================================================*/ #ifndef QmitkUltrasoundSupport_h #define QmitkUltrasoundSupport_h #include #include #include #include #include "ui_QmitkUltrasoundSupportControls.h" #include "QmitkUSAbstractCustomWidget.h" #include "QmitkUSControlsBModeWidget.h" #include "QmitkUSControlsDopplerWidget.h" #include "QmitkUSControlsProbesWidget.h" #include #include "QmitkRenderWindow.h" #include #include #include -#include +#include #include /*! \brief UltrasoundSupport This plugin provides functionality to manage Ultrasound devices, create video devices and to view device images. \ingroup ${plugin_target}_internal */ class QmitkUltrasoundSupport : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: void SetFocus() override; static const std::string VIEW_ID; void CreateQtPartControl(QWidget *parent) override; QmitkUltrasoundSupport(); ~QmitkUltrasoundSupport() override; public slots: /* * \brief This is called when the newDeviceWidget is closed */ void OnNewDeviceWidgetDone(); protected slots: void OnClickedAddNewDevice(); void OnChangedFramerateLimit(); void OnClickedEditDevice(); /* *\brief Called, when the selection in the list of the active devices changes. */ void OnChangedActiveDevice(); void OnClickedFreezeButton(); void OnDeviceServiceEvent(const ctkServiceEvent event); /* * \brief This is the main imaging loop that updates the image and is called regularly during the imaging process */ void UpdateImage(); void RenderImage2d(); void RenderImage3d(); void StartTimers(); void StopTimers(); protected: void CreateControlWidgets(); void RemoveControlWidgets(); Ui::UltrasoundSupportControls* m_Controls; QmitkUSAbstractCustomWidget* m_ControlCustomWidget; QmitkUSControlsBModeWidget* m_ControlBModeWidget; QmitkUSControlsDopplerWidget* m_ControlDopplerWidget; QmitkUSControlsProbesWidget* m_ControlProbesWidget; bool m_ImageAlreadySetToNode; unsigned int m_CurrentImageWidth; unsigned int m_CurrentImageHeight; /** Keeps track of the amount of output Nodes*/ unsigned int m_AmountOfOutputs; /** The device that is currently used to acquire images */ mitk::USDevice::Pointer m_Device; void SetTimerIntervals(int intervalPipeline, int interval2D, int interval3D); /** This timer triggers periodic updates to the pipeline */ QTimer* m_UpdateTimer; QTimer* m_RenderingTimer2d; QTimer* m_RenderingTimer3d; /** These clocks are used to compute the framerate in the methods DisplayImage(),RenderImage2d() and RenderImage3d(). */ - QTime m_Clock; - QTime m_Clock2d; - QTime m_Clock3d; + QElapsedTimer m_Clock; + QElapsedTimer m_Clock2d; + QElapsedTimer m_Clock3d; /** A counter to compute the framerate. */ int m_FrameCounterPipeline; int m_FrameCounter2d; int m_FrameCounter3d; int m_FPSPipeline, m_FPS2d, m_FPS3d; /** Stores the properties of some QWidgets (and the tool storage file name) to QSettings.*/ void StoreUISettings(); /** Loads the properties of some QWidgets (and the tool storage file name) from QSettings.*/ void LoadUISettings(); /** The nodes that we feed images into.*/ std::vector m_Node; /** Adds a new node to the m_Nodes vector*/ void InitNewNode(); /** Destroys the last node in the m_Nodes vector */ void DestroyLastNode(); /** Checks the amount of slices in the image from the USDevice and creates as many Nodes as there are slices */ void UpdateAmountOfOutputs(); /** This function just checks how many nodes there are currently and sets the laser image to a jet transparent colormap. */ void UpdateLevelWindows(); bool m_ForceRequestUpdateAll; void SetColormap(mitk::DataNode::Pointer node, mitk::LookupTable::LookupTableType type); /** The separated slices from m_Image */ std::vector m_curOutput; /** The old geometry of m_Image. It is needed to check if the geometry changed (e.g. because * the zoom factor was modified) and the image needs to be reinitialized. */ mitk::SlicedGeometry3D::Pointer m_OldGeometry; QList m_CustomWidgetServiceReference; double m_CurrentDynamicRange; /* Spacing calibration variables and methods */ mitk::Point3D m_Xpoint1,m_Xpoint2,m_Ypoint1,m_Ypoint2; double m_XSpacing, m_YSpacing; double ComputeSpacing(mitk::Point3D p1, mitk::Point3D p2, double distance); protected slots: void SetXPoint1(); void SetXPoint2(); void SetYPoint1(); void SetYPoint2(); void WriteSpacingToDevice(); }; #endif