From 0703a7df2e97f4a2aa804471af1cd2ca5c1643c5 Mon Sep 17 00:00:00 2001 From: dankers Date: Wed, 3 Feb 2010 23:52:51 +0000 Subject: [PATCH] Build system branding git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@167 ebee16cc-31ac-478f-84a7-5cbb03baadba --- ground/bin/bin.pro | 4 +- ground/openpilotgcs.pri | 6 +- .../libs/extensionsystem/extensionsystem.pro | 2 +- .../libs/extensionsystem/pluginmanager.cpp | 1522 +++---- ground/src/openpilotgcslibrary.pri | 2 +- ground/src/openpilotgcsplugin.pri | 6 +- ground/src/plugins/coreplugin/Core.pluginspec | 2 +- ground/src/plugins/coreplugin/coreconstants.h | 456 +- .../editormanager/editormanager.cpp | 3874 ++++++++--------- .../coreplugin/editormanager/editorview.cpp | 2024 ++++----- ground/src/plugins/coreplugin/mainwindow.cpp | 2 +- .../src/plugins/coreplugin/versiondialog.cpp | 210 +- ground/src/plugins/welcome/Welcome.pluginspec | 4 +- ground/src/plugins/welcome/rssfetcher.cpp | 374 +- ground/src/rpath.pri | 4 +- 15 files changed, 4246 insertions(+), 4246 deletions(-) diff --git a/ground/bin/bin.pro b/ground/bin/bin.pro index 06feba8b4..3988a81e3 100644 --- a/ground/bin/bin.pro +++ b/ground/bin/bin.pro @@ -1,14 +1,14 @@ include(../openpilotgcs.pri) TEMPLATE = app -TARGET = $$IDE_APP_WRAPPER +TARGET = $$GCS_APP_WRAPPER OBJECTS_DIR = PRE_TARGETDEPS = $$PWD/openpilotgcs QMAKE_LINK = cp $$PWD/openpilotgcs $@ && : IGNORE REST -QMAKE_CLEAN = $$IDE_APP_WRAPPER +QMAKE_CLEAN = $$GCS_APP_WRAPPER target.path = /bin INSTALLS += target diff --git a/ground/openpilotgcs.pri b/ground/openpilotgcs.pri index 955bd424e..3ec4ed322 100644 --- a/ground/openpilotgcs.pri +++ b/ground/openpilotgcs.pri @@ -59,7 +59,7 @@ macx { GCS_PLUGIN_PATH = $$GCS_LIBRARY_PATH GCS_LIBEXEC_PATH = $$GCS_APP_PATH/$${GCS_APP_TARGET}.app/Contents/Resources GCS_DATA_PATH = $$GCS_APP_PATH/$${GCS_APP_TARGET}.app/Contents/Resources - IDE_DOC_PATH = $$GCS_DATA_PATH/doc + GCS_DOC_PATH = $$GCS_DATA_PATH/doc contains(QT_CONFIG, ppc):CONFIG += ppc x86 copydata = 1 } else { @@ -67,14 +67,14 @@ macx { contains(TEMPLATE, vc.*)|contains(TEMPLATE_PREFIX, vc):vcproj = 1 GCS_APP_TARGET = openpilotgcs } else { - IDE_APP_WRAPPER = openpilotgcs + GCS_APP_WRAPPER = openpilotgcs GCS_APP_TARGET = openpilotgcs.bin } GCS_LIBRARY_PATH = $$GCS_BUILD_TREE/$$GCS_LIBRARY_BASENAME/openpilotgcs GCS_PLUGIN_PATH = $$GCS_LIBRARY_PATH/plugins GCS_LIBEXEC_PATH = $$GCS_APP_PATH # FIXME GCS_DATA_PATH = $$GCS_BUILD_TREE/share/openpilotgcs - IDE_DOC_PATH = $$GCS_BUILD_TREE/share/doc/openpilotgcs + GCS_DOC_PATH = $$GCS_BUILD_TREE/share/doc/openpilotgcs !isEqual(GCS_SOURCE_TREE, $$GCS_BUILD_TREE):copydata = 1 } diff --git a/ground/src/libs/extensionsystem/extensionsystem.pro b/ground/src/libs/extensionsystem/extensionsystem.pro index 0d2084f81..30b21dec3 100644 --- a/ground/src/libs/extensionsystem/extensionsystem.pro +++ b/ground/src/libs/extensionsystem/extensionsystem.pro @@ -6,7 +6,7 @@ include(extensionsystem_dependencies.pri) unix:!macx:!freebsd*:LIBS += -ldl -DEFINES += IDE_TEST_DIR=\\\"$$GCS_SOURCE_TREE\\\" +DEFINES += GCS_TEST_DIR=\\\"$$GCS_SOURCE_TREE\\\" HEADERS += pluginerrorview.h \ plugindetailsview.h \ diff --git a/ground/src/libs/extensionsystem/pluginmanager.cpp b/ground/src/libs/extensionsystem/pluginmanager.cpp index 8cf365b67..70d5465f3 100644 --- a/ground/src/libs/extensionsystem/pluginmanager.cpp +++ b/ground/src/libs/extensionsystem/pluginmanager.cpp @@ -1,761 +1,761 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://qt.nokia.com/contact. -** -**************************************************************************/ - -#include "pluginmanager.h" -#include "pluginmanager_p.h" -#include "pluginspec.h" -#include "pluginspec_p.h" -#include "optionsparser.h" -#include "iplugin.h" - -#include -#include -#include -#include -#include -#ifdef WITH_TESTS -#include -#endif - -typedef QList PluginSpecSet; - -enum { debugLeaks = 0 }; - -/*! - \namespace ExtensionSystem - \brief The ExtensionSystem namespace provides classes that belong to the core plugin system. - - The basic extension system contains of the plugin manager and its supporting classes, - and the IPlugin interface that must be implemented by plugin providers. -*/ - -/*! - \namespace ExtensionSystem::Internal - \internal -*/ - -/*! - \class ExtensionSystem::PluginManager - \mainclass - - \brief Core plugin system that manages the plugins, their life cycle and their registered objects. - - The plugin manager is used for the following tasks: - \list - \o Manage plugins and their state - \o Manipulate a 'common object pool' - \endlist - - \section1 Plugins - Plugins consist of an xml descriptor file, and of a library that contains a Qt plugin - (declared via Q_EXPORT_PLUGIN) that must derive from the IPlugin class. - The plugin manager is used to set a list of file system directories to search for - plugins, retrieve information about the state of these plugins, and to load them. - - Usually the application creates a PluginManager instance and initiates the loading. - \code - ExtensionSystem::PluginManager *manager = new ExtensionSystem::PluginManager(); - manager->setPluginPaths(QStringList() << "plugins"); // 'plugins' and subdirs will be searched for plugins - manager->loadPlugins(); // try to load all the plugins - \endcode - Additionally it is possible to directly access to the plugin specifications - (the information in the descriptor file), and the plugin instances (via PluginSpec), - and their state. - - \section1 Object Pool - Plugins (and everybody else) can add objects to a common 'pool' that is located in - the plugin manager. Objects in the pool must derive from QObject, there are no other - prerequisites. All objects of a specified type can be retrieved from the object pool - via the getObjects() and getObject() methods. They are aware of Aggregation::Aggregate, i.e. - these methods use the Aggregation::query methods instead of a qobject_cast to determine - the matching objects. - - Whenever the state of the object pool changes a corresponding signal is emitted by the plugin manager. - - A common usecase for the object pool is that a plugin (or the application) provides - an "extension point" for other plugins, which is a class / interface that can - be implemented and added to the object pool. The plugin that provides the - extension point looks for implementations of the class / interface in the object pool. - \code - // plugin A provides a "MimeTypeHandler" extension point - // in plugin B: - MyMimeTypeHandler *handler = new MyMimeTypeHandler(); - ExtensionSystem::PluginManager::instance()->addObject(handler); - // in plugin A: - QList mimeHandlers = - ExtensionSystem::PluginManager::instance()->getObjects(); - \endcode - - \bold Note: The object pool manipulating functions are thread-safe. -*/ - -/*! - \fn void PluginManager::objectAdded(QObject *obj) - Signal that \a obj has been added to the object pool. -*/ - -/*! - \fn void PluginManager::aboutToRemoveObject(QObject *obj) - Signal that \a obj will be removed from the object pool. -*/ - -/*! - \fn void PluginManager::pluginsChanged() - Signal that the list of available plugins has changed. - - \sa plugins() -*/ - -/*! - \fn T *PluginManager::getObject() const - Retrieve the object of a given type from the object pool. - This method is aware of Aggregation::Aggregate, i.e. it uses - the Aggregation::query methods instead of qobject_cast to - determine the type of an object. - If there are more than one object of the given type in - the object pool, this method will choose an arbitrary one of them. - - \sa addObject() -*/ - -/*! - \fn QList PluginManager::getObjects() const - Retrieve all objects of a given type from the object pool. - This method is aware of Aggregation::Aggregate, i.e. it uses - the Aggregation::query methods instead of qobject_cast to - determine the type of an object. - - \sa addObject() -*/ - -using namespace ExtensionSystem; -using namespace ExtensionSystem::Internal; - -static bool lessThanByPluginName(const PluginSpec *one, const PluginSpec *two) -{ - return one->name() < two->name(); -} - -PluginManager *PluginManager::m_instance = 0; - -/*! - \fn PluginManager *PluginManager::instance() - Get the unique plugin manager instance. -*/ -PluginManager *PluginManager::instance() -{ - return m_instance; -} - -/*! - \fn PluginManager::PluginManager() - Create a plugin manager. Should be done only once per application. -*/ -PluginManager::PluginManager() - : d(new PluginManagerPrivate(this)) -{ - m_instance = this; -} - -/*! - \fn PluginManager::~PluginManager() - \internal -*/ -PluginManager::~PluginManager() -{ - delete d; - d = 0; -} - -/*! - \fn void PluginManager::addObject(QObject *obj) - Add the given object \a obj to the object pool, so it can be retrieved again from the pool by type. - The plugin manager does not do any memory management - added objects - must be removed from the pool and deleted manually by whoever is responsible for the object. - - Emits the objectAdded() signal. - - \sa PluginManager::removeObject() - \sa PluginManager::getObject() - \sa PluginManager::getObjects() -*/ -void PluginManager::addObject(QObject *obj) -{ - d->addObject(obj); -} - -/*! - \fn void PluginManager::removeObject(QObject *obj) - Emits aboutToRemoveObject() and removes the object \a obj from the object pool. - \sa PluginManager::addObject() -*/ -void PluginManager::removeObject(QObject *obj) -{ - d->removeObject(obj); -} - -/*! - \fn QList PluginManager::allObjects() const - Retrieve the list of all objects in the pool, unfiltered. - Usually clients do not need to call this. - \sa PluginManager::getObject() - \sa PluginManager::getObjects() -*/ -QList PluginManager::allObjects() const -{ - return d->allObjects; -} - -/*! - \fn void PluginManager::loadPlugins() - Tries to load all the plugins that were previously found when - setting the plugin search paths. The plugin specs of the plugins - can be used to retrieve error and state information about individual plugins. - - \sa setPluginPaths() - \sa plugins() -*/ -void PluginManager::loadPlugins() -{ - return d->loadPlugins(); -} - -/*! - \fn QStringList PluginManager::pluginPaths() const - The list of paths were the plugin manager searches for plugins. - - \sa setPluginPaths() -*/ -QStringList PluginManager::pluginPaths() const -{ - return d->pluginPaths; -} - -/*! - \fn void PluginManager::setPluginPaths(const QStringList &paths) - Sets the plugin search paths, i.e. the file system paths where the plugin manager - looks for plugin descriptions. All given \a paths and their sub directory trees - are searched for plugin xml description files. - - \sa pluginPaths() - \sa loadPlugins() -*/ -void PluginManager::setPluginPaths(const QStringList &paths) -{ - d->setPluginPaths(paths); -} - -/*! - \fn QString PluginManager::fileExtension() const - The file extension of plugin description files. - The default is "xml". - - \sa setFileExtension() -*/ -QString PluginManager::fileExtension() const -{ - return d->extension; -} - -/*! - \fn void PluginManager::setFileExtension(const QString &extension) - Sets the file extension of plugin description files. - The default is "xml". - At the moment this must be called before setPluginPaths() is called. - // ### TODO let this + setPluginPaths read the plugin specs lazyly whenever loadPlugins() or plugins() is called. -*/ -void PluginManager::setFileExtension(const QString &extension) -{ - d->extension = extension; -} - -/*! - \fn QStringList PluginManager::arguments() const - The arguments left over after parsing (Neither startup nor plugin - arguments). Typically, this will be the list of files to open. -*/ -QStringList PluginManager::arguments() const -{ - return d->arguments; -} - -/*! - \fn QList PluginManager::plugins() const - List of all plugin specifications that have been found in the plugin search paths. - This list is valid directly after the setPluginPaths() call. - The plugin specifications contain the information from the plugins' xml description files - and the current state of the plugins. If a plugin's library has been already successfully loaded, - the plugin specification has a reference to the created plugin instance as well. - - \sa setPluginPaths() -*/ -QList PluginManager::plugins() const -{ - return d->pluginSpecs; -} - -/*! - \fn bool PluginManager::parseOptions(const QStringList &args, const QMap &appOptions, QMap *foundAppOptions, QString *errorString) - Takes the list of command line options in \a args and parses them. - The plugin manager itself might process some options itself directly (-noload ), and - adds options that are registered by plugins to their plugin specs. - The caller (the application) may register itself for options via the \a appOptions list, containing pairs - of "option string" and a bool that indicates if the option requires an argument. - Application options always override any plugin's options. - - \a foundAppOptions is set to pairs of ("option string", "argument") for any application options that were found. - The command line options that were not processed can be retrieved via the arguments() method. - If an error occurred (like missing argument for an option that requires one), \a errorString contains - a descriptive message of the error. - - Returns if there was an error. - */ -bool PluginManager::parseOptions(const QStringList &args, - const QMap &appOptions, - QMap *foundAppOptions, - QString *errorString) -{ - OptionsParser options(args, appOptions, foundAppOptions, errorString, d); - return options.parse(); -} - - - -static inline void indent(QTextStream &str, int indent) -{ - const QChar blank = QLatin1Char(' '); - for (int i = 0 ; i < indent; i++) - str << blank; -} - -static inline void formatOption(QTextStream &str, - const QString &opt, const QString &parm, const QString &description, - int optionIndentation, int descriptionIndentation) -{ - int remainingIndent = descriptionIndentation - optionIndentation - opt.size(); - indent(str, optionIndentation); - str << opt; - if (!parm.isEmpty()) { - str << " <" << parm << '>'; - remainingIndent -= 3 + parm.size(); - } - indent(str, qMax(0, remainingIndent)); - str << description << '\n'; -} - -/*! - \fn static PluginManager::formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) - - Format the startup options of the plugin manager for command line help. -*/ - -void PluginManager::formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) -{ - formatOption(str, QLatin1String(OptionsParser::NO_LOAD_OPTION), - QLatin1String("plugin"), QLatin1String("Do not load "), - optionIndentation, descriptionIndentation); -} - -/*! - \fn PluginManager::formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) const - - Format the plugin options of the plugin specs for command line help. -*/ - -void PluginManager::formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) const -{ - typedef PluginSpec::PluginArgumentDescriptions PluginArgumentDescriptions; - // Check plugins for options - const PluginSpecSet::const_iterator pcend = d->pluginSpecs.constEnd(); - for (PluginSpecSet::const_iterator pit = d->pluginSpecs.constBegin(); pit != pcend; ++pit) { - const PluginArgumentDescriptions pargs = (*pit)->argumentDescriptions(); - if (!pargs.empty()) { - str << "\nPlugin: " << (*pit)->name() << '\n'; - const PluginArgumentDescriptions::const_iterator acend = pargs.constEnd(); - for (PluginArgumentDescriptions::const_iterator ait =pargs.constBegin(); ait != acend; ++ait) - formatOption(str, ait->name, ait->parameter, ait->description, optionIndentation, descriptionIndentation); - } - } -} - -/*! - \fn PluginManager::formatPluginVersions(QTextStream &str) const - - Format the version of the plugin specs for command line help. -*/ - -void PluginManager::formatPluginVersions(QTextStream &str) const -{ - const PluginSpecSet::const_iterator cend = d->pluginSpecs.constEnd(); - for (PluginSpecSet::const_iterator it = d->pluginSpecs.constBegin(); it != cend; ++it) { - const PluginSpec *ps = *it; - str << " " << ps->name() << ' ' << ps->version() << ' ' << ps->description() << '\n'; - } -} - -void PluginManager::startTests() -{ -#ifdef WITH_TESTS - foreach (PluginSpec *pluginSpec, d->testSpecs) { - const QMetaObject *mo = pluginSpec->plugin()->metaObject(); - QStringList methods; - methods.append("arg0"); - // We only want slots starting with "test" - for (int i = mo->methodOffset(); i < mo->methodCount(); ++i) { - if (QByteArray(mo->method(i).signature()).startsWith("test")) { - QString method = QString::fromLatin1(mo->method(i).signature()); - methods.append(method.left(method.size()-2)); - } - } - QTest::qExec(pluginSpec->plugin(), methods); - - } -#endif -} - -/*! - * \fn bool PluginManager::runningTests() const - * \internal - */ -bool PluginManager::runningTests() const -{ - return !d->testSpecs.isEmpty(); -} - -/*! - * \fn QString PluginManager::testDataDirectory() const - * \internal - */ -QString PluginManager::testDataDirectory() const -{ - QByteArray ba = qgetenv("QTCREATOR_TEST_DIR"); - QString s = QString::fromLocal8Bit(ba.constData(), ba.size()); - if (s.isEmpty()) { - s = IDE_TEST_DIR; - s.append("/tests"); - } - s = QDir::cleanPath(s); - return s; -} - -//============PluginManagerPrivate=========== - -/*! - \fn PluginSpec *PluginManagerPrivate::createSpec() - \internal -*/ -PluginSpec *PluginManagerPrivate::createSpec() -{ - return new PluginSpec(); -} - -/*! - \fn PluginSpecPrivate *PluginManagerPrivate::privateSpec(PluginSpec *spec) - \internal -*/ -PluginSpecPrivate *PluginManagerPrivate::privateSpec(PluginSpec *spec) -{ - return spec->d; -} - -/*! - \fn PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager) - \internal -*/ -PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager) - : extension("xml"), q(pluginManager) -{ -} - -/*! - \fn PluginManagerPrivate::~PluginManagerPrivate() - \internal -*/ -PluginManagerPrivate::~PluginManagerPrivate() -{ - stopAll(); - qDeleteAll(pluginSpecs); - if (!allObjects.isEmpty()) { - qDebug() << "There are" << allObjects.size() << "objects left in the plugin manager pool: " << allObjects; - } -} - -void PluginManagerPrivate::stopAll() -{ - QList queue = loadQueue(); - foreach (PluginSpec *spec, queue) { - loadPlugin(spec, PluginSpec::Stopped); - } - QListIterator it(queue); - it.toBack(); - while (it.hasPrevious()) { - loadPlugin(it.previous(), PluginSpec::Deleted); - } -} - -/*! - \fn void PluginManagerPrivate::addObject(QObject *obj) - \internal -*/ -void PluginManagerPrivate::addObject(QObject *obj) -{ - { - QWriteLocker lock(&(q->m_lock)); - if (obj == 0) { - qWarning() << "PluginManagerPrivate::addObject(): trying to add null object"; - return; - } - if (allObjects.contains(obj)) { - qWarning() << "PluginManagerPrivate::addObject(): trying to add duplicate object"; - return; - } - - if (debugLeaks) - qDebug() << "PluginManagerPrivate::addObject" << obj << obj->objectName(); - - allObjects.append(obj); - } - emit q->objectAdded(obj); -} - -/*! - \fn void PluginManagerPrivate::removeObject(QObject *obj) - \internal -*/ -void PluginManagerPrivate::removeObject(QObject *obj) -{ - if (obj == 0) { - qWarning() << "PluginManagerPrivate::removeObject(): trying to remove null object"; - return; - } - - if (!allObjects.contains(obj)) { - qWarning() << "PluginManagerPrivate::removeObject(): object not in list:" - << obj << obj->objectName(); - return; - } - if (debugLeaks) - qDebug() << "PluginManagerPrivate::removeObject" << obj << obj->objectName(); - - emit q->aboutToRemoveObject(obj); - QWriteLocker lock(&(q->m_lock)); - allObjects.removeAll(obj); -} - -/*! - \fn void PluginManagerPrivate::loadPlugins() - \internal -*/ -void PluginManagerPrivate::loadPlugins() -{ - QList queue = loadQueue(); - foreach (PluginSpec *spec, queue) { - loadPlugin(spec, PluginSpec::Loaded); - } - foreach (PluginSpec *spec, queue) { - loadPlugin(spec, PluginSpec::Initialized); - } - QListIterator it(queue); - it.toBack(); - while (it.hasPrevious()) { - loadPlugin(it.previous(), PluginSpec::Running); - } - emit q->pluginsChanged(); -} - -/*! - \fn void PluginManagerPrivate::loadQueue() - \internal -*/ -QList PluginManagerPrivate::loadQueue() -{ - QList queue; - foreach (PluginSpec *spec, pluginSpecs) { - QList circularityCheckQueue; - loadQueue(spec, queue, circularityCheckQueue); - } - return queue; -} - -/*! - \fn bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList &queue, QList &circularityCheckQueue) - \internal -*/ -bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList &queue, - QList &circularityCheckQueue) -{ - if (queue.contains(spec)) - return true; - // check for circular dependencies - if (circularityCheckQueue.contains(spec)) { - spec->d->hasError = true; - spec->d->errorString = PluginManager::tr("Circular dependency detected:\n"); - int index = circularityCheckQueue.indexOf(spec); - for (int i = index; i < circularityCheckQueue.size(); ++i) { - spec->d->errorString.append(PluginManager::tr("%1(%2) depends on\n") - .arg(circularityCheckQueue.at(i)->name()).arg(circularityCheckQueue.at(i)->version())); - } - spec->d->errorString.append(PluginManager::tr("%1(%2)").arg(spec->name()).arg(spec->version())); - return false; - } - circularityCheckQueue.append(spec); - // check if we have the dependencies - if (spec->state() == PluginSpec::Invalid || spec->state() == PluginSpec::Read) { - spec->d->hasError = true; - spec->d->errorString += "\n"; - spec->d->errorString += PluginManager::tr("Cannot load plugin because dependencies are not resolved"); - return false; - } - // add dependencies - foreach (PluginSpec *depSpec, spec->dependencySpecs()) { - if (!loadQueue(depSpec, queue, circularityCheckQueue)) { - spec->d->hasError = true; - spec->d->errorString = - PluginManager::tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3") - .arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString()); - return false; - } - } - // add self - queue.append(spec); - return true; -} - -/*! - \fn void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destState) - \internal -*/ -void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destState) -{ - if (spec->hasError()) - return; - if (destState == PluginSpec::Running) { - spec->d->initializeExtensions(); - return; - } else if (destState == PluginSpec::Deleted) { - spec->d->kill(); - return; - } - foreach (PluginSpec *depSpec, spec->dependencySpecs()) { - if (depSpec->state() != destState) { - spec->d->hasError = true; - spec->d->errorString = - PluginManager::tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3") - .arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString()); - return; - } - } - if (destState == PluginSpec::Loaded) - spec->d->loadLibrary(); - else if (destState == PluginSpec::Initialized) - spec->d->initializePlugin(); - else if (destState == PluginSpec::Stopped) - spec->d->stop(); -} - -/*! - \fn void PluginManagerPrivate::setPluginPaths(const QStringList &paths) - \internal -*/ -void PluginManagerPrivate::setPluginPaths(const QStringList &paths) -{ - pluginPaths = paths; - readPluginPaths(); -} - -/*! - \fn void PluginManagerPrivate::readPluginPaths() - \internal -*/ -void PluginManagerPrivate::readPluginPaths() -{ - qDeleteAll(pluginSpecs); - pluginSpecs.clear(); - - QStringList specFiles; - QStringList searchPaths = pluginPaths; - while (!searchPaths.isEmpty()) { - const QDir dir(searchPaths.takeFirst()); - const QFileInfoList files = dir.entryInfoList(QStringList() << QString("*.%1").arg(extension), QDir::Files); - foreach (const QFileInfo &file, files) - specFiles << file.absoluteFilePath(); - const QFileInfoList dirs = dir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot); - foreach (const QFileInfo &subdir, dirs) - searchPaths << subdir.absoluteFilePath(); - } - foreach (const QString &specFile, specFiles) { - PluginSpec *spec = new PluginSpec; - spec->d->read(specFile); - pluginSpecs.append(spec); - } - resolveDependencies(); - // ensure deterministic plugin load order by sorting - qSort(pluginSpecs.begin(), pluginSpecs.end(), lessThanByPluginName); - emit q->pluginsChanged(); -} - -void PluginManagerPrivate::resolveDependencies() -{ - foreach (PluginSpec *spec, pluginSpecs) { - spec->d->resolveDependencies(pluginSpecs); - } -} - - // Look in argument descriptions of the specs for the option. -PluginSpec *PluginManagerPrivate::pluginForOption(const QString &option, bool *requiresArgument) const -{ - // Look in the plugins for an option - typedef PluginSpec::PluginArgumentDescriptions PluginArgumentDescriptions; - - *requiresArgument = false; - const PluginSpecSet::const_iterator pcend = pluginSpecs.constEnd(); - for (PluginSpecSet::const_iterator pit = pluginSpecs.constBegin(); pit != pcend; ++pit) { - PluginSpec *ps = *pit; - const PluginArgumentDescriptions pargs = ps->argumentDescriptions(); - if (!pargs.empty()) { - const PluginArgumentDescriptions::const_iterator acend = pargs.constEnd(); - for (PluginArgumentDescriptions::const_iterator ait = pargs.constBegin(); ait != acend; ++ait) { - if (ait->name == option) { - *requiresArgument = !ait->parameter.isEmpty(); - return ps; - } - } - } - } - return 0; -} - -PluginSpec *PluginManagerPrivate::pluginByName(const QString &name) const -{ - foreach (PluginSpec *spec, pluginSpecs) - if (spec->name() == name) - return spec; - return 0; -} - +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "pluginmanager.h" +#include "pluginmanager_p.h" +#include "pluginspec.h" +#include "pluginspec_p.h" +#include "optionsparser.h" +#include "iplugin.h" + +#include +#include +#include +#include +#include +#ifdef WITH_TESTS +#include +#endif + +typedef QList PluginSpecSet; + +enum { debugLeaks = 0 }; + +/*! + \namespace ExtensionSystem + \brief The ExtensionSystem namespace provides classes that belong to the core plugin system. + + The basic extension system contains of the plugin manager and its supporting classes, + and the IPlugin interface that must be implemented by plugin providers. +*/ + +/*! + \namespace ExtensionSystem::Internal + \internal +*/ + +/*! + \class ExtensionSystem::PluginManager + \mainclass + + \brief Core plugin system that manages the plugins, their life cycle and their registered objects. + + The plugin manager is used for the following tasks: + \list + \o Manage plugins and their state + \o Manipulate a 'common object pool' + \endlist + + \section1 Plugins + Plugins consist of an xml descriptor file, and of a library that contains a Qt plugin + (declared via Q_EXPORT_PLUGIN) that must derive from the IPlugin class. + The plugin manager is used to set a list of file system directories to search for + plugins, retrieve information about the state of these plugins, and to load them. + + Usually the application creates a PluginManager instance and initiates the loading. + \code + ExtensionSystem::PluginManager *manager = new ExtensionSystem::PluginManager(); + manager->setPluginPaths(QStringList() << "plugins"); // 'plugins' and subdirs will be searched for plugins + manager->loadPlugins(); // try to load all the plugins + \endcode + Additionally it is possible to directly access to the plugin specifications + (the information in the descriptor file), and the plugin instances (via PluginSpec), + and their state. + + \section1 Object Pool + Plugins (and everybody else) can add objects to a common 'pool' that is located in + the plugin manager. Objects in the pool must derive from QObject, there are no other + prerequisites. All objects of a specified type can be retrieved from the object pool + via the getObjects() and getObject() methods. They are aware of Aggregation::Aggregate, i.e. + these methods use the Aggregation::query methods instead of a qobject_cast to determine + the matching objects. + + Whenever the state of the object pool changes a corresponding signal is emitted by the plugin manager. + + A common usecase for the object pool is that a plugin (or the application) provides + an "extension point" for other plugins, which is a class / interface that can + be implemented and added to the object pool. The plugin that provides the + extension point looks for implementations of the class / interface in the object pool. + \code + // plugin A provides a "MimeTypeHandler" extension point + // in plugin B: + MyMimeTypeHandler *handler = new MyMimeTypeHandler(); + ExtensionSystem::PluginManager::instance()->addObject(handler); + // in plugin A: + QList mimeHandlers = + ExtensionSystem::PluginManager::instance()->getObjects(); + \endcode + + \bold Note: The object pool manipulating functions are thread-safe. +*/ + +/*! + \fn void PluginManager::objectAdded(QObject *obj) + Signal that \a obj has been added to the object pool. +*/ + +/*! + \fn void PluginManager::aboutToRemoveObject(QObject *obj) + Signal that \a obj will be removed from the object pool. +*/ + +/*! + \fn void PluginManager::pluginsChanged() + Signal that the list of available plugins has changed. + + \sa plugins() +*/ + +/*! + \fn T *PluginManager::getObject() const + Retrieve the object of a given type from the object pool. + This method is aware of Aggregation::Aggregate, i.e. it uses + the Aggregation::query methods instead of qobject_cast to + determine the type of an object. + If there are more than one object of the given type in + the object pool, this method will choose an arbitrary one of them. + + \sa addObject() +*/ + +/*! + \fn QList PluginManager::getObjects() const + Retrieve all objects of a given type from the object pool. + This method is aware of Aggregation::Aggregate, i.e. it uses + the Aggregation::query methods instead of qobject_cast to + determine the type of an object. + + \sa addObject() +*/ + +using namespace ExtensionSystem; +using namespace ExtensionSystem::Internal; + +static bool lessThanByPluginName(const PluginSpec *one, const PluginSpec *two) +{ + return one->name() < two->name(); +} + +PluginManager *PluginManager::m_instance = 0; + +/*! + \fn PluginManager *PluginManager::instance() + Get the unique plugin manager instance. +*/ +PluginManager *PluginManager::instance() +{ + return m_instance; +} + +/*! + \fn PluginManager::PluginManager() + Create a plugin manager. Should be done only once per application. +*/ +PluginManager::PluginManager() + : d(new PluginManagerPrivate(this)) +{ + m_instance = this; +} + +/*! + \fn PluginManager::~PluginManager() + \internal +*/ +PluginManager::~PluginManager() +{ + delete d; + d = 0; +} + +/*! + \fn void PluginManager::addObject(QObject *obj) + Add the given object \a obj to the object pool, so it can be retrieved again from the pool by type. + The plugin manager does not do any memory management - added objects + must be removed from the pool and deleted manually by whoever is responsible for the object. + + Emits the objectAdded() signal. + + \sa PluginManager::removeObject() + \sa PluginManager::getObject() + \sa PluginManager::getObjects() +*/ +void PluginManager::addObject(QObject *obj) +{ + d->addObject(obj); +} + +/*! + \fn void PluginManager::removeObject(QObject *obj) + Emits aboutToRemoveObject() and removes the object \a obj from the object pool. + \sa PluginManager::addObject() +*/ +void PluginManager::removeObject(QObject *obj) +{ + d->removeObject(obj); +} + +/*! + \fn QList PluginManager::allObjects() const + Retrieve the list of all objects in the pool, unfiltered. + Usually clients do not need to call this. + \sa PluginManager::getObject() + \sa PluginManager::getObjects() +*/ +QList PluginManager::allObjects() const +{ + return d->allObjects; +} + +/*! + \fn void PluginManager::loadPlugins() + Tries to load all the plugins that were previously found when + setting the plugin search paths. The plugin specs of the plugins + can be used to retrieve error and state information about individual plugins. + + \sa setPluginPaths() + \sa plugins() +*/ +void PluginManager::loadPlugins() +{ + return d->loadPlugins(); +} + +/*! + \fn QStringList PluginManager::pluginPaths() const + The list of paths were the plugin manager searches for plugins. + + \sa setPluginPaths() +*/ +QStringList PluginManager::pluginPaths() const +{ + return d->pluginPaths; +} + +/*! + \fn void PluginManager::setPluginPaths(const QStringList &paths) + Sets the plugin search paths, i.e. the file system paths where the plugin manager + looks for plugin descriptions. All given \a paths and their sub directory trees + are searched for plugin xml description files. + + \sa pluginPaths() + \sa loadPlugins() +*/ +void PluginManager::setPluginPaths(const QStringList &paths) +{ + d->setPluginPaths(paths); +} + +/*! + \fn QString PluginManager::fileExtension() const + The file extension of plugin description files. + The default is "xml". + + \sa setFileExtension() +*/ +QString PluginManager::fileExtension() const +{ + return d->extension; +} + +/*! + \fn void PluginManager::setFileExtension(const QString &extension) + Sets the file extension of plugin description files. + The default is "xml". + At the moment this must be called before setPluginPaths() is called. + // ### TODO let this + setPluginPaths read the plugin specs lazyly whenever loadPlugins() or plugins() is called. +*/ +void PluginManager::setFileExtension(const QString &extension) +{ + d->extension = extension; +} + +/*! + \fn QStringList PluginManager::arguments() const + The arguments left over after parsing (Neither startup nor plugin + arguments). Typically, this will be the list of files to open. +*/ +QStringList PluginManager::arguments() const +{ + return d->arguments; +} + +/*! + \fn QList PluginManager::plugins() const + List of all plugin specifications that have been found in the plugin search paths. + This list is valid directly after the setPluginPaths() call. + The plugin specifications contain the information from the plugins' xml description files + and the current state of the plugins. If a plugin's library has been already successfully loaded, + the plugin specification has a reference to the created plugin instance as well. + + \sa setPluginPaths() +*/ +QList PluginManager::plugins() const +{ + return d->pluginSpecs; +} + +/*! + \fn bool PluginManager::parseOptions(const QStringList &args, const QMap &appOptions, QMap *foundAppOptions, QString *errorString) + Takes the list of command line options in \a args and parses them. + The plugin manager itself might process some options itself directly (-noload ), and + adds options that are registered by plugins to their plugin specs. + The caller (the application) may register itself for options via the \a appOptions list, containing pairs + of "option string" and a bool that indicates if the option requires an argument. + Application options always override any plugin's options. + + \a foundAppOptions is set to pairs of ("option string", "argument") for any application options that were found. + The command line options that were not processed can be retrieved via the arguments() method. + If an error occurred (like missing argument for an option that requires one), \a errorString contains + a descriptive message of the error. + + Returns if there was an error. + */ +bool PluginManager::parseOptions(const QStringList &args, + const QMap &appOptions, + QMap *foundAppOptions, + QString *errorString) +{ + OptionsParser options(args, appOptions, foundAppOptions, errorString, d); + return options.parse(); +} + + + +static inline void indent(QTextStream &str, int indent) +{ + const QChar blank = QLatin1Char(' '); + for (int i = 0 ; i < indent; i++) + str << blank; +} + +static inline void formatOption(QTextStream &str, + const QString &opt, const QString &parm, const QString &description, + int optionIndentation, int descriptionIndentation) +{ + int remainingIndent = descriptionIndentation - optionIndentation - opt.size(); + indent(str, optionIndentation); + str << opt; + if (!parm.isEmpty()) { + str << " <" << parm << '>'; + remainingIndent -= 3 + parm.size(); + } + indent(str, qMax(0, remainingIndent)); + str << description << '\n'; +} + +/*! + \fn static PluginManager::formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) + + Format the startup options of the plugin manager for command line help. +*/ + +void PluginManager::formatOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) +{ + formatOption(str, QLatin1String(OptionsParser::NO_LOAD_OPTION), + QLatin1String("plugin"), QLatin1String("Do not load "), + optionIndentation, descriptionIndentation); +} + +/*! + \fn PluginManager::formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) const + + Format the plugin options of the plugin specs for command line help. +*/ + +void PluginManager::formatPluginOptions(QTextStream &str, int optionIndentation, int descriptionIndentation) const +{ + typedef PluginSpec::PluginArgumentDescriptions PluginArgumentDescriptions; + // Check plugins for options + const PluginSpecSet::const_iterator pcend = d->pluginSpecs.constEnd(); + for (PluginSpecSet::const_iterator pit = d->pluginSpecs.constBegin(); pit != pcend; ++pit) { + const PluginArgumentDescriptions pargs = (*pit)->argumentDescriptions(); + if (!pargs.empty()) { + str << "\nPlugin: " << (*pit)->name() << '\n'; + const PluginArgumentDescriptions::const_iterator acend = pargs.constEnd(); + for (PluginArgumentDescriptions::const_iterator ait =pargs.constBegin(); ait != acend; ++ait) + formatOption(str, ait->name, ait->parameter, ait->description, optionIndentation, descriptionIndentation); + } + } +} + +/*! + \fn PluginManager::formatPluginVersions(QTextStream &str) const + + Format the version of the plugin specs for command line help. +*/ + +void PluginManager::formatPluginVersions(QTextStream &str) const +{ + const PluginSpecSet::const_iterator cend = d->pluginSpecs.constEnd(); + for (PluginSpecSet::const_iterator it = d->pluginSpecs.constBegin(); it != cend; ++it) { + const PluginSpec *ps = *it; + str << " " << ps->name() << ' ' << ps->version() << ' ' << ps->description() << '\n'; + } +} + +void PluginManager::startTests() +{ +#ifdef WITH_TESTS + foreach (PluginSpec *pluginSpec, d->testSpecs) { + const QMetaObject *mo = pluginSpec->plugin()->metaObject(); + QStringList methods; + methods.append("arg0"); + // We only want slots starting with "test" + for (int i = mo->methodOffset(); i < mo->methodCount(); ++i) { + if (QByteArray(mo->method(i).signature()).startsWith("test")) { + QString method = QString::fromLatin1(mo->method(i).signature()); + methods.append(method.left(method.size()-2)); + } + } + QTest::qExec(pluginSpec->plugin(), methods); + + } +#endif +} + +/*! + * \fn bool PluginManager::runningTests() const + * \internal + */ +bool PluginManager::runningTests() const +{ + return !d->testSpecs.isEmpty(); +} + +/*! + * \fn QString PluginManager::testDataDirectory() const + * \internal + */ +QString PluginManager::testDataDirectory() const +{ + QByteArray ba = qgetenv("QTCREATOR_TEST_DIR"); + QString s = QString::fromLocal8Bit(ba.constData(), ba.size()); + if (s.isEmpty()) { + s = GCS_TEST_DIR; + s.append("/tests"); + } + s = QDir::cleanPath(s); + return s; +} + +//============PluginManagerPrivate=========== + +/*! + \fn PluginSpec *PluginManagerPrivate::createSpec() + \internal +*/ +PluginSpec *PluginManagerPrivate::createSpec() +{ + return new PluginSpec(); +} + +/*! + \fn PluginSpecPrivate *PluginManagerPrivate::privateSpec(PluginSpec *spec) + \internal +*/ +PluginSpecPrivate *PluginManagerPrivate::privateSpec(PluginSpec *spec) +{ + return spec->d; +} + +/*! + \fn PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager) + \internal +*/ +PluginManagerPrivate::PluginManagerPrivate(PluginManager *pluginManager) + : extension("xml"), q(pluginManager) +{ +} + +/*! + \fn PluginManagerPrivate::~PluginManagerPrivate() + \internal +*/ +PluginManagerPrivate::~PluginManagerPrivate() +{ + stopAll(); + qDeleteAll(pluginSpecs); + if (!allObjects.isEmpty()) { + qDebug() << "There are" << allObjects.size() << "objects left in the plugin manager pool: " << allObjects; + } +} + +void PluginManagerPrivate::stopAll() +{ + QList queue = loadQueue(); + foreach (PluginSpec *spec, queue) { + loadPlugin(spec, PluginSpec::Stopped); + } + QListIterator it(queue); + it.toBack(); + while (it.hasPrevious()) { + loadPlugin(it.previous(), PluginSpec::Deleted); + } +} + +/*! + \fn void PluginManagerPrivate::addObject(QObject *obj) + \internal +*/ +void PluginManagerPrivate::addObject(QObject *obj) +{ + { + QWriteLocker lock(&(q->m_lock)); + if (obj == 0) { + qWarning() << "PluginManagerPrivate::addObject(): trying to add null object"; + return; + } + if (allObjects.contains(obj)) { + qWarning() << "PluginManagerPrivate::addObject(): trying to add duplicate object"; + return; + } + + if (debugLeaks) + qDebug() << "PluginManagerPrivate::addObject" << obj << obj->objectName(); + + allObjects.append(obj); + } + emit q->objectAdded(obj); +} + +/*! + \fn void PluginManagerPrivate::removeObject(QObject *obj) + \internal +*/ +void PluginManagerPrivate::removeObject(QObject *obj) +{ + if (obj == 0) { + qWarning() << "PluginManagerPrivate::removeObject(): trying to remove null object"; + return; + } + + if (!allObjects.contains(obj)) { + qWarning() << "PluginManagerPrivate::removeObject(): object not in list:" + << obj << obj->objectName(); + return; + } + if (debugLeaks) + qDebug() << "PluginManagerPrivate::removeObject" << obj << obj->objectName(); + + emit q->aboutToRemoveObject(obj); + QWriteLocker lock(&(q->m_lock)); + allObjects.removeAll(obj); +} + +/*! + \fn void PluginManagerPrivate::loadPlugins() + \internal +*/ +void PluginManagerPrivate::loadPlugins() +{ + QList queue = loadQueue(); + foreach (PluginSpec *spec, queue) { + loadPlugin(spec, PluginSpec::Loaded); + } + foreach (PluginSpec *spec, queue) { + loadPlugin(spec, PluginSpec::Initialized); + } + QListIterator it(queue); + it.toBack(); + while (it.hasPrevious()) { + loadPlugin(it.previous(), PluginSpec::Running); + } + emit q->pluginsChanged(); +} + +/*! + \fn void PluginManagerPrivate::loadQueue() + \internal +*/ +QList PluginManagerPrivate::loadQueue() +{ + QList queue; + foreach (PluginSpec *spec, pluginSpecs) { + QList circularityCheckQueue; + loadQueue(spec, queue, circularityCheckQueue); + } + return queue; +} + +/*! + \fn bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList &queue, QList &circularityCheckQueue) + \internal +*/ +bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList &queue, + QList &circularityCheckQueue) +{ + if (queue.contains(spec)) + return true; + // check for circular dependencies + if (circularityCheckQueue.contains(spec)) { + spec->d->hasError = true; + spec->d->errorString = PluginManager::tr("Circular dependency detected:\n"); + int index = circularityCheckQueue.indexOf(spec); + for (int i = index; i < circularityCheckQueue.size(); ++i) { + spec->d->errorString.append(PluginManager::tr("%1(%2) depends on\n") + .arg(circularityCheckQueue.at(i)->name()).arg(circularityCheckQueue.at(i)->version())); + } + spec->d->errorString.append(PluginManager::tr("%1(%2)").arg(spec->name()).arg(spec->version())); + return false; + } + circularityCheckQueue.append(spec); + // check if we have the dependencies + if (spec->state() == PluginSpec::Invalid || spec->state() == PluginSpec::Read) { + spec->d->hasError = true; + spec->d->errorString += "\n"; + spec->d->errorString += PluginManager::tr("Cannot load plugin because dependencies are not resolved"); + return false; + } + // add dependencies + foreach (PluginSpec *depSpec, spec->dependencySpecs()) { + if (!loadQueue(depSpec, queue, circularityCheckQueue)) { + spec->d->hasError = true; + spec->d->errorString = + PluginManager::tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3") + .arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString()); + return false; + } + } + // add self + queue.append(spec); + return true; +} + +/*! + \fn void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destState) + \internal +*/ +void PluginManagerPrivate::loadPlugin(PluginSpec *spec, PluginSpec::State destState) +{ + if (spec->hasError()) + return; + if (destState == PluginSpec::Running) { + spec->d->initializeExtensions(); + return; + } else if (destState == PluginSpec::Deleted) { + spec->d->kill(); + return; + } + foreach (PluginSpec *depSpec, spec->dependencySpecs()) { + if (depSpec->state() != destState) { + spec->d->hasError = true; + spec->d->errorString = + PluginManager::tr("Cannot load plugin because dependency failed to load: %1(%2)\nReason: %3") + .arg(depSpec->name()).arg(depSpec->version()).arg(depSpec->errorString()); + return; + } + } + if (destState == PluginSpec::Loaded) + spec->d->loadLibrary(); + else if (destState == PluginSpec::Initialized) + spec->d->initializePlugin(); + else if (destState == PluginSpec::Stopped) + spec->d->stop(); +} + +/*! + \fn void PluginManagerPrivate::setPluginPaths(const QStringList &paths) + \internal +*/ +void PluginManagerPrivate::setPluginPaths(const QStringList &paths) +{ + pluginPaths = paths; + readPluginPaths(); +} + +/*! + \fn void PluginManagerPrivate::readPluginPaths() + \internal +*/ +void PluginManagerPrivate::readPluginPaths() +{ + qDeleteAll(pluginSpecs); + pluginSpecs.clear(); + + QStringList specFiles; + QStringList searchPaths = pluginPaths; + while (!searchPaths.isEmpty()) { + const QDir dir(searchPaths.takeFirst()); + const QFileInfoList files = dir.entryInfoList(QStringList() << QString("*.%1").arg(extension), QDir::Files); + foreach (const QFileInfo &file, files) + specFiles << file.absoluteFilePath(); + const QFileInfoList dirs = dir.entryInfoList(QDir::Dirs|QDir::NoDotAndDotDot); + foreach (const QFileInfo &subdir, dirs) + searchPaths << subdir.absoluteFilePath(); + } + foreach (const QString &specFile, specFiles) { + PluginSpec *spec = new PluginSpec; + spec->d->read(specFile); + pluginSpecs.append(spec); + } + resolveDependencies(); + // ensure deterministic plugin load order by sorting + qSort(pluginSpecs.begin(), pluginSpecs.end(), lessThanByPluginName); + emit q->pluginsChanged(); +} + +void PluginManagerPrivate::resolveDependencies() +{ + foreach (PluginSpec *spec, pluginSpecs) { + spec->d->resolveDependencies(pluginSpecs); + } +} + + // Look in argument descriptions of the specs for the option. +PluginSpec *PluginManagerPrivate::pluginForOption(const QString &option, bool *requiresArgument) const +{ + // Look in the plugins for an option + typedef PluginSpec::PluginArgumentDescriptions PluginArgumentDescriptions; + + *requiresArgument = false; + const PluginSpecSet::const_iterator pcend = pluginSpecs.constEnd(); + for (PluginSpecSet::const_iterator pit = pluginSpecs.constBegin(); pit != pcend; ++pit) { + PluginSpec *ps = *pit; + const PluginArgumentDescriptions pargs = ps->argumentDescriptions(); + if (!pargs.empty()) { + const PluginArgumentDescriptions::const_iterator acend = pargs.constEnd(); + for (PluginArgumentDescriptions::const_iterator ait = pargs.constBegin(); ait != acend; ++ait) { + if (ait->name == option) { + *requiresArgument = !ait->parameter.isEmpty(); + return ps; + } + } + } + } + return 0; +} + +PluginSpec *PluginManagerPrivate::pluginByName(const QString &name) const +{ + foreach (PluginSpec *spec, pluginSpecs) + if (spec->name() == name) + return spec; + return 0; +} + diff --git a/ground/src/openpilotgcslibrary.pri b/ground/src/openpilotgcslibrary.pri index 223f99ebb..9aa6f00d2 100644 --- a/ground/src/openpilotgcslibrary.pri +++ b/ground/src/openpilotgcslibrary.pri @@ -10,7 +10,7 @@ include(rpath.pri) TARGET = $$qtLibraryTarget($$TARGET) -contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols +contains(QT_CONFIG, reduce_exports):CONFIG += hGCS_symbols !macx { win32 { diff --git a/ground/src/openpilotgcsplugin.pri b/ground/src/openpilotgcsplugin.pri index 220d5335c..139bc9a1a 100644 --- a/ground/src/openpilotgcsplugin.pri +++ b/ground/src/openpilotgcsplugin.pri @@ -32,13 +32,13 @@ macx { QMAKE_RPATHDIR += \$\$ORIGIN QMAKE_RPATHDIR += \$\$ORIGIN/.. QMAKE_RPATHDIR += \$\$ORIGIN/../.. - IDE_PLUGIN_RPATH = $$join(QMAKE_RPATHDIR, ":") - QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${IDE_PLUGIN_RPATH}\' + GCS_PLUGIN_RPATH = $$join(QMAKE_RPATHDIR, ":") + QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${GCS_PLUGIN_RPATH}\' QMAKE_RPATHDIR = } -contains(QT_CONFIG, reduce_exports):CONFIG += hide_symbols +contains(QT_CONFIG, reduce_exports):CONFIG += hGCS_symbols CONFIG += plugin plugin_with_soname diff --git a/ground/src/plugins/coreplugin/Core.pluginspec b/ground/src/plugins/coreplugin/Core.pluginspec index a47bd979d..72f71a872 100644 --- a/ground/src/plugins/coreplugin/Core.pluginspec +++ b/ground/src/plugins/coreplugin/Core.pluginspec @@ -1,4 +1,4 @@ - + The OpenPilot Project (C) 2010 OpenPilot Project diff --git a/ground/src/plugins/coreplugin/coreconstants.h b/ground/src/plugins/coreplugin/coreconstants.h index a391f8b72..644a6f3a3 100644 --- a/ground/src/plugins/coreplugin/coreconstants.h +++ b/ground/src/plugins/coreplugin/coreconstants.h @@ -1,228 +1,228 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://qt.nokia.com/contact. -** -**************************************************************************/ - -#ifndef CORECONSTANTS_H -#define CORECONSTANTS_H - -namespace Core { -namespace Constants { - -#define IDE_VERSION_MAJOR 1 -#define IDE_VERSION_MINOR 3 -#define IDE_VERSION_RELEASE 1 - -#define STRINGIFY_INTERNAL(x) #x -#define STRINGIFY(x) STRINGIFY_INTERNAL(x) - -#define IDE_VERSION STRINGIFY(IDE_VERSION_MAJOR) \ - "." STRINGIFY(IDE_VERSION_MINOR) \ - "." STRINGIFY(IDE_VERSION_RELEASE) - -const char * const IDE_VERSION_LONG = IDE_VERSION; -const char * const IDE_AUTHOR = "Nokia Corporation"; -const char * const IDE_YEAR = "2009"; - -#ifdef IDE_REVISION -const char * const IDE_REVISION_STR = STRINGIFY(IDE_REVISION); -#else -const char * const IDE_REVISION_STR = ""; -#endif - -#undef IDE_VERSION -#undef STRINGIFY -#undef STRINGIFY_INTERNAL - -//modes -const char * const MODE_WELCOME = "Welcome"; -const char * const MODE_EDIT = "Edit"; -const char * const MODE_OUTPUT = "Output"; -const int P_MODE_WELCOME = 100; -const int P_MODE_EDIT = 90; -const int P_MODE_OUTPUT = 10; - -//menubar -const char * const MENU_BAR = "QtCreator.MenuBar"; - -//menus -const char * const M_FILE = "QtCreator.Menu.File"; -const char * const M_FILE_OPEN = "QtCreator.Menu.File.Open"; -const char * const M_FILE_NEW = "QtCreator.Menu.File.New"; -const char * const M_FILE_RECENTFILES = "QtCreator.Menu.File.RecentFiles"; -const char * const M_EDIT = "QtCreator.Menu.Edit"; -const char * const M_EDIT_ADVANCED = "QtCreator.Menu.Edit.Advanced"; -const char * const M_TOOLS = "QtCreator.Menu.Tools"; -const char * const M_WINDOW = "QtCreator.Menu.Window"; -const char * const M_WINDOW_PANES = "QtCreator.Menu.Window.Panes"; -const char * const M_HELP = "QtCreator.Menu.Help"; - -//contexts -const char * const C_GLOBAL = "Global Context"; -const int C_GLOBAL_ID = 0; -const char * const C_WELCOME_MODE = "Core.WelcomeMode"; -const char * const C_EDIT_MODE = "Core.EditMode"; -const char * const C_EDITORMANAGER = "Core.EditorManager"; -const char * const C_NAVIGATION_PANE = "Core.NavigationPane"; -const char * const C_PROBLEM_PANE = "Core.ProblemPane"; - -//default editor kind -const char * const K_DEFAULT_TEXT_EDITOR = QT_TRANSLATE_NOOP("OpenWith::Editors", "Plain Text Editor"); -const char * const K_DEFAULT_BINARY_EDITOR = QT_TRANSLATE_NOOP("OpenWith::Editors", "Binary Editor"); - -//actions -const char * const UNDO = "QtCreator.Undo"; -const char * const REDO = "QtCreator.Redo"; -const char * const COPY = "QtCreator.Copy"; -const char * const PASTE = "QtCreator.Paste"; -const char * const CUT = "QtCreator.Cut"; -const char * const SELECTALL = "QtCreator.SelectAll"; - -const char * const GOTO = "QtCreator.Goto"; - -const char * const NEW = "QtCreator.New"; -const char * const OPEN = "QtCreator.Open"; -const char * const OPEN_WITH = "QtCreator.OpenWith"; -const char * const REVERTTOSAVED = "QtCreator.RevertToSaved"; -const char * const SAVE = "QtCreator.Save"; -const char * const SAVEAS = "QtCreator.SaveAs"; -const char * const SAVEALL = "QtCreator.SaveAll"; -const char * const PRINT = "QtCreator.Print"; -const char * const EXIT = "QtCreator.Exit"; - -const char * const OPTIONS = "QtCreator.Options"; -const char * const TOGGLE_SIDEBAR = "QtCreator.ToggleSidebar"; -const char * const TOGGLE_FULLSCREEN = "QtCreator.ToggleFullScreen"; - -const char * const MINIMIZE_WINDOW = "QtCreator.MinimizeWindow"; -const char * const ZOOM_WINDOW = "QtCreator.ZoomWindow"; - -const char * const SPLIT = "QtCreator.Split"; -const char * const SPLIT_SIDE_BY_SIDE = "QtCreator.SplitSideBySide"; -const char * const REMOVE_CURRENT_SPLIT = "QtCreator.RemoveCurrentSplit"; -const char * const REMOVE_ALL_SPLITS = "QtCreator.RemoveAllSplits"; -const char * const GOTO_OTHER_SPLIT = "QtCreator.GotoOtherSplit"; -const char * const SAVEASDEFAULT = "QtCreator.SaveAsDefaultLayout"; -const char * const RESTOREDEFAULT = "QtCreator.RestoreDefaultLayout"; -const char * const CLOSE = "QtCreator.Close"; -const char * const CLOSEALL = "QtCreator.CloseAll"; -const char * const CLOSEOTHERS = "QtCreator.CloseOthers"; -const char * const GOTONEXT = "QtCreator.GotoNext"; -const char * const GOTOPREV = "QtCreator.GotoPrevious"; -const char * const GOTONEXTINHISTORY = "QtCreator.GotoNextInHistory"; -const char * const GOTOPREVINHISTORY = "QtCreator.GotoPreviousInHistory"; -const char * const GO_BACK = "QtCreator.GoBack"; -const char * const GO_FORWARD = "QtCreator.GoForward"; -const char * const GOTOPREVIOUSGROUP = "QtCreator.GotoPreviousTabGroup"; -const char * const GOTONEXTGROUP = "QtCreator.GotoNextTabGroup"; -const char * const WINDOWSLIST = "QtCreator.WindowsList"; -const char * const ABOUT_QTCREATOR = "QtCreator.AboutQtCreator"; -const char * const ABOUT_PLUGINS = "QtCreator.AboutPlugins"; -const char * const ABOUT_QT = "QtCreator.AboutQt"; -const char * const S_RETURNTOEDITOR = "QtCreator.ReturnToEditor"; -const char * const OPEN_IN_EXTERNAL_EDITOR = "QtCreator.OpenInExternalEditor"; - -// default groups -const char * const G_DEFAULT_ONE = "QtCreator.Group.Default.One"; -const char * const G_DEFAULT_TWO = "QtCreator.Group.Default.Two"; -const char * const G_DEFAULT_THREE = "QtCreator.Group.Default.Three"; - -// main menu bar groups -const char * const G_FILE = "QtCreator.Group.File"; -const char * const G_EDIT = "QtCreator.Group.Edit"; -const char * const G_VIEW = "QtCreator.Group.View"; -const char * const G_TOOLS = "QtCreator.Group.Tools"; -const char * const G_WINDOW = "QtCreator.Group.Window"; -const char * const G_HELP = "QtCreator.Group.Help"; - -// file menu groups -const char * const G_FILE_NEW = "QtCreator.Group.File.New"; -const char * const G_FILE_OPEN = "QtCreator.Group.File.Open"; -const char * const G_FILE_PROJECT = "QtCreator.Group.File.Project"; -const char * const G_FILE_SAVE = "QtCreator.Group.File.Save"; -const char * const G_FILE_CLOSE = "QtCreator.Group.File.Close"; -const char * const G_FILE_PRINT = "QtCreator.Group.File.Print"; -const char * const G_FILE_OTHER = "QtCreator.Group.File.Other"; - -// edit menu groups -const char * const G_EDIT_UNDOREDO = "QtCreator.Group.Edit.UndoRedo"; -const char * const G_EDIT_COPYPASTE = "QtCreator.Group.Edit.CopyPaste"; -const char * const G_EDIT_SELECTALL = "QtCreator.Group.Edit.SelectAll"; -const char * const G_EDIT_ADVANCED = "QtCreator.Group.Edit.Advanced"; - -const char * const G_EDIT_FIND = "QtCreator.Group.Edit.Find"; -const char * const G_EDIT_OTHER = "QtCreator.Group.Edit.Other"; - -// advanced edit menu groups - -const char * const G_EDIT_FORMAT = "QtCreator.Group.Edit.Format"; -const char * const G_EDIT_COLLAPSING = "QtCreator.Group.Edit.Collapsing"; -const char * const G_EDIT_BLOCKS = "QtCreator.Group.Edit.Blocks"; -const char * const G_EDIT_FONT = "QtCreator.Group.Edit.Font"; -const char * const G_EDIT_EDITOR = "QtCreator.Group.Edit.Editor"; - -// window menu groups -const char * const G_WINDOW_SIZE = "QtCreator.Group.Window.Size"; -const char * const G_WINDOW_PANES = "QtCreator.Group.Window.Panes"; -const char * const G_WINDOW_SPLIT = "QtCreator.Group.Window.Split"; -const char * const G_WINDOW_NAVIGATE = "QtCreator.Group.Window.Navigate"; -const char * const G_WINDOW_OTHER = "QtCreator.Group.Window.Other"; - -// help groups (global) -const char * const G_HELP_HELP = "QtCreator.Group.Help.Help"; -const char * const G_HELP_ABOUT = "QtCreator.Group.Help.About"; - -const char * const ICON_MINUS = ":/core/images/minus.png"; -const char * const ICON_PLUS = ":/core/images/plus.png"; -const char * const ICON_NEWFILE = ":/core/images/filenew.png"; -const char * const ICON_OPENFILE = ":/core/images/fileopen.png"; -const char * const ICON_SAVEFILE = ":/core/images/filesave.png"; -const char * const ICON_UNDO = ":/core/images/undo.png"; -const char * const ICON_REDO = ":/core/images/redo.png"; -const char * const ICON_COPY = ":/core/images/editcopy.png"; -const char * const ICON_PASTE = ":/core/images/editpaste.png"; -const char * const ICON_CUT = ":/core/images/editcut.png"; -const char * const ICON_NEXT = ":/core/images/next.png"; -const char * const ICON_PREV = ":/core/images/prev.png"; -const char * const ICON_DIR = ":/core/images/dir.png"; -const char * const ICON_CLEAN_PANE = ":/core/images/clean_pane_small.png"; -const char * const ICON_CLEAR = ":/core/images/clear.png"; -const char * const ICON_FIND = ":/core/images/find.png"; -const char * const ICON_FINDNEXT = ":/core/images/findnext.png"; -const char * const ICON_REPLACE = ":/core/images/replace.png"; -const char * const ICON_RESET = ":/core/images/reset.png"; -const char * const ICON_MAGNIFIER = ":/core/images/magnifier.png"; -const char * const ICON_TOGGLE_SIDEBAR = ":/core/images/sidebaricon.png"; - -// wizard kind -const char * const WIZARD_TYPE_FILE = "QtCreator::WizardType::File"; -const char * const WIZARD_TYPE_CLASS = "QtCreator::WizardType::Class"; - -} // namespace Constants -} // namespace Core - -#endif // CORECONSTANTS_H +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#ifndef CORECONSTANTS_H +#define CORECONSTANTS_H + +namespace Core { +namespace Constants { + +#define GCS_VERSION_MAJOR 1 +#define GCS_VERSION_MINOR 3 +#define GCS_VERSION_RELEASE 1 + +#define STRINGIFY_INTERNAL(x) #x +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) + +#define GCS_VERSION STRINGIFY(GCS_VERSION_MAJOR) \ + "." STRINGIFY(GCS_VERSION_MINOR) \ + "." STRINGIFY(GCS_VERSION_RELEASE) + +const char * const GCS_VERSION_LONG = GCS_VERSION; +const char * const GCS_AUTHOR = "Nokia Corporation"; +const char * const GCS_YEAR = "2009"; + +#ifdef GCS_REVISION +const char * const GCS_REVISION_STR = STRINGIFY(GCS_REVISION); +#else +const char * const GCS_REVISION_STR = ""; +#endif + +#undef GCS_VERSION +#undef STRINGIFY +#undef STRINGIFY_INTERNAL + +//modes +const char * const MODE_WELCOME = "Welcome"; +const char * const MODE_EDIT = "Edit"; +const char * const MODE_OUTPUT = "Output"; +const int P_MODE_WELCOME = 100; +const int P_MODE_EDIT = 90; +const int P_MODE_OUTPUT = 10; + +//menubar +const char * const MENU_BAR = "QtCreator.MenuBar"; + +//menus +const char * const M_FILE = "QtCreator.Menu.File"; +const char * const M_FILE_OPEN = "QtCreator.Menu.File.Open"; +const char * const M_FILE_NEW = "QtCreator.Menu.File.New"; +const char * const M_FILE_RECENTFILES = "QtCreator.Menu.File.RecentFiles"; +const char * const M_EDIT = "QtCreator.Menu.Edit"; +const char * const M_EDIT_ADVANCED = "QtCreator.Menu.Edit.Advanced"; +const char * const M_TOOLS = "QtCreator.Menu.Tools"; +const char * const M_WINDOW = "QtCreator.Menu.Window"; +const char * const M_WINDOW_PANES = "QtCreator.Menu.Window.Panes"; +const char * const M_HELP = "QtCreator.Menu.Help"; + +//contexts +const char * const C_GLOBAL = "Global Context"; +const int C_GLOBAL_ID = 0; +const char * const C_WELCOME_MODE = "Core.WelcomeMode"; +const char * const C_EDIT_MODE = "Core.EditMode"; +const char * const C_EDITORMANAGER = "Core.EditorManager"; +const char * const C_NAVIGATION_PANE = "Core.NavigationPane"; +const char * const C_PROBLEM_PANE = "Core.ProblemPane"; + +//default editor kind +const char * const K_DEFAULT_TEXT_EDITOR = QT_TRANSLATE_NOOP("OpenWith::Editors", "Plain Text Editor"); +const char * const K_DEFAULT_BINARY_EDITOR = QT_TRANSLATE_NOOP("OpenWith::Editors", "Binary Editor"); + +//actions +const char * const UNDO = "QtCreator.Undo"; +const char * const REDO = "QtCreator.Redo"; +const char * const COPY = "QtCreator.Copy"; +const char * const PASTE = "QtCreator.Paste"; +const char * const CUT = "QtCreator.Cut"; +const char * const SELECTALL = "QtCreator.SelectAll"; + +const char * const GOTO = "QtCreator.Goto"; + +const char * const NEW = "QtCreator.New"; +const char * const OPEN = "QtCreator.Open"; +const char * const OPEN_WITH = "QtCreator.OpenWith"; +const char * const REVERTTOSAVED = "QtCreator.RevertToSaved"; +const char * const SAVE = "QtCreator.Save"; +const char * const SAVEAS = "QtCreator.SaveAs"; +const char * const SAVEALL = "QtCreator.SaveAll"; +const char * const PRINT = "QtCreator.Print"; +const char * const EXIT = "QtCreator.Exit"; + +const char * const OPTIONS = "QtCreator.Options"; +const char * const TOGGLE_SIDEBAR = "QtCreator.ToggleSidebar"; +const char * const TOGGLE_FULLSCREEN = "QtCreator.ToggleFullScreen"; + +const char * const MINIMIZE_WINDOW = "QtCreator.MinimizeWindow"; +const char * const ZOOM_WINDOW = "QtCreator.ZoomWindow"; + +const char * const SPLIT = "QtCreator.Split"; +const char * const SPLIT_SGCS_BY_SIDE = "QtCreator.SplitSideBySide"; +const char * const REMOVE_CURRENT_SPLIT = "QtCreator.RemoveCurrentSplit"; +const char * const REMOVE_ALL_SPLITS = "QtCreator.RemoveAllSplits"; +const char * const GOTO_OTHER_SPLIT = "QtCreator.GotoOtherSplit"; +const char * const SAVEASDEFAULT = "QtCreator.SaveAsDefaultLayout"; +const char * const RESTOREDEFAULT = "QtCreator.RestoreDefaultLayout"; +const char * const CLOSE = "QtCreator.Close"; +const char * const CLOSEALL = "QtCreator.CloseAll"; +const char * const CLOSEOTHERS = "QtCreator.CloseOthers"; +const char * const GOTONEXT = "QtCreator.GotoNext"; +const char * const GOTOPREV = "QtCreator.GotoPrevious"; +const char * const GOTONEXTINHISTORY = "QtCreator.GotoNextInHistory"; +const char * const GOTOPREVINHISTORY = "QtCreator.GotoPreviousInHistory"; +const char * const GO_BACK = "QtCreator.GoBack"; +const char * const GO_FORWARD = "QtCreator.GoForward"; +const char * const GOTOPREVIOUSGROUP = "QtCreator.GotoPreviousTabGroup"; +const char * const GOTONEXTGROUP = "QtCreator.GotoNextTabGroup"; +const char * const WINDOWSLIST = "QtCreator.WindowsList"; +const char * const ABOUT_QTCREATOR = "QtCreator.AboutQtCreator"; +const char * const ABOUT_PLUGINS = "QtCreator.AboutPlugins"; +const char * const ABOUT_QT = "QtCreator.AboutQt"; +const char * const S_RETURNTOEDITOR = "QtCreator.ReturnToEditor"; +const char * const OPEN_IN_EXTERNAL_EDITOR = "QtCreator.OpenInExternalEditor"; + +// default groups +const char * const G_DEFAULT_ONE = "QtCreator.Group.Default.One"; +const char * const G_DEFAULT_TWO = "QtCreator.Group.Default.Two"; +const char * const G_DEFAULT_THREE = "QtCreator.Group.Default.Three"; + +// main menu bar groups +const char * const G_FILE = "QtCreator.Group.File"; +const char * const G_EDIT = "QtCreator.Group.Edit"; +const char * const G_VIEW = "QtCreator.Group.View"; +const char * const G_TOOLS = "QtCreator.Group.Tools"; +const char * const G_WINDOW = "QtCreator.Group.Window"; +const char * const G_HELP = "QtCreator.Group.Help"; + +// file menu groups +const char * const G_FILE_NEW = "QtCreator.Group.File.New"; +const char * const G_FILE_OPEN = "QtCreator.Group.File.Open"; +const char * const G_FILE_PROJECT = "QtCreator.Group.File.Project"; +const char * const G_FILE_SAVE = "QtCreator.Group.File.Save"; +const char * const G_FILE_CLOSE = "QtCreator.Group.File.Close"; +const char * const G_FILE_PRINT = "QtCreator.Group.File.Print"; +const char * const G_FILE_OTHER = "QtCreator.Group.File.Other"; + +// edit menu groups +const char * const G_EDIT_UNDOREDO = "QtCreator.Group.Edit.UndoRedo"; +const char * const G_EDIT_COPYPASTE = "QtCreator.Group.Edit.CopyPaste"; +const char * const G_EDIT_SELECTALL = "QtCreator.Group.Edit.SelectAll"; +const char * const G_EDIT_ADVANCED = "QtCreator.Group.Edit.Advanced"; + +const char * const G_EDIT_FIND = "QtCreator.Group.Edit.Find"; +const char * const G_EDIT_OTHER = "QtCreator.Group.Edit.Other"; + +// advanced edit menu groups + +const char * const G_EDIT_FORMAT = "QtCreator.Group.Edit.Format"; +const char * const G_EDIT_COLLAPSING = "QtCreator.Group.Edit.Collapsing"; +const char * const G_EDIT_BLOCKS = "QtCreator.Group.Edit.Blocks"; +const char * const G_EDIT_FONT = "QtCreator.Group.Edit.Font"; +const char * const G_EDIT_EDITOR = "QtCreator.Group.Edit.Editor"; + +// window menu groups +const char * const G_WINDOW_SIZE = "QtCreator.Group.Window.Size"; +const char * const G_WINDOW_PANES = "QtCreator.Group.Window.Panes"; +const char * const G_WINDOW_SPLIT = "QtCreator.Group.Window.Split"; +const char * const G_WINDOW_NAVIGATE = "QtCreator.Group.Window.Navigate"; +const char * const G_WINDOW_OTHER = "QtCreator.Group.Window.Other"; + +// help groups (global) +const char * const G_HELP_HELP = "QtCreator.Group.Help.Help"; +const char * const G_HELP_ABOUT = "QtCreator.Group.Help.About"; + +const char * const ICON_MINUS = ":/core/images/minus.png"; +const char * const ICON_PLUS = ":/core/images/plus.png"; +const char * const ICON_NEWFILE = ":/core/images/filenew.png"; +const char * const ICON_OPENFILE = ":/core/images/fileopen.png"; +const char * const ICON_SAVEFILE = ":/core/images/filesave.png"; +const char * const ICON_UNDO = ":/core/images/undo.png"; +const char * const ICON_REDO = ":/core/images/redo.png"; +const char * const ICON_COPY = ":/core/images/editcopy.png"; +const char * const ICON_PASTE = ":/core/images/editpaste.png"; +const char * const ICON_CUT = ":/core/images/editcut.png"; +const char * const ICON_NEXT = ":/core/images/next.png"; +const char * const ICON_PREV = ":/core/images/prev.png"; +const char * const ICON_DIR = ":/core/images/dir.png"; +const char * const ICON_CLEAN_PANE = ":/core/images/clean_pane_small.png"; +const char * const ICON_CLEAR = ":/core/images/clear.png"; +const char * const ICON_FIND = ":/core/images/find.png"; +const char * const ICON_FINDNEXT = ":/core/images/findnext.png"; +const char * const ICON_REPLACE = ":/core/images/replace.png"; +const char * const ICON_RESET = ":/core/images/reset.png"; +const char * const ICON_MAGNIFIER = ":/core/images/magnifier.png"; +const char * const ICON_TOGGLE_SIDEBAR = ":/core/images/sidebaricon.png"; + +// wizard kind +const char * const WIZARD_TYPE_FILE = "QtCreator::WizardType::File"; +const char * const WIZARD_TYPE_CLASS = "QtCreator::WizardType::Class"; + +} // namespace Constants +} // namespace Core + +#endif // CORECONSTANTS_H diff --git a/ground/src/plugins/coreplugin/editormanager/editormanager.cpp b/ground/src/plugins/coreplugin/editormanager/editormanager.cpp index 21f032904..cf5da8bf1 100644 --- a/ground/src/plugins/coreplugin/editormanager/editormanager.cpp +++ b/ground/src/plugins/coreplugin/editormanager/editormanager.cpp @@ -1,1937 +1,1937 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://qt.nokia.com/contact. -** -**************************************************************************/ - -#include "editormanager.h" -#include "editorview.h" -#include "openeditorswindow.h" -#include "openeditorsview.h" -#include "openeditorsmodel.h" -#include "openwithdialog.h" -#include "filemanager.h" -#include "icore.h" -#include "iversioncontrol.h" -#include "mimedatabase.h" -#include "tabpositionindicator.h" -#include "vcsmanager.h" - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -Q_DECLARE_METATYPE(Core::IEditor*) - -using namespace Core; -using namespace Core::Internal; -using namespace Utils; - -enum { debugEditorManager=0 }; - -static inline ExtensionSystem::PluginManager *pluginManager() -{ - return ExtensionSystem::PluginManager::instance(); -} - -//===================EditorManager===================== - -EditorManagerPlaceHolder *EditorManagerPlaceHolder::m_current = 0; - -EditorManagerPlaceHolder::EditorManagerPlaceHolder(Core::IMode *mode, QWidget *parent) - : QWidget(parent), m_mode(mode) -{ - setLayout(new QVBoxLayout); - layout()->setMargin(0); - connect(Core::ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode *)), - this, SLOT(currentModeChanged(Core::IMode *))); - - currentModeChanged(Core::ModeManager::instance()->currentMode()); -} - -EditorManagerPlaceHolder::~EditorManagerPlaceHolder() -{ - if (m_current == this) { - EditorManager::instance()->setParent(0); - EditorManager::instance()->hide(); - } -} - -void EditorManagerPlaceHolder::currentModeChanged(Core::IMode *mode) -{ - if (m_current == this) { - m_current = 0; - EditorManager::instance()->setParent(0); - EditorManager::instance()->hide(); - } - if (m_mode == mode) { - m_current = this; - layout()->addWidget(EditorManager::instance()); - EditorManager::instance()->show(); - } -} - -EditorManagerPlaceHolder* EditorManagerPlaceHolder::current() -{ - return m_current; -} - -// ---------------- EditorManager - -namespace Core { - - -struct EditorManagerPrivate { - explicit EditorManagerPrivate(ICore *core, QWidget *parent); - ~EditorManagerPrivate(); - Internal::EditorView *m_view; - Internal::SplitterOrView *m_splitter; - QPointer m_currentEditor; - QPointer m_currentView; - - ICore *m_core; - - - // actions - QAction *m_revertToSavedAction; - QAction *m_saveAction; - QAction *m_saveAsAction; - QAction *m_closeCurrentEditorAction; - QAction *m_closeAllEditorsAction; - QAction *m_closeOtherEditorsAction; - QAction *m_gotoNextDocHistoryAction; - QAction *m_gotoPreviousDocHistoryAction; - QAction *m_goBackAction; - QAction *m_goForwardAction; - QAction *m_openInExternalEditorAction; - QAction *m_splitAction; - QAction *m_splitSideBySideAction; - QAction *m_removeCurrentSplitAction; - QAction *m_removeAllSplitsAction; - QAction *m_gotoOtherSplitAction; - - Internal::OpenEditorsWindow *m_windowPopup; - Core::BaseView *m_openEditorsView; - Internal::EditorClosingCoreListener *m_coreListener; - - QMap m_editorStates; - Internal::OpenEditorsViewFactory *m_openEditorsFactory; - - QString fileFilters; - QString selectedFilter; - - OpenEditorsModel *m_editorModel; - QString m_externalEditor; - - IFile::ReloadBehavior m_reloadBehavior; -}; -} - -EditorManagerPrivate::EditorManagerPrivate(ICore *core, QWidget *parent) : - m_view(0), - m_splitter(0), - m_core(core), - m_revertToSavedAction(new QAction(EditorManager::tr("Revert to Saved"), parent)), - m_saveAction(new QAction(parent)), - m_saveAsAction(new QAction(parent)), - m_closeCurrentEditorAction(new QAction(EditorManager::tr("Close"), parent)), - m_closeAllEditorsAction(new QAction(EditorManager::tr("Close All"), parent)), - m_closeOtherEditorsAction(new QAction(EditorManager::tr("Close Others"), parent)), - m_gotoNextDocHistoryAction(new QAction(EditorManager::tr("Next Open Document in History"), parent)), - m_gotoPreviousDocHistoryAction(new QAction(EditorManager::tr("Previous Open Document in History"), parent)), - m_goBackAction(new QAction(QIcon(QLatin1String(":/help/images/previous.png")), EditorManager::tr("Go Back"), parent)), - m_goForwardAction(new QAction(QIcon(QLatin1String(":/help/images/next.png")), EditorManager::tr("Go Forward"), parent)), - m_openInExternalEditorAction(new QAction(EditorManager::tr("Open in External Editor"), parent)), - m_windowPopup(0), - m_coreListener(0), - m_reloadBehavior(IFile::AskForReload) -{ - m_editorModel = new OpenEditorsModel(parent); -} - -EditorManagerPrivate::~EditorManagerPrivate() -{ -// clearNavigationHistory(); -} - -EditorManager *EditorManager::m_instance = 0; - -static Command *createSeparator(ActionManager *am, QObject *parent, - const QString &name, - const QList &context) -{ - QAction *tmpaction = new QAction(parent); - tmpaction->setSeparator(true); - Command *cmd = am->registerAction(tmpaction, name, context); - return cmd; -} - -EditorManager::EditorManager(ICore *core, QWidget *parent) : - QWidget(parent), - m_d(new EditorManagerPrivate(core, parent)) -{ - m_instance = this; - - connect(m_d->m_core, SIGNAL(contextAboutToChange(Core::IContext *)), - this, SLOT(handleContextChange(Core::IContext *))); - - const QList gc = QList() << Constants::C_GLOBAL_ID; - const QList editManagerContext = - QList() << m_d->m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_EDITORMANAGER); - - ActionManager *am = m_d->m_core->actionManager(); - ActionContainer *mfile = am->actionContainer(Constants::M_FILE); - - //Revert to saved - Command *cmd = am->registerAction(m_d->m_revertToSavedAction, - Constants::REVERTTOSAVED, editManagerContext); - cmd->setAttribute(Command::CA_UpdateText); - cmd->setDefaultText(tr("Revert File to Saved")); - mfile->addAction(cmd, Constants::G_FILE_SAVE); - connect(m_d->m_revertToSavedAction, SIGNAL(triggered()), this, SLOT(revertToSaved())); - - //Save Action - am->registerAction(m_d->m_saveAction, Constants::SAVE, editManagerContext); - connect(m_d->m_saveAction, SIGNAL(triggered()), this, SLOT(saveFile())); - - //Save As Action - am->registerAction(m_d->m_saveAsAction, Constants::SAVEAS, editManagerContext); - connect(m_d->m_saveAsAction, SIGNAL(triggered()), this, SLOT(saveFileAs())); - - //Window Menu - ActionContainer *mwindow = am->actionContainer(Constants::M_WINDOW); - - //Window menu separators - QAction *tmpaction = new QAction(this); - tmpaction->setSeparator(true); - cmd = am->registerAction(tmpaction, QLatin1String("QtCreator.Window.Sep.Split"), editManagerContext); - mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); - - tmpaction = new QAction(this); - tmpaction->setSeparator(true); - cmd = am->registerAction(tmpaction, QLatin1String("QtCreator.Window.Sep.Navigate"), editManagerContext); - mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE); - - //Close Action - cmd = am->registerAction(m_d->m_closeCurrentEditorAction, Constants::CLOSE, editManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+W"))); - cmd->setAttribute(Core::Command::CA_UpdateText); - cmd->setDefaultText(m_d->m_closeCurrentEditorAction->text()); - mfile->addAction(cmd, Constants::G_FILE_CLOSE); - connect(m_d->m_closeCurrentEditorAction, SIGNAL(triggered()), this, SLOT(closeEditor())); - - //Close All Action - cmd = am->registerAction(m_d->m_closeAllEditorsAction, Constants::CLOSEALL, editManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+W"))); - mfile->addAction(cmd, Constants::G_FILE_CLOSE); - connect(m_d->m_closeAllEditorsAction, SIGNAL(triggered()), this, SLOT(closeAllEditors())); - - //Close All Others Action - cmd = am->registerAction(m_d->m_closeOtherEditorsAction, Constants::CLOSEOTHERS, editManagerContext); - mfile->addAction(cmd, Constants::G_FILE_CLOSE); - cmd->setAttribute(Core::Command::CA_UpdateText); - connect(m_d->m_closeOtherEditorsAction, SIGNAL(triggered()), this, SLOT(closeOtherEditors())); - - // Goto Previous In History Action - cmd = am->registerAction(m_d->m_gotoPreviousDocHistoryAction, Constants::GOTOPREVINHISTORY, editManagerContext); -#ifdef Q_WS_MAC - cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Tab"))); -#else - cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Tab"))); -#endif - mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE); - connect(m_d->m_gotoPreviousDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoPreviousDocHistory())); - - // Goto Next In History Action - cmd = am->registerAction(m_d->m_gotoNextDocHistoryAction, Constants::GOTONEXTINHISTORY, editManagerContext); -#ifdef Q_WS_MAC - cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Shift+Tab"))); -#else - cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+Tab"))); -#endif - mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE); - connect(m_d->m_gotoNextDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoNextDocHistory())); - - // Go back in navigation history - cmd = am->registerAction(m_d->m_goBackAction, Constants::GO_BACK, editManagerContext); -#ifdef Q_WS_MAC - cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Left"))); -#else - cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Left"))); -#endif - mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE); - connect(m_d->m_goBackAction, SIGNAL(triggered()), this, SLOT(goBackInNavigationHistory())); - - // Go forward in navigation history - cmd = am->registerAction(m_d->m_goForwardAction, Constants::GO_FORWARD, editManagerContext); -#ifdef Q_WS_MAC - cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Right"))); -#else - cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Right"))); -#endif - mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE); - connect(m_d->m_goForwardAction, SIGNAL(triggered()), this, SLOT(goForwardInNavigationHistory())); - -#ifdef Q_WS_MAC - QString prefix = tr("Meta+E"); -#else - QString prefix = tr("Ctrl+E"); -#endif - - m_d->m_splitAction = new QAction(tr("Split"), this); - cmd = am->registerAction(m_d->m_splitAction, Constants::SPLIT, editManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("%1,2").arg(prefix))); - mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); - connect(m_d->m_splitAction, SIGNAL(triggered()), this, SLOT(split())); - - m_d->m_splitSideBySideAction = new QAction(tr("Split Side by Side"), this); - cmd = am->registerAction(m_d->m_splitSideBySideAction, Constants::SPLIT_SIDE_BY_SIDE, editManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("%1,3").arg(prefix))); - mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); - connect(m_d->m_splitSideBySideAction, SIGNAL(triggered()), this, SLOT(splitSideBySide())); - - m_d->m_removeCurrentSplitAction = new QAction(tr("Remove Current Split"), this); - cmd = am->registerAction(m_d->m_removeCurrentSplitAction, Constants::REMOVE_CURRENT_SPLIT, editManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("%1,0").arg(prefix))); - mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); - connect(m_d->m_removeCurrentSplitAction, SIGNAL(triggered()), this, SLOT(removeCurrentSplit())); - - m_d->m_removeAllSplitsAction = new QAction(tr("Remove All Splits"), this); - cmd = am->registerAction(m_d->m_removeAllSplitsAction, Constants::REMOVE_ALL_SPLITS, editManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("%1,1").arg(prefix))); - mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); - connect(m_d->m_removeAllSplitsAction, SIGNAL(triggered()), this, SLOT(removeAllSplits())); - - m_d->m_gotoOtherSplitAction = new QAction(tr("Goto Other Split"), this); - cmd = am->registerAction(m_d->m_gotoOtherSplitAction, Constants::GOTO_OTHER_SPLIT, editManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("%1,o").arg(prefix))); - mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); - connect(m_d->m_gotoOtherSplitAction, SIGNAL(triggered()), this, SLOT(gotoOtherSplit())); - - ActionContainer *medit = am->actionContainer(Constants::M_EDIT); - ActionContainer *advancedMenu = am->createMenu(Constants::M_EDIT_ADVANCED); - medit->addMenu(advancedMenu, Constants::G_EDIT_ADVANCED); - advancedMenu->menu()->setTitle(tr("&Advanced")); - advancedMenu->appendGroup(Constants::G_EDIT_FORMAT); - advancedMenu->appendGroup(Constants::G_EDIT_COLLAPSING); - advancedMenu->appendGroup(Constants::G_EDIT_BLOCKS); - advancedMenu->appendGroup(Constants::G_EDIT_FONT); - advancedMenu->appendGroup(Constants::G_EDIT_EDITOR); - - // Advanced menu separators - cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Collapsing"), editManagerContext); - advancedMenu->addAction(cmd, Constants::G_EDIT_COLLAPSING); - cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Blocks"), editManagerContext); - advancedMenu->addAction(cmd, Constants::G_EDIT_BLOCKS); - cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Font"), editManagerContext); - advancedMenu->addAction(cmd, Constants::G_EDIT_FONT); - cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Editor"), editManagerContext); - advancedMenu->addAction(cmd, Constants::G_EDIT_EDITOR); - - cmd = am->registerAction(m_d->m_openInExternalEditorAction, Constants::OPEN_IN_EXTERNAL_EDITOR, editManagerContext); - cmd->setDefaultKeySequence(QKeySequence(tr("Alt+V,Alt+I"))); - advancedMenu->addAction(cmd, Constants::G_EDIT_EDITOR); - connect(m_d->m_openInExternalEditorAction, SIGNAL(triggered()), this, SLOT(openInExternalEditor())); - - // Connect to VariableManager for CURRENT_DOCUMENT variable setting - VariableManager *vm = VariableManager::instance(); - connect(this, SIGNAL(currentEditorChanged(Core::IEditor *)), - vm, SLOT(updateCurrentDocument(Core::IEditor *))); - - - // other setup - m_d->m_splitter = new SplitterOrView(m_d->m_editorModel); - m_d->m_view = m_d->m_splitter->view(); - - - QHBoxLayout *layout = new QHBoxLayout(this); - layout->setMargin(0); - layout->setSpacing(0); - layout->addWidget(m_d->m_splitter); - - updateActions(); - - m_d->m_windowPopup = new OpenEditorsWindow(this); -} - -EditorManager::~EditorManager() -{ - if (m_d->m_core) { - ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); - if (m_d->m_coreListener) { - pm->removeObject(m_d->m_coreListener); - delete m_d->m_coreListener; - } - pm->removeObject(m_d->m_openEditorsFactory); - delete m_d->m_openEditorsFactory; - } - delete m_d; -} - -void EditorManager::init() -{ - QList context; - context << m_d->m_core->uniqueIDManager()->uniqueIdentifier("QtCreator.OpenDocumentsView"); - - m_d->m_coreListener = new EditorClosingCoreListener(this); - - pluginManager()->addObject(m_d->m_coreListener); - - m_d->m_openEditorsFactory = new OpenEditorsViewFactory(); - pluginManager()->addObject(m_d->m_openEditorsFactory); -} - -QString EditorManager::defaultExternalEditor() const -{ -#ifdef Q_OS_UNIX - return ConsoleProcess::defaultTerminalEmulator() + QLatin1String( -# ifdef Q_OS_MAC - " -async" -# endif - " -geom %Wx%H+%x+%y -e vi %f +%l +\"normal %c|\""); -#else - return QLatin1String("notepad %f"); -#endif -} - -void EditorManager::removeEditor(IEditor *editor) -{ - bool isDuplicate = m_d->m_editorModel->isDuplicate(editor); - m_d->m_editorModel->removeEditor(editor); - if (!isDuplicate) { - m_d->m_core->fileManager()->removeFile(editor->file()); - } - m_d->m_core->removeContextObject(editor); -} - -void EditorManager::handleContextChange(Core::IContext *context) -{ - if (debugEditorManager) - qDebug() << Q_FUNC_INFO; - IEditor *editor = context ? qobject_cast(context) : 0; - if (editor) { - setCurrentEditor(editor); - } else { - updateActions(); - } -} - -void EditorManager::setCurrentEditor(IEditor *editor, bool ignoreNavigationHistory) -{ - if (editor) - setCurrentView(0); - - if (m_d->m_currentEditor == editor) - return; - if (m_d->m_currentEditor && !ignoreNavigationHistory) - addCurrentPositionToNavigationHistory(); - - m_d->m_currentEditor = editor; - if (editor) { - if (SplitterOrView *splitterOrView = m_d->m_splitter->findView(editor)) - splitterOrView->view()->setCurrentEditor(editor); - m_d->m_view->updateEditorHistory(editor); // the global view should have a complete history - } - updateActions(); - emit currentEditorChanged(editor); -} - - -void EditorManager::setCurrentView(Core::Internal::SplitterOrView *view) -{ - if (view == m_d->m_currentView) - return; - - SplitterOrView *old = m_d->m_currentView; - m_d->m_currentView = view; - - if (old) - old->update(); - if (view) - view->update(); - - if (view && !view->editor()) - view->setFocus(); -} - -Core::Internal::SplitterOrView *EditorManager::currentSplitterOrView() const -{ - SplitterOrView *view = m_d->m_currentView; - if (!view) - view = m_d->m_currentEditor? - m_d->m_splitter->findView(m_d->m_currentEditor): - m_d->m_splitter->findFirstView(); - if (!view) - return m_d->m_splitter; - return view; -} - -Core::Internal::EditorView *EditorManager::currentEditorView() const -{ - return currentSplitterOrView()->view(); -} - - - -QList EditorManager::editorsForFileName(const QString &filename) const -{ - QList found; - QString fixedname = FileManager::fixFileName(filename); - foreach (IEditor *editor, openedEditors()) { - if (fixedname == FileManager::fixFileName(editor->file()->fileName())) - found << editor; - } - return found; -} - -QList EditorManager::editorsForFile(IFile *file) const -{ - QList found; - foreach (IEditor *editor, openedEditors()) { - if (editor->file() == file) - found << editor; - } - return found; -} - -IEditor *EditorManager::currentEditor() const -{ - return m_d->m_currentEditor; -} - -void EditorManager::emptyView(Core::Internal::EditorView *view) -{ - if (!view) - return; - - QList editors = view->editors(); - foreach (IEditor *editor, editors) { - if (!m_d->m_editorModel->isDuplicate(editor)) { - editors.removeAll(editor); - view->removeEditor(editor); - continue; - } - emit editorAboutToClose(editor); - removeEditor(editor); - view->removeEditor(editor); - } - emit editorsClosed(editors); - foreach (IEditor *editor, editors) { - delete editor; - } -} - -void EditorManager::closeView(Core::Internal::EditorView *view) -{ - if (!view) - return; - - if (view == m_d->m_view) { - if (IEditor *e = view->currentEditor()) - closeEditors(QList() << e); - return; - } - - emptyView(view); - - SplitterOrView *splitterOrView = m_d->m_splitter->findView(view); - Q_ASSERT(splitterOrView); - Q_ASSERT(splitterOrView->view() == view); - SplitterOrView *splitter = m_d->m_splitter->findSplitter(splitterOrView); - Q_ASSERT(splitterOrView->hasEditors() == false); - splitterOrView->hide(); - delete splitterOrView; - - splitter->unsplit(); - - SplitterOrView *newCurrent = splitter->findFirstView(); - if (newCurrent) { - if (newCurrent->editor()) - activateEditor(newCurrent->view(), newCurrent->editor()); - else - setCurrentView(newCurrent); - } -} - -QList - EditorManager::editorsForFiles(QList files) const -{ - const QList editors = openedEditors(); - QSet found; - foreach (IFile *file, files) { - foreach (IEditor *editor, editors) { - if (editor->file() == file && !found.contains(editor)) { - found << editor; - } - } - } - return found.toList(); -} - -QList EditorManager::filesForEditors(QList editors) const -{ - QSet handledEditors; - QList files; - foreach (IEditor *editor, editors) { - if (!handledEditors.contains(editor)) { - files << editor->file(); - handledEditors.insert(editor); - } - } - return files; -} - -bool EditorManager::closeAllEditors(bool askAboutModifiedEditors) -{ - m_d->m_editorModel->removeAllRestoredEditors(); - if (closeEditors(openedEditors(), askAboutModifiedEditors)) { -// m_d->clearNavigationHistory(); - return true; - } - return false; -} - -void EditorManager::closeOtherEditors(IEditor *editor) -{ - m_d->m_editorModel->removeAllRestoredEditors(); - QList editors = openedEditors(); - editors.removeAll(editor); - closeEditors(editors, true); -} - - -void EditorManager::closeOtherEditors() -{ - IEditor *current = currentEditor(); - QTC_ASSERT(current, return); - closeOtherEditors(current); -} - - -// SLOT connected to action -// since this is potentially called in the event handler of the editor -// we simply postpone it with a single shot timer -void EditorManager::closeEditor() -{ - closeEditor(m_d->m_currentEditor); -} - -void EditorManager::closeEditor(Core::IEditor *editor) -{ - if (!editor) - return; - closeEditors(QList() << editor); -} - -void EditorManager::closeEditor(const QModelIndex &index) -{ - IEditor *editor = index.data(Qt::UserRole).value(); - if (editor) - closeEditor(editor); - else - m_d->m_editorModel->removeEditor(index); -} - -bool EditorManager::closeEditors(const QList editorsToClose, bool askAboutModifiedEditors) -{ - if (editorsToClose.isEmpty()) - return true; - - SplitterOrView *currentSplitterOrView = this->currentSplitterOrView(); - - bool closingFailed = false; - QList acceptedEditors; - //ask all core listeners to check whether the editor can be closed - const QList listeners = - pluginManager()->getObjects(); - foreach (IEditor *editor, editorsToClose) { - bool editorAccepted = true; - if (m_d->m_editorModel->isDuplicate(editor)) - editor = m_d->m_editorModel->originalForDuplicate(editor); - foreach (ICoreListener *listener, listeners) { - if (!listener->editorAboutToClose(editor)) { - editorAccepted = false; - closingFailed = false; - break; - } - } - if (editorAccepted) - acceptedEditors.append(editor); - } - if (acceptedEditors.isEmpty()) - return false; - //ask whether to save modified files - if (askAboutModifiedEditors) { - bool cancelled = false; - QList list = m_d->m_core->fileManager()-> - saveModifiedFiles(filesForEditors(acceptedEditors), &cancelled); - if (cancelled) - return false; - if (!list.isEmpty()) { - closingFailed = true; - QSet skipSet = editorsForFiles(list).toSet(); - acceptedEditors = acceptedEditors.toSet().subtract(skipSet).toList(); - } - } - if (acceptedEditors.isEmpty()) - return false; - - // add duplicates - foreach(IEditor *editor, acceptedEditors) - acceptedEditors += m_d->m_editorModel->duplicatesFor(editor); - - QList closedViews; - - // remove the editors - foreach (IEditor *editor, acceptedEditors) { - emit editorAboutToClose(editor); - if (!editor->file()->fileName().isEmpty()) { - QByteArray state = editor->saveState(); - if (!state.isEmpty()) - m_d->m_editorStates.insert(editor->file()->fileName(), QVariant(state)); - } - - removeEditor(editor); - if (SplitterOrView *view = m_d->m_splitter->findView(editor)) { - if (editor == view->view()->currentEditor()) - closedViews += view->view(); - view->view()->removeEditor(editor); - } - } - - foreach (EditorView *view, closedViews) { - IEditor *newCurrent = view->currentEditor(); - if (!newCurrent) - newCurrent = pickUnusedEditor(); - if (newCurrent) { - activateEditor(view, newCurrent, NoActivate); - } else { - QModelIndex idx = m_d->m_editorModel->firstRestoredEditor(); - if (idx.isValid()) - activateEditor(idx, view, NoActivate); - } - } - - emit editorsClosed(acceptedEditors); - - foreach (IEditor *editor, acceptedEditors) { - delete editor; - } - - if (currentSplitterOrView) { - if (IEditor *editor = currentSplitterOrView->editor()) - activateEditor(currentSplitterOrView->view(), editor); - } - - if (!currentEditor()) - emit currentEditorChanged(0); - - return !closingFailed; -} - -void EditorManager::closeDuplicate(Core::IEditor *editor) -{ - - IEditor *original = editor; - if (m_d->m_editorModel->isDuplicate(editor)) - original= m_d->m_editorModel->originalForDuplicate(editor); - QList duplicates = m_d->m_editorModel->duplicatesFor(original); - - if (duplicates.isEmpty()) { - closeEditor(editor); - return; - } - - if (original== editor) - m_d->m_editorModel->makeOriginal(duplicates.first()); - - SplitterOrView *currentSplitterOrView = this->currentSplitterOrView(); - - emit editorAboutToClose(editor); - - EditorView *view = m_d->m_splitter->findView(editor)->view(); - removeEditor(editor); - view->removeEditor(editor); - - IEditor *newCurrent = view->currentEditor(); - if (!newCurrent) - newCurrent = pickUnusedEditor(); - if (newCurrent) { - activateEditor(view, newCurrent, NoActivate); - } else { - QModelIndex idx = m_d->m_editorModel->firstRestoredEditor(); - if (idx.isValid()) - activateEditor(idx, view, NoActivate); - } - - emit editorsClosed(QList() << editor); - delete editor; - if (currentSplitterOrView) { - if (IEditor *currentEditor = currentSplitterOrView->editor()) - activateEditor(currentSplitterOrView->view(), currentEditor); - } -} - -Core::IEditor *EditorManager::pickUnusedEditor() const -{ - foreach (IEditor *editor, openedEditors()) { - SplitterOrView *view = m_d->m_splitter->findView(editor); - if (!view || view->editor() != editor) - return editor; - } - return 0; -} - -Core::IEditor *EditorManager::activateEditor(const QModelIndex &index, Internal::EditorView *view, OpenEditorFlags flags) -{ - IEditor *editor = index.data(Qt::UserRole).value(); - if (editor) { - return activateEditor(view, editor, flags); - } - - QString fileName = index.data(Qt::UserRole + 1).toString(); - QByteArray kind = index.data(Qt::UserRole + 2).toByteArray(); - return openEditor(view, fileName, kind, flags); -} - -Core::IEditor *EditorManager::placeEditor(Core::Internal::EditorView *view, Core::IEditor *editor) -{ - Q_ASSERT(view && editor); - - if (view->currentEditor() && view->currentEditor()->file() == editor->file()) - editor = view->currentEditor(); - - if (!view->hasEditor(editor)) { - bool duplicateSupported = editor->duplicateSupported(); - if (SplitterOrView *sourceView = m_d->m_splitter->findView(editor)) { - if (editor != sourceView->editor() || !duplicateSupported) { - sourceView->view()->removeEditor(editor); - view->addEditor(editor); - view->setCurrentEditor(editor); - if (!sourceView->editor()) { - if (IEditor *replacement = pickUnusedEditor()) { - sourceView->view()->addEditor(replacement); - } - } - return editor; - } else if (duplicateSupported) { - editor = duplicateEditor(editor); - Q_ASSERT(editor); - m_d->m_editorModel->makeOriginal(editor); - } - } - view->addEditor(editor); - } - return editor; -} - -Core::IEditor *EditorManager::activateEditor(Core::IEditor *editor, OpenEditorFlags flags) -{ - return activateEditor(0, editor, flags); -} - -Core::IEditor *EditorManager::activateEditor(Core::Internal::EditorView *view, Core::IEditor *editor, OpenEditorFlags flags) -{ - if (!view) - view = currentEditorView(); - - Q_ASSERT(view); - - if (!editor) { - if (!m_d->m_currentEditor) - setCurrentEditor(0, (flags & IgnoreNavigationHistory)); - return 0; - } - - editor = placeEditor(view, editor); - - if (!(flags & NoActivate)) { - setCurrentEditor(editor, (flags & IgnoreNavigationHistory)); - if (!(flags & NoModeSwitch)) - ensureEditorManagerVisible(); - if (isVisible()) - editor->widget()->setFocus(); - } - return editor; -} - -Core::IEditor *EditorManager::activateEditor(Core::Internal::EditorView *view, Core::IFile *file, OpenEditorFlags flags) -{ - QList editors = editorsForFile(file); - Q_ASSERT(!editors.isEmpty()); - return activateEditor(view, editors.first(), flags); -} - -/* For something that has a 'QStringList mimeTypes' (IEditorFactory - * or IExternalEditor), find the one best matching the mimetype passed in. - * Recurse over the parent classes of the mimetype to find them. */ -template -static void mimeTypeFactoryRecursion(const MimeDatabase *db, - const MimeType &mimeType, - const QList &allFactories, - bool firstMatchOnly, - QList *list) -{ - typedef typename QList::const_iterator EditorFactoryLikeListConstIterator; - // Loop factories to find type - const QString type = mimeType.type(); - const EditorFactoryLikeListConstIterator fcend = allFactories.constEnd(); - for (EditorFactoryLikeListConstIterator fit = allFactories.constBegin(); fit != fcend; ++fit) { - // Exclude duplicates when recursing over xml or C++ -> C -> text. - EditorFactoryLike *factory = *fit; - if (!list->contains(factory) && factory->mimeTypes().contains(type)) { - list->push_back(*fit); - if (firstMatchOnly) - return; - break; - } - } - // Any parent mime type classes? -> recurse - QStringList parentTypes = mimeType.subClassesOf(); - if (parentTypes.empty()) - return; - const QStringList::const_iterator pcend = parentTypes .constEnd(); - for (QStringList::const_iterator pit = parentTypes .constBegin(); pit != pcend; ++pit) { - if (const MimeType parent = db->findByType(*pit)) - mimeTypeFactoryRecursion(db, parent, allFactories, firstMatchOnly, list); - } -} - -EditorManager::EditorFactoryList - EditorManager::editorFactories(const MimeType &mimeType, bool bestMatchOnly) const -{ - EditorFactoryList rc; - const EditorFactoryList allFactories = pluginManager()->getObjects(); - mimeTypeFactoryRecursion(m_d->m_core->mimeDatabase(), mimeType, allFactories, bestMatchOnly, &rc); - if (debugEditorManager) - qDebug() << Q_FUNC_INFO << mimeType.type() << " returns " << rc; - return rc; -} - -EditorManager::ExternalEditorList - EditorManager::externalEditors(const MimeType &mimeType, bool bestMatchOnly) const -{ - ExternalEditorList rc; - const ExternalEditorList allEditors = pluginManager()->getObjects(); - mimeTypeFactoryRecursion(m_d->m_core->mimeDatabase(), mimeType, allEditors, bestMatchOnly, &rc); - if (debugEditorManager) - qDebug() << Q_FUNC_INFO << mimeType.type() << " returns " << rc; - return rc; -} - -/* For something that has a 'QString kind' (IEditorFactory - * or IExternalEditor), find the one matching a kind. */ -template - inline EditorFactoryLike *findByKind(ExtensionSystem::PluginManager *pm, - const QString &kind) -{ - const QList factories = pm->template getObjects(); - foreach(EditorFactoryLike *efl, factories) - if (kind == efl->kind()) - return efl; - return 0; -} - -IEditor *EditorManager::createEditor(const QString &editorKind, - const QString &fileName) -{ - typedef QList FactoryList; - if (debugEditorManager) - qDebug() << Q_FUNC_INFO << editorKind << fileName; - - - EditorFactoryList factories; - if (editorKind.isEmpty()) { - // Find by mime type - MimeType mimeType = m_d->m_core->mimeDatabase()->findByFile(QFileInfo(fileName)); - if (!mimeType) { - qWarning("%s unable to determine mime type of %s/%s. Falling back to text/plain", - Q_FUNC_INFO, fileName.toUtf8().constData(), editorKind.toUtf8().constData()); - mimeType = m_d->m_core->mimeDatabase()->findByType(QLatin1String("text/plain")); - } - factories = editorFactories(mimeType, true); - } else { - // Find by editor kind - if (IEditorFactory *factory = findByKind(pluginManager(), editorKind)) - factories.push_back(factory); - } - if (factories.empty()) { - qWarning("%s: unable to find an editor factory for the file '%s', editor kind '%s'.", - Q_FUNC_INFO, fileName.toUtf8().constData(), editorKind.toUtf8().constData()); - return 0; - } - - IEditor *editor = factories.front()->createEditor(this); - if (editor) - connect(editor, SIGNAL(changed()), this, SLOT(updateActions())); - if (editor) - emit editorCreated(editor, fileName); - return editor; -} - -void EditorManager::addEditor(IEditor *editor, bool isDuplicate) -{ - if (!editor) - return; - m_d->m_core->addContextObject(editor); - - m_d->m_editorModel->addEditor(editor, isDuplicate); - if (!isDuplicate) { - m_d->m_core->fileManager()->addFile(editor->file()); - if (!editor->isTemporary()) { - m_d->m_core->fileManager()->addToRecentFiles(editor->file()->fileName()); - } - } - emit editorOpened(editor); -} - -// Run the OpenWithDialog and return the editor kind -// selected by the user. -QString EditorManager::getOpenWithEditorKind(const QString &fileName, - bool *isExternalEditor) const -{ - // Collect editors that can open the file - const MimeType mt = m_d->m_core->mimeDatabase()->findByFile(fileName); - if (!mt) - return QString(); - QStringList allEditorKinds; - QStringList externalEditorKinds; - // Built-in - const EditorFactoryList editors = editorFactories(mt, false); - const int size = editors.size(); - for (int i = 0; i < size; i++) { - allEditorKinds.push_back(editors.at(i)->kind()); - } - // External editors - const ExternalEditorList exEditors = externalEditors(mt, false); - const int esize = exEditors.size(); - for (int i = 0; i < esize; i++) { - externalEditorKinds.push_back(exEditors.at(i)->kind()); - allEditorKinds.push_back(exEditors.at(i)->kind()); - } - if (allEditorKinds.empty()) - return QString(); - // Run dialog. - OpenWithDialog dialog(fileName, m_d->m_core->mainWindow()); - dialog.setEditors(allEditorKinds); - dialog.setCurrentEditor(0); - if (dialog.exec() != QDialog::Accepted) - return QString(); - const QString selectedKind = dialog.editor(); - if (isExternalEditor) - *isExternalEditor = externalEditorKinds.contains(selectedKind); - return selectedKind; -} - -static QString formatFileFilters(const Core::ICore *core, QString *selectedFilter) -{ - QString rc; - // Compile list of filter strings. If we find a glob matching all files, - // put it last and set it as default selectedFilter. - QStringList filters = core->mimeDatabase()->filterStrings(); - filters.sort(); - selectedFilter->clear(); - if (filters.empty()) - return rc; - const QString filterSeparator = QLatin1String(";;"); - bool hasAllFilter = false; - const int size = filters.size(); - for (int i = 0; i < size; i++) { - const QString &filterString = filters.at(i); - if (filterString.isEmpty()) { // binary editor - hasAllFilter = true; - } else { - if (!rc.isEmpty()) - rc += filterSeparator; - rc += filterString; - } - } - if (hasAllFilter) { - // prepend all files filter - // prepending instead of appending to work around a but in Qt/Mac - QString allFilesFilter = EditorManager::tr("All Files (*)"); - if (!rc.isEmpty()) - allFilesFilter += filterSeparator; - rc.prepend(allFilesFilter); - *selectedFilter = allFilesFilter; - } else { - *selectedFilter = filters.front(); - } - return rc; -} - -IEditor *EditorManager::openEditor(const QString &fileName, const QString &editorKind, - EditorManager::OpenEditorFlags flags) -{ - return openEditor(0, fileName, editorKind, flags); -} - -IEditor *EditorManager::openEditor(Core::Internal::EditorView *view, const QString &fileName, - const QString &editorKind, EditorManager::OpenEditorFlags flags) -{ - if (debugEditorManager) - qDebug() << Q_FUNC_INFO << fileName << editorKind; - - if (fileName.isEmpty()) - return 0; - - const QList editors = editorsForFileName(fileName); - if (!editors.isEmpty()) { - return activateEditor(view, editors.first(), flags); - } - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - IEditor *editor = createEditor(editorKind, fileName); - if (!editor || !editor->open(fileName)) { - QApplication::restoreOverrideCursor(); - QMessageBox::critical(m_d->m_core->mainWindow(), tr("Opening File"), tr("Cannot open file %1!").arg(QDir::toNativeSeparators(fileName))); - delete editor; - editor = 0; - return 0; - } - addEditor(editor); - - IEditor *result= activateEditor(view, editor, flags); - if (editor == result) - restoreEditorState(editor); - QApplication::restoreOverrideCursor(); - return result; -} - -bool EditorManager::openExternalEditor(const QString &fileName, const QString &editorKind) -{ - IExternalEditor *ee = findByKind(pluginManager(), editorKind); - if (!ee) - return false; - QString errorMessage; - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - const bool ok = ee->startEditor(fileName, &errorMessage); - QApplication::restoreOverrideCursor(); - if (!ok) - QMessageBox::critical(m_d->m_core->mainWindow(), tr("Opening File"), errorMessage); - return ok; -} - -QStringList EditorManager::getOpenFileNames() const -{ - static QString dir = QDir::homePath(); - if (m_d->fileFilters.isEmpty()) - m_d->fileFilters = formatFileFilters(m_d->m_core, &m_d->selectedFilter); - - QString currentFile = ICore::instance()->fileManager()->currentFile(); - if (!currentFile.isEmpty()) { - const QFileInfo fi(currentFile); - dir = fi.absolutePath(); - } - - QStringList files = QFileDialog::getOpenFileNames(m_d->m_core->mainWindow(), tr("Open File"), - dir, m_d->fileFilters, &m_d->selectedFilter); - if (!files.isEmpty()) - dir = QFileInfo(files.at(0)).absolutePath(); - return files; -} - -void EditorManager::ensureEditorManagerVisible() -{ - if (!isVisible()) - m_d->m_core->modeManager()->activateMode(Constants::MODE_EDIT); -} - -IEditor *EditorManager::openEditorWithContents(const QString &editorKind, - QString *titlePattern, - const QString &contents) -{ - if (debugEditorManager) - qDebug() << Q_FUNC_INFO << editorKind << titlePattern << contents; - - if (editorKind.isEmpty()) - return 0; - - QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); - IEditor *edt = createEditor(editorKind); - if (!edt) { - QApplication::restoreOverrideCursor(); - return 0; - } - - if (!edt->createNew(contents)) { - QApplication::restoreOverrideCursor(); - delete edt; - edt = 0; - return 0; - } - - QString title = edt->displayName(); - - if (title.isEmpty() && titlePattern) { - const QChar dollar = QLatin1Char('$'); - const QChar dot = QLatin1Char('.'); - - QString base = *titlePattern; - if (base.isEmpty()) - base = QLatin1String("unnamed$"); - if (base.contains(dollar)) { - int i = 1; - QSet docnames; - foreach (IEditor *editor, openedEditors()) { - QString name = editor->file()->fileName(); - if (name.isEmpty()) { - name = editor->displayName(); - name.remove(QLatin1Char('*')); - } else { - name = QFileInfo(name).completeBaseName(); - } - docnames << name; - } - - do { - title = base; - title.replace(QString(dollar), QString::number(i++)); - } while (docnames.contains(title)); - } else { - title = *titlePattern; - } - } - *titlePattern = title; - edt->setDisplayName(title); - addEditor(edt); - QApplication::restoreOverrideCursor(); - return edt; -} - -bool EditorManager::hasEditor(const QString &fileName) const -{ - return !editorsForFileName(fileName).isEmpty(); -} - -void EditorManager::restoreEditorState(IEditor *editor) -{ - QTC_ASSERT(editor, return); - QString fileName = editor->file()->fileName(); - if (m_d->m_editorStates.contains(fileName)) - editor->restoreState(m_d->m_editorStates.value(fileName).toByteArray()); -} - -bool EditorManager::saveEditor(IEditor *editor) -{ - return saveFile(editor); -} - -bool EditorManager::saveFile(IEditor *editor) -{ - if (!editor) - editor = currentEditor(); - if (!editor) - return false; - - IFile *file = editor->file(); - file->checkPermissions(); - - const QString &fileName = file->fileName(); - - if (fileName.isEmpty()) - return saveFileAs(editor); - - bool success = false; - - // try saving, no matter what isReadOnly tells us - m_d->m_core->fileManager()->blockFileChange(file); - success = file->save(fileName); - m_d->m_core->fileManager()->unblockFileChange(file); - - if (!success) { - MakeWritableResult answer = - makeEditorWritable(editor); - if (answer == Failed) - return false; - if (answer == SavedAs) - return true; - - file->checkPermissions(); - - m_d->m_core->fileManager()->blockFileChange(file); - success = file->save(fileName); - m_d->m_core->fileManager()->unblockFileChange(file); - } - - if (success && !editor->isTemporary()) - m_d->m_core->fileManager()->addToRecentFiles(editor->file()->fileName()); - - return success; -} - -EditorManager::ReadOnlyAction - EditorManager::promptReadOnlyFile(const QString &fileName, - const IVersionControl *versionControl, - QWidget *parent, - bool displaySaveAsButton) -{ - QMessageBox msgBox(QMessageBox::Question, tr("File is Read Only"), - tr("The file %1 is read only.").arg(QDir::toNativeSeparators(fileName)), - QMessageBox::Cancel, parent); - - QPushButton *sccButton = 0; - if (versionControl && versionControl->supportsOperation(IVersionControl::OpenOperation)) - sccButton = msgBox.addButton(tr("Open with VCS (%1)").arg(versionControl->name()), QMessageBox::AcceptRole); - - QPushButton *makeWritableButton = msgBox.addButton(tr("Make writable"), QMessageBox::AcceptRole); - - QPushButton *saveAsButton = 0; - if (displaySaveAsButton) - saveAsButton = msgBox.addButton(tr("Save as ..."), QMessageBox::ActionRole); - - msgBox.setDefaultButton(sccButton ? sccButton : makeWritableButton); - msgBox.exec(); - - QAbstractButton *clickedButton = msgBox.clickedButton(); - if (clickedButton == sccButton) - return RO_OpenVCS; - if (clickedButton == makeWritableButton) - return RO_MakeWriteable; - if (clickedButton == saveAsButton) - return RO_SaveAs; - return RO_Cancel; -} - - -MakeWritableResult -EditorManager::makeEditorWritable(IEditor *editor) -{ - if (!editor || !editor->file()) - return Failed; - QString directory = QFileInfo(editor->file()->fileName()).absolutePath(); - IVersionControl *versionControl = m_d->m_core->vcsManager()->findVersionControlForDirectory(directory); - IFile *file = editor->file(); - const QString &fileName = file->fileName(); - - switch (promptReadOnlyFile(fileName, versionControl, m_d->m_core->mainWindow(), true)) { - case RO_OpenVCS: - if (!versionControl->vcsOpen(fileName)) { - QMessageBox::warning(m_d->m_core->mainWindow(), tr("Failed!"), tr("Could not open the file for editing with SCC.")); - return Failed; - } - file->checkPermissions(); - return OpenedWithVersionControl; - case RO_MakeWriteable: { - const bool permsOk = QFile::setPermissions(fileName, QFile::permissions(fileName) | QFile::WriteUser); - if (!permsOk) { - QMessageBox::warning(m_d->m_core->mainWindow(), tr("Failed!"), tr("Could not set permissions to writable.")); - return Failed; - } - } - file->checkPermissions(); - return MadeWritable; - case RO_SaveAs : - return saveFileAs(editor) ? SavedAs : Failed; - case RO_Cancel: - break; - } - return Failed; -} - -bool EditorManager::saveFileAs(IEditor *editor) -{ - if (!editor) - editor = currentEditor(); - if (!editor) - return false; - - QString absoluteFilePath = m_d->m_core->fileManager()->getSaveAsFileName(editor->file()); - if (absoluteFilePath.isEmpty()) - return false; - if (absoluteFilePath != editor->file()->fileName()) { - const QList existList = editorsForFileName(absoluteFilePath); - if (!existList.isEmpty()) { - closeEditors(existList, false); - } - } - - m_d->m_core->fileManager()->blockFileChange(editor->file()); - const bool success = editor->file()->save(absoluteFilePath); - m_d->m_core->fileManager()->unblockFileChange(editor->file()); - editor->file()->checkPermissions(); - - if (success && !editor->isTemporary()) - m_d->m_core->fileManager()->addToRecentFiles(editor->file()->fileName()); - - updateActions(); - return success; -} - -void EditorManager::gotoNextDocHistory() -{ - OpenEditorsWindow *dialog = windowPopup(); - if (dialog->isVisible()) { - dialog->selectNextEditor(); - } else { - EditorView *view = currentEditorView(); - dialog->setEditors(m_d->m_view, view, m_d->m_editorModel); - dialog->selectNextEditor(); - showWindowPopup(); - } -} - -void EditorManager::gotoPreviousDocHistory() -{ - OpenEditorsWindow *dialog = windowPopup(); - if (dialog->isVisible()) { - dialog->selectPreviousEditor(); - } else { - EditorView *view = currentEditorView(); - dialog->setEditors(m_d->m_view, view, m_d->m_editorModel); - dialog->selectPreviousEditor(); - showWindowPopup(); - } -} - -void EditorManager::makeCurrentEditorWritable() -{ - if (IEditor* curEditor = currentEditor()) - makeEditorWritable(curEditor); -} - -void EditorManager::updateActions() -{ - QString fName; - IEditor *curEditor = currentEditor(); - int openedCount = openedEditors().count() + m_d->m_editorModel->restoredEditorCount(); - if (curEditor) { - if (!curEditor->file()->fileName().isEmpty()) { - QFileInfo fi(curEditor->file()->fileName()); - fName = fi.fileName(); - } else { - fName = curEditor->displayName(); - } - - - if (curEditor->file()->isModified() && curEditor->file()->isReadOnly()) { - // we are about to change a read-only file, warn user - showEditorInfoBar(QLatin1String("Core.EditorManager.MakeWritable"), - tr("Warning: You are changing a read-only file."), - tr("Make writable"), this, SLOT(makeCurrentEditorWritable())); - } else { - hideEditorInfoBar(QLatin1String("Core.EditorManager.MakeWritable")); - } - } - - m_d->m_saveAction->setEnabled(curEditor != 0 && curEditor->file()->isModified()); - m_d->m_saveAsAction->setEnabled(curEditor != 0 && curEditor->file()->isSaveAsAllowed()); - m_d->m_revertToSavedAction->setEnabled(curEditor != 0 - && !curEditor->file()->fileName().isEmpty() && curEditor->file()->isModified()); - - QString quotedName; - if (!fName.isEmpty()) - quotedName = '"' + fName + '"'; - m_d->m_saveAsAction->setText(tr("Save %1 As...").arg(quotedName)); - m_d->m_saveAction->setText(tr("&Save %1").arg(quotedName)); - m_d->m_revertToSavedAction->setText(tr("Revert %1 to Saved").arg(quotedName)); - - - m_d->m_closeCurrentEditorAction->setEnabled(curEditor != 0); - m_d->m_closeCurrentEditorAction->setText(tr("Close %1").arg(quotedName)); - m_d->m_closeAllEditorsAction->setEnabled(openedCount > 0); - m_d->m_closeOtherEditorsAction->setEnabled(openedCount > 1); - m_d->m_closeOtherEditorsAction->setText((openedCount > 1 ? tr("Close All Except %1").arg(quotedName) : tr("Close Others"))); - - m_d->m_gotoNextDocHistoryAction->setEnabled(m_d->m_editorModel->rowCount() != 0); - m_d->m_gotoPreviousDocHistoryAction->setEnabled(m_d->m_editorModel->rowCount() != 0); - EditorView *view = currentEditorView(); - m_d->m_goBackAction->setEnabled(view ? view->canGoBack() : false); - m_d->m_goForwardAction->setEnabled(view ? view->canGoForward() : false); - - bool hasSplitter = m_d->m_splitter->isSplitter(); - m_d->m_removeCurrentSplitAction->setEnabled(hasSplitter); - m_d->m_removeAllSplitsAction->setEnabled(hasSplitter); - m_d->m_gotoOtherSplitAction->setEnabled(hasSplitter); - - m_d->m_openInExternalEditorAction->setEnabled(curEditor != 0); -} - -QList EditorManager::openedEditors() const -{ - return m_d->m_editorModel->editors(); -} - -OpenEditorsModel *EditorManager::openedEditorsModel() const -{ - return m_d->m_editorModel; -} - -void EditorManager::addCurrentPositionToNavigationHistory(IEditor *editor, const QByteArray &saveState) -{ - currentEditorView()->addCurrentPositionToNavigationHistory(editor, saveState); - updateActions(); -} - -void EditorManager::goBackInNavigationHistory() -{ - currentEditorView()->goBackInNavigationHistory(); - updateActions(); - ensureEditorManagerVisible(); - return; -} - -void EditorManager::goForwardInNavigationHistory() -{ - currentEditorView()->goForwardInNavigationHistory(); - updateActions(); - ensureEditorManagerVisible(); -} - -OpenEditorsWindow *EditorManager::windowPopup() const -{ - return m_d->m_windowPopup; -} - -void EditorManager::showWindowPopup() const -{ - const QPoint p(mapToGlobal(QPoint(0, 0))); - m_d->m_windowPopup->move((width()-m_d->m_windowPopup->width())/2 + p.x(), - (height()-m_d->m_windowPopup->height())/2 + p.y()); - m_d->m_windowPopup->setVisible(true); -} - -QByteArray EditorManager::saveState() const -{ - QByteArray bytes; - QDataStream stream(&bytes, QIODevice::WriteOnly); - - stream << QByteArray("EditorManagerV4"); - - QList editors = openedEditors(); - foreach (IEditor *editor, editors) { - if (!editor->file()->fileName().isEmpty()) { - QByteArray state = editor->saveState(); - if (!state.isEmpty()) - m_d->m_editorStates.insert(editor->file()->fileName(), QVariant(state)); - } - } - - stream << m_d->m_editorStates; - - QList entries = m_d->m_editorModel->entries(); - stream << entries.count(); - - foreach (OpenEditorsModel::Entry entry, entries) { - stream << entry.fileName() << entry.displayName() << entry.kind(); - } - - stream << m_d->m_splitter->saveState(); - - return bytes; -} - -bool EditorManager::restoreState(const QByteArray &state) -{ - closeAllEditors(true); - removeAllSplits(); - QDataStream stream(state); - - QByteArray version; - stream >> version; - - if (version != "EditorManagerV4") - return false; - - QMap editorstates; - - QApplication::setOverrideCursor(Qt::WaitCursor); - - stream >> editorstates; - - QMapIterator i(editorstates); - while (i.hasNext()) { - i.next(); - m_d->m_editorStates.insert(i.key(), i.value()); - } - - int editorCount = 0; - stream >> editorCount; - while (--editorCount >= 0) { - QString fileName; - stream >> fileName; - QString displayName; - stream >> displayName; - QByteArray kind; - stream >> kind; - - if (!fileName.isEmpty() && !displayName.isEmpty()){ - m_d->m_editorModel->addRestoredEditor(fileName, displayName, kind); - } - } - - QByteArray splitterstates; - stream >> splitterstates; - m_d->m_splitter->restoreState(splitterstates); - - // splitting and stuff results in focus trouble, that's why we set the focus again after restoration - ensureEditorManagerVisible(); - if (m_d->m_currentEditor) { - m_d->m_currentEditor->widget()->setFocus(); - } else if (Core::Internal::SplitterOrView *view = currentSplitterOrView()) { - if (IEditor *e = view->editor()) - e->widget()->setFocus(); - else if (view->view()) - view->view()->setFocus(); - } - - QApplication::restoreOverrideCursor(); - - return true; -} - -static const char * const documentStatesKey = "EditorManager/DocumentStates"; -static const char * const externalEditorKey = "EditorManager/ExternalEditorCommand"; -static const char * const reloadBehaviorKey = "EditorManager/ReloadBehavior"; - -void EditorManager::saveSettings() -{ - SettingsDatabase *settings = m_d->m_core->settingsDatabase(); - settings->setValue(QLatin1String(documentStatesKey), m_d->m_editorStates); - settings->setValue(QLatin1String(externalEditorKey), m_d->m_externalEditor); - settings->setValue(QLatin1String(reloadBehaviorKey), m_d->m_reloadBehavior); -} - -void EditorManager::readSettings() -{ - // Backward compatibility to old locations for these settings - QSettings *qs = m_d->m_core->settings(); - if (qs->contains(QLatin1String(documentStatesKey))) { - m_d->m_editorStates = qs->value(QLatin1String(documentStatesKey)) - .value >(); - qs->remove(QLatin1String(documentStatesKey)); - } - if (qs->contains(QLatin1String(externalEditorKey))) { - m_d->m_externalEditor = qs->value(QLatin1String(externalEditorKey)).toString(); - qs->remove(QLatin1String(externalEditorKey)); - } - - SettingsDatabase *settings = m_d->m_core->settingsDatabase(); - if (settings->contains(QLatin1String(documentStatesKey))) - m_d->m_editorStates = settings->value(QLatin1String(documentStatesKey)) - .value >(); - if (settings->contains(QLatin1String(externalEditorKey))) - m_d->m_externalEditor = settings->value(QLatin1String(externalEditorKey)).toString(); - - if (settings->contains(QLatin1String(reloadBehaviorKey))) - m_d->m_reloadBehavior = (IFile::ReloadBehavior)settings->value(QLatin1String(reloadBehaviorKey)).toInt(); -} - - -void EditorManager::revertToSaved() -{ - IEditor *currEditor = currentEditor(); - if (!currEditor) - return; - const QString fileName = currEditor->file()->fileName(); - if (fileName.isEmpty()) - return; - if (currEditor->file()->isModified()) { - QMessageBox msgBox(QMessageBox::Question, tr("Revert to Saved"), - tr("You will lose your current changes if you proceed reverting %1.").arg(QDir::toNativeSeparators(fileName)), - QMessageBox::Yes|QMessageBox::No, m_d->m_core->mainWindow()); - msgBox.button(QMessageBox::Yes)->setText(tr("Proceed")); - msgBox.button(QMessageBox::No)->setText(tr("Cancel")); - msgBox.setDefaultButton(QMessageBox::No); - msgBox.setEscapeButton(QMessageBox::No); - if (msgBox.exec() == QMessageBox::No) - return; - - } - IFile::ReloadBehavior temp = IFile::ReloadAll; - currEditor->file()->modified(&temp); -} - -void EditorManager::showEditorInfoBar(const QString &kind, - const QString &infoText, - const QString &buttonText, - QObject *object, const char *member) -{ - - currentEditorView()->showEditorInfoBar(kind, infoText, buttonText, object, member); -} - - -void EditorManager::hideEditorInfoBar(const QString &kind) -{ - Core::Internal::EditorView *cev = currentEditorView(); - if (cev) - cev->hideEditorInfoBar(kind); -} - -void EditorManager::showEditorStatusBar(const QString &kind, - const QString &infoText, - const QString &buttonText, - QObject *object, const char *member) -{ - - currentEditorView()->showEditorStatusBar(kind, infoText, buttonText, object, member); -} - -void EditorManager::hideEditorStatusBar(const QString &kind) -{ - currentEditorView()->hideEditorStatusBar(kind); -} - -QString EditorManager::externalEditorHelpText() const -{ - QString help = tr( - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "" - "
VariableExpands to
%ffile name
%lcurrent line number
%ccurrent column number
%xeditor's x position on screen
%yeditor's y position on screen
%weditor's width in pixels
%heditor's height in pixels
%Weditor's width in characters
%Heditor's height in characters
%%%
"); - return help; -} - -void EditorManager::openInExternalEditor() -{ - QString command = m_d->m_externalEditor; - if (command.isEmpty()) - command = defaultExternalEditor(); - - if (command.isEmpty()) - return; - - IEditor *editor = currentEditor(); - if (!editor) - return; - if (editor->file()->isModified()) { - bool cancelled = false; - QList list = m_d->m_core->fileManager()-> - saveModifiedFiles(QList() << editor->file(), &cancelled); - if (cancelled) - return; - } - - QRect rect = editor->widget()->rect(); - QFont font = editor->widget()->font(); - QFontMetrics fm(font); - rect.moveTo(editor->widget()->mapToGlobal(QPoint(0,0))); - - QString pre = command; - QString cmd; - for (int i = 0; i < pre.size(); ++i) { - QChar c = pre.at(i); - if (c == QLatin1Char('%') && i < pre.size()-1) { - c = pre.at(++i); - QString s; - if (c == QLatin1Char('f')) - s = editor->file()->fileName(); - else if (c == QLatin1Char('l')) - s = QString::number(editor->currentLine()); - else if (c == QLatin1Char('c')) - s = QString::number(editor->currentColumn()); - else if (c == QLatin1Char('x')) - s = QString::number(rect.x()); - else if (c == QLatin1Char('y')) - s = QString::number(rect.y()); - else if (c == QLatin1Char('w')) - s = QString::number(rect.width()); - else if (c == QLatin1Char('h')) - s = QString::number(rect.height()); - else if (c == QLatin1Char('W')) - s = QString::number(rect.width() / fm.width(QLatin1Char('x'))); - else if (c == QLatin1Char('H')) - s = QString::number(rect.height() / fm.lineSpacing()); - else if (c == QLatin1Char('%')) - s = c; - else { - s = QLatin1Char('%'); - cmd += c; - } - cmd += s; - continue; - - } - cmd += c; - } - - QProcess::startDetached(cmd); -} - -void EditorManager::setExternalEditor(const QString &editor) -{ - if (editor.isEmpty() || editor == defaultExternalEditor()) - m_d->m_externalEditor = defaultExternalEditor(); - else - m_d->m_externalEditor = editor; -} - -QString EditorManager::externalEditor() const -{ - if (m_d->m_externalEditor.isEmpty()) - return defaultExternalEditor(); - return m_d->m_externalEditor; -} - -void EditorManager::setReloadBehavior(IFile::ReloadBehavior behavior) -{ - m_d->m_reloadBehavior = behavior; -} - -IFile::ReloadBehavior EditorManager::reloadBehavior() const -{ - return m_d->m_reloadBehavior; -} - -Core::IEditor *EditorManager::duplicateEditor(Core::IEditor *editor) -{ - if (!editor->duplicateSupported()) - return 0; - - IEditor *duplicate = editor->duplicate(0); - duplicate->restoreState(editor->saveState()); - emit editorCreated(duplicate, duplicate->file()->fileName()); - addEditor(duplicate, true); - return duplicate; -} - -void EditorManager::split(Qt::Orientation orientation) -{ - SplitterOrView *view = m_d->m_currentView; - if (!view) - view = m_d->m_currentEditor ? m_d->m_splitter->findView(m_d->m_currentEditor) - : m_d->m_splitter->findFirstView(); - if (view && !view->splitter()) { - view->split(orientation); - } - updateActions(); -} - -void EditorManager::split() -{ - split(Qt::Vertical); -} - -void EditorManager::splitSideBySide() -{ - split(Qt::Horizontal); -} - -void EditorManager::removeCurrentSplit() -{ - SplitterOrView *viewToClose = m_d->m_currentView; - if (!viewToClose && m_d->m_currentEditor) - viewToClose = m_d->m_splitter->findView(m_d->m_currentEditor); - - if (!viewToClose || viewToClose->isSplitter() || viewToClose == m_d->m_splitter) - return; - - closeView(viewToClose->view()); - updateActions(); -} - -void EditorManager::removeAllSplits() -{ - if (!m_d->m_splitter->isSplitter()) - return; - IEditor *editor = m_d->m_currentEditor; - m_d->m_currentEditor = 0; // trigger update below - if (editor && m_d->m_editorModel->isDuplicate(editor)) - editor = m_d->m_editorModel->originalForDuplicate(editor); - m_d->m_splitter->unsplitAll(); - if (!editor) - editor = pickUnusedEditor(); - activateEditor(editor); -} - -void EditorManager::gotoOtherSplit() -{ - if (m_d->m_splitter->isSplitter()) { - SplitterOrView *currentView = m_d->m_currentView; - if (!currentView && m_d->m_currentEditor) - currentView = m_d->m_splitter->findView(m_d->m_currentEditor); - if (!currentView) - currentView = m_d->m_splitter->findFirstView(); - SplitterOrView *view = m_d->m_splitter->findNextView(currentView); - if (!view) - view = m_d->m_splitter->findFirstView(); - if (view) { - if (IEditor *editor = view->editor()) { - setCurrentEditor(editor, true); - editor->widget()->setFocus(); - } else { - setCurrentView(view); - } - } - } -} -//===================EditorClosingCoreListener====================== - -EditorClosingCoreListener::EditorClosingCoreListener(EditorManager *em) - : m_em(em) -{ -} - -bool EditorClosingCoreListener::editorAboutToClose(IEditor *) -{ - return true; -} - -bool EditorClosingCoreListener::coreAboutToClose() -{ - // Do not ask for files to save. - // MainWindow::closeEvent has already done that. - return m_em->closeAllEditors(false); -} +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "editormanager.h" +#include "editorview.h" +#include "openeditorswindow.h" +#include "openeditorsview.h" +#include "openeditorsmodel.h" +#include "openwithdialog.h" +#include "filemanager.h" +#include "icore.h" +#include "iversioncontrol.h" +#include "mimedatabase.h" +#include "tabpositionindicator.h" +#include "vcsmanager.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +Q_DECLARE_METATYPE(Core::IEditor*) + +using namespace Core; +using namespace Core::Internal; +using namespace Utils; + +enum { debugEditorManager=0 }; + +static inline ExtensionSystem::PluginManager *pluginManager() +{ + return ExtensionSystem::PluginManager::instance(); +} + +//===================EditorManager===================== + +EditorManagerPlaceHolder *EditorManagerPlaceHolder::m_current = 0; + +EditorManagerPlaceHolder::EditorManagerPlaceHolder(Core::IMode *mode, QWidget *parent) + : QWidget(parent), m_mode(mode) +{ + setLayout(new QVBoxLayout); + layout()->setMargin(0); + connect(Core::ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode *)), + this, SLOT(currentModeChanged(Core::IMode *))); + + currentModeChanged(Core::ModeManager::instance()->currentMode()); +} + +EditorManagerPlaceHolder::~EditorManagerPlaceHolder() +{ + if (m_current == this) { + EditorManager::instance()->setParent(0); + EditorManager::instance()->hide(); + } +} + +void EditorManagerPlaceHolder::currentModeChanged(Core::IMode *mode) +{ + if (m_current == this) { + m_current = 0; + EditorManager::instance()->setParent(0); + EditorManager::instance()->hide(); + } + if (m_mode == mode) { + m_current = this; + layout()->addWidget(EditorManager::instance()); + EditorManager::instance()->show(); + } +} + +EditorManagerPlaceHolder* EditorManagerPlaceHolder::current() +{ + return m_current; +} + +// ---------------- EditorManager + +namespace Core { + + +struct EditorManagerPrivate { + explicit EditorManagerPrivate(ICore *core, QWidget *parent); + ~EditorManagerPrivate(); + Internal::EditorView *m_view; + Internal::SplitterOrView *m_splitter; + QPointer m_currentEditor; + QPointer m_currentView; + + ICore *m_core; + + + // actions + QAction *m_revertToSavedAction; + QAction *m_saveAction; + QAction *m_saveAsAction; + QAction *m_closeCurrentEditorAction; + QAction *m_closeAllEditorsAction; + QAction *m_closeOtherEditorsAction; + QAction *m_gotoNextDocHistoryAction; + QAction *m_gotoPreviousDocHistoryAction; + QAction *m_goBackAction; + QAction *m_goForwardAction; + QAction *m_openInExternalEditorAction; + QAction *m_splitAction; + QAction *m_splitSideBySideAction; + QAction *m_removeCurrentSplitAction; + QAction *m_removeAllSplitsAction; + QAction *m_gotoOtherSplitAction; + + Internal::OpenEditorsWindow *m_windowPopup; + Core::BaseView *m_openEditorsView; + Internal::EditorClosingCoreListener *m_coreListener; + + QMap m_editorStates; + Internal::OpenEditorsViewFactory *m_openEditorsFactory; + + QString fileFilters; + QString selectedFilter; + + OpenEditorsModel *m_editorModel; + QString m_externalEditor; + + IFile::ReloadBehavior m_reloadBehavior; +}; +} + +EditorManagerPrivate::EditorManagerPrivate(ICore *core, QWidget *parent) : + m_view(0), + m_splitter(0), + m_core(core), + m_revertToSavedAction(new QAction(EditorManager::tr("Revert to Saved"), parent)), + m_saveAction(new QAction(parent)), + m_saveAsAction(new QAction(parent)), + m_closeCurrentEditorAction(new QAction(EditorManager::tr("Close"), parent)), + m_closeAllEditorsAction(new QAction(EditorManager::tr("Close All"), parent)), + m_closeOtherEditorsAction(new QAction(EditorManager::tr("Close Others"), parent)), + m_gotoNextDocHistoryAction(new QAction(EditorManager::tr("Next Open Document in History"), parent)), + m_gotoPreviousDocHistoryAction(new QAction(EditorManager::tr("Previous Open Document in History"), parent)), + m_goBackAction(new QAction(QIcon(QLatin1String(":/help/images/previous.png")), EditorManager::tr("Go Back"), parent)), + m_goForwardAction(new QAction(QIcon(QLatin1String(":/help/images/next.png")), EditorManager::tr("Go Forward"), parent)), + m_openInExternalEditorAction(new QAction(EditorManager::tr("Open in External Editor"), parent)), + m_windowPopup(0), + m_coreListener(0), + m_reloadBehavior(IFile::AskForReload) +{ + m_editorModel = new OpenEditorsModel(parent); +} + +EditorManagerPrivate::~EditorManagerPrivate() +{ +// clearNavigationHistory(); +} + +EditorManager *EditorManager::m_instance = 0; + +static Command *createSeparator(ActionManager *am, QObject *parent, + const QString &name, + const QList &context) +{ + QAction *tmpaction = new QAction(parent); + tmpaction->setSeparator(true); + Command *cmd = am->registerAction(tmpaction, name, context); + return cmd; +} + +EditorManager::EditorManager(ICore *core, QWidget *parent) : + QWidget(parent), + m_d(new EditorManagerPrivate(core, parent)) +{ + m_instance = this; + + connect(m_d->m_core, SIGNAL(contextAboutToChange(Core::IContext *)), + this, SLOT(handleContextChange(Core::IContext *))); + + const QList gc = QList() << Constants::C_GLOBAL_ID; + const QList editManagerContext = + QList() << m_d->m_core->uniqueIDManager()->uniqueIdentifier(Constants::C_EDITORMANAGER); + + ActionManager *am = m_d->m_core->actionManager(); + ActionContainer *mfile = am->actionContainer(Constants::M_FILE); + + //Revert to saved + Command *cmd = am->registerAction(m_d->m_revertToSavedAction, + Constants::REVERTTOSAVED, editManagerContext); + cmd->setAttribute(Command::CA_UpdateText); + cmd->setDefaultText(tr("Revert File to Saved")); + mfile->addAction(cmd, Constants::G_FILE_SAVE); + connect(m_d->m_revertToSavedAction, SIGNAL(triggered()), this, SLOT(revertToSaved())); + + //Save Action + am->registerAction(m_d->m_saveAction, Constants::SAVE, editManagerContext); + connect(m_d->m_saveAction, SIGNAL(triggered()), this, SLOT(saveFile())); + + //Save As Action + am->registerAction(m_d->m_saveAsAction, Constants::SAVEAS, editManagerContext); + connect(m_d->m_saveAsAction, SIGNAL(triggered()), this, SLOT(saveFileAs())); + + //Window Menu + ActionContainer *mwindow = am->actionContainer(Constants::M_WINDOW); + + //Window menu separators + QAction *tmpaction = new QAction(this); + tmpaction->setSeparator(true); + cmd = am->registerAction(tmpaction, QLatin1String("QtCreator.Window.Sep.Split"), editManagerContext); + mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); + + tmpaction = new QAction(this); + tmpaction->setSeparator(true); + cmd = am->registerAction(tmpaction, QLatin1String("QtCreator.Window.Sep.Navigate"), editManagerContext); + mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE); + + //Close Action + cmd = am->registerAction(m_d->m_closeCurrentEditorAction, Constants::CLOSE, editManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+W"))); + cmd->setAttribute(Core::Command::CA_UpdateText); + cmd->setDefaultText(m_d->m_closeCurrentEditorAction->text()); + mfile->addAction(cmd, Constants::G_FILE_CLOSE); + connect(m_d->m_closeCurrentEditorAction, SIGNAL(triggered()), this, SLOT(closeEditor())); + + //Close All Action + cmd = am->registerAction(m_d->m_closeAllEditorsAction, Constants::CLOSEALL, editManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+W"))); + mfile->addAction(cmd, Constants::G_FILE_CLOSE); + connect(m_d->m_closeAllEditorsAction, SIGNAL(triggered()), this, SLOT(closeAllEditors())); + + //Close All Others Action + cmd = am->registerAction(m_d->m_closeOtherEditorsAction, Constants::CLOSEOTHERS, editManagerContext); + mfile->addAction(cmd, Constants::G_FILE_CLOSE); + cmd->setAttribute(Core::Command::CA_UpdateText); + connect(m_d->m_closeOtherEditorsAction, SIGNAL(triggered()), this, SLOT(closeOtherEditors())); + + // Goto Previous In History Action + cmd = am->registerAction(m_d->m_gotoPreviousDocHistoryAction, Constants::GOTOPREVINHISTORY, editManagerContext); +#ifdef Q_WS_MAC + cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Tab"))); +#else + cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Tab"))); +#endif + mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE); + connect(m_d->m_gotoPreviousDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoPreviousDocHistory())); + + // Goto Next In History Action + cmd = am->registerAction(m_d->m_gotoNextDocHistoryAction, Constants::GOTONEXTINHISTORY, editManagerContext); +#ifdef Q_WS_MAC + cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Shift+Tab"))); +#else + cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+Tab"))); +#endif + mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE); + connect(m_d->m_gotoNextDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoNextDocHistory())); + + // Go back in navigation history + cmd = am->registerAction(m_d->m_goBackAction, Constants::GO_BACK, editManagerContext); +#ifdef Q_WS_MAC + cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Left"))); +#else + cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Left"))); +#endif + mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE); + connect(m_d->m_goBackAction, SIGNAL(triggered()), this, SLOT(goBackInNavigationHistory())); + + // Go forward in navigation history + cmd = am->registerAction(m_d->m_goForwardAction, Constants::GO_FORWARD, editManagerContext); +#ifdef Q_WS_MAC + cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Right"))); +#else + cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Right"))); +#endif + mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE); + connect(m_d->m_goForwardAction, SIGNAL(triggered()), this, SLOT(goForwardInNavigationHistory())); + +#ifdef Q_WS_MAC + QString prefix = tr("Meta+E"); +#else + QString prefix = tr("Ctrl+E"); +#endif + + m_d->m_splitAction = new QAction(tr("Split"), this); + cmd = am->registerAction(m_d->m_splitAction, Constants::SPLIT, editManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("%1,2").arg(prefix))); + mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); + connect(m_d->m_splitAction, SIGNAL(triggered()), this, SLOT(split())); + + m_d->m_splitSideBySideAction = new QAction(tr("Split Side by Side"), this); + cmd = am->registerAction(m_d->m_splitSideBySideAction, Constants::SPLIT_SGCS_BY_SIDE, editManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("%1,3").arg(prefix))); + mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); + connect(m_d->m_splitSideBySideAction, SIGNAL(triggered()), this, SLOT(splitSideBySide())); + + m_d->m_removeCurrentSplitAction = new QAction(tr("Remove Current Split"), this); + cmd = am->registerAction(m_d->m_removeCurrentSplitAction, Constants::REMOVE_CURRENT_SPLIT, editManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("%1,0").arg(prefix))); + mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); + connect(m_d->m_removeCurrentSplitAction, SIGNAL(triggered()), this, SLOT(removeCurrentSplit())); + + m_d->m_removeAllSplitsAction = new QAction(tr("Remove All Splits"), this); + cmd = am->registerAction(m_d->m_removeAllSplitsAction, Constants::REMOVE_ALL_SPLITS, editManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("%1,1").arg(prefix))); + mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); + connect(m_d->m_removeAllSplitsAction, SIGNAL(triggered()), this, SLOT(removeAllSplits())); + + m_d->m_gotoOtherSplitAction = new QAction(tr("Goto Other Split"), this); + cmd = am->registerAction(m_d->m_gotoOtherSplitAction, Constants::GOTO_OTHER_SPLIT, editManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("%1,o").arg(prefix))); + mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT); + connect(m_d->m_gotoOtherSplitAction, SIGNAL(triggered()), this, SLOT(gotoOtherSplit())); + + ActionContainer *medit = am->actionContainer(Constants::M_EDIT); + ActionContainer *advancedMenu = am->createMenu(Constants::M_EDIT_ADVANCED); + medit->addMenu(advancedMenu, Constants::G_EDIT_ADVANCED); + advancedMenu->menu()->setTitle(tr("&Advanced")); + advancedMenu->appendGroup(Constants::G_EDIT_FORMAT); + advancedMenu->appendGroup(Constants::G_EDIT_COLLAPSING); + advancedMenu->appendGroup(Constants::G_EDIT_BLOCKS); + advancedMenu->appendGroup(Constants::G_EDIT_FONT); + advancedMenu->appendGroup(Constants::G_EDIT_EDITOR); + + // Advanced menu separators + cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Collapsing"), editManagerContext); + advancedMenu->addAction(cmd, Constants::G_EDIT_COLLAPSING); + cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Blocks"), editManagerContext); + advancedMenu->addAction(cmd, Constants::G_EDIT_BLOCKS); + cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Font"), editManagerContext); + advancedMenu->addAction(cmd, Constants::G_EDIT_FONT); + cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Editor"), editManagerContext); + advancedMenu->addAction(cmd, Constants::G_EDIT_EDITOR); + + cmd = am->registerAction(m_d->m_openInExternalEditorAction, Constants::OPEN_IN_EXTERNAL_EDITOR, editManagerContext); + cmd->setDefaultKeySequence(QKeySequence(tr("Alt+V,Alt+I"))); + advancedMenu->addAction(cmd, Constants::G_EDIT_EDITOR); + connect(m_d->m_openInExternalEditorAction, SIGNAL(triggered()), this, SLOT(openInExternalEditor())); + + // Connect to VariableManager for CURRENT_DOCUMENT variable setting + VariableManager *vm = VariableManager::instance(); + connect(this, SIGNAL(currentEditorChanged(Core::IEditor *)), + vm, SLOT(updateCurrentDocument(Core::IEditor *))); + + + // other setup + m_d->m_splitter = new SplitterOrView(m_d->m_editorModel); + m_d->m_view = m_d->m_splitter->view(); + + + QHBoxLayout *layout = new QHBoxLayout(this); + layout->setMargin(0); + layout->setSpacing(0); + layout->addWidget(m_d->m_splitter); + + updateActions(); + + m_d->m_windowPopup = new OpenEditorsWindow(this); +} + +EditorManager::~EditorManager() +{ + if (m_d->m_core) { + ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance(); + if (m_d->m_coreListener) { + pm->removeObject(m_d->m_coreListener); + delete m_d->m_coreListener; + } + pm->removeObject(m_d->m_openEditorsFactory); + delete m_d->m_openEditorsFactory; + } + delete m_d; +} + +void EditorManager::init() +{ + QList context; + context << m_d->m_core->uniqueIDManager()->uniqueIdentifier("QtCreator.OpenDocumentsView"); + + m_d->m_coreListener = new EditorClosingCoreListener(this); + + pluginManager()->addObject(m_d->m_coreListener); + + m_d->m_openEditorsFactory = new OpenEditorsViewFactory(); + pluginManager()->addObject(m_d->m_openEditorsFactory); +} + +QString EditorManager::defaultExternalEditor() const +{ +#ifdef Q_OS_UNIX + return ConsoleProcess::defaultTerminalEmulator() + QLatin1String( +# ifdef Q_OS_MAC + " -async" +# endif + " -geom %Wx%H+%x+%y -e vi %f +%l +\"normal %c|\""); +#else + return QLatin1String("notepad %f"); +#endif +} + +void EditorManager::removeEditor(IEditor *editor) +{ + bool isDuplicate = m_d->m_editorModel->isDuplicate(editor); + m_d->m_editorModel->removeEditor(editor); + if (!isDuplicate) { + m_d->m_core->fileManager()->removeFile(editor->file()); + } + m_d->m_core->removeContextObject(editor); +} + +void EditorManager::handleContextChange(Core::IContext *context) +{ + if (debugEditorManager) + qDebug() << Q_FUNC_INFO; + IEditor *editor = context ? qobject_cast(context) : 0; + if (editor) { + setCurrentEditor(editor); + } else { + updateActions(); + } +} + +void EditorManager::setCurrentEditor(IEditor *editor, bool ignoreNavigationHistory) +{ + if (editor) + setCurrentView(0); + + if (m_d->m_currentEditor == editor) + return; + if (m_d->m_currentEditor && !ignoreNavigationHistory) + addCurrentPositionToNavigationHistory(); + + m_d->m_currentEditor = editor; + if (editor) { + if (SplitterOrView *splitterOrView = m_d->m_splitter->findView(editor)) + splitterOrView->view()->setCurrentEditor(editor); + m_d->m_view->updateEditorHistory(editor); // the global view should have a complete history + } + updateActions(); + emit currentEditorChanged(editor); +} + + +void EditorManager::setCurrentView(Core::Internal::SplitterOrView *view) +{ + if (view == m_d->m_currentView) + return; + + SplitterOrView *old = m_d->m_currentView; + m_d->m_currentView = view; + + if (old) + old->update(); + if (view) + view->update(); + + if (view && !view->editor()) + view->setFocus(); +} + +Core::Internal::SplitterOrView *EditorManager::currentSplitterOrView() const +{ + SplitterOrView *view = m_d->m_currentView; + if (!view) + view = m_d->m_currentEditor? + m_d->m_splitter->findView(m_d->m_currentEditor): + m_d->m_splitter->findFirstView(); + if (!view) + return m_d->m_splitter; + return view; +} + +Core::Internal::EditorView *EditorManager::currentEditorView() const +{ + return currentSplitterOrView()->view(); +} + + + +QList EditorManager::editorsForFileName(const QString &filename) const +{ + QList found; + QString fixedname = FileManager::fixFileName(filename); + foreach (IEditor *editor, openedEditors()) { + if (fixedname == FileManager::fixFileName(editor->file()->fileName())) + found << editor; + } + return found; +} + +QList EditorManager::editorsForFile(IFile *file) const +{ + QList found; + foreach (IEditor *editor, openedEditors()) { + if (editor->file() == file) + found << editor; + } + return found; +} + +IEditor *EditorManager::currentEditor() const +{ + return m_d->m_currentEditor; +} + +void EditorManager::emptyView(Core::Internal::EditorView *view) +{ + if (!view) + return; + + QList editors = view->editors(); + foreach (IEditor *editor, editors) { + if (!m_d->m_editorModel->isDuplicate(editor)) { + editors.removeAll(editor); + view->removeEditor(editor); + continue; + } + emit editorAboutToClose(editor); + removeEditor(editor); + view->removeEditor(editor); + } + emit editorsClosed(editors); + foreach (IEditor *editor, editors) { + delete editor; + } +} + +void EditorManager::closeView(Core::Internal::EditorView *view) +{ + if (!view) + return; + + if (view == m_d->m_view) { + if (IEditor *e = view->currentEditor()) + closeEditors(QList() << e); + return; + } + + emptyView(view); + + SplitterOrView *splitterOrView = m_d->m_splitter->findView(view); + Q_ASSERT(splitterOrView); + Q_ASSERT(splitterOrView->view() == view); + SplitterOrView *splitter = m_d->m_splitter->findSplitter(splitterOrView); + Q_ASSERT(splitterOrView->hasEditors() == false); + splitterOrView->hide(); + delete splitterOrView; + + splitter->unsplit(); + + SplitterOrView *newCurrent = splitter->findFirstView(); + if (newCurrent) { + if (newCurrent->editor()) + activateEditor(newCurrent->view(), newCurrent->editor()); + else + setCurrentView(newCurrent); + } +} + +QList + EditorManager::editorsForFiles(QList files) const +{ + const QList editors = openedEditors(); + QSet found; + foreach (IFile *file, files) { + foreach (IEditor *editor, editors) { + if (editor->file() == file && !found.contains(editor)) { + found << editor; + } + } + } + return found.toList(); +} + +QList EditorManager::filesForEditors(QList editors) const +{ + QSet handledEditors; + QList files; + foreach (IEditor *editor, editors) { + if (!handledEditors.contains(editor)) { + files << editor->file(); + handledEditors.insert(editor); + } + } + return files; +} + +bool EditorManager::closeAllEditors(bool askAboutModifiedEditors) +{ + m_d->m_editorModel->removeAllRestoredEditors(); + if (closeEditors(openedEditors(), askAboutModifiedEditors)) { +// m_d->clearNavigationHistory(); + return true; + } + return false; +} + +void EditorManager::closeOtherEditors(IEditor *editor) +{ + m_d->m_editorModel->removeAllRestoredEditors(); + QList editors = openedEditors(); + editors.removeAll(editor); + closeEditors(editors, true); +} + + +void EditorManager::closeOtherEditors() +{ + IEditor *current = currentEditor(); + QTC_ASSERT(current, return); + closeOtherEditors(current); +} + + +// SLOT connected to action +// since this is potentially called in the event handler of the editor +// we simply postpone it with a single shot timer +void EditorManager::closeEditor() +{ + closeEditor(m_d->m_currentEditor); +} + +void EditorManager::closeEditor(Core::IEditor *editor) +{ + if (!editor) + return; + closeEditors(QList() << editor); +} + +void EditorManager::closeEditor(const QModelIndex &index) +{ + IEditor *editor = index.data(Qt::UserRole).value(); + if (editor) + closeEditor(editor); + else + m_d->m_editorModel->removeEditor(index); +} + +bool EditorManager::closeEditors(const QList editorsToClose, bool askAboutModifiedEditors) +{ + if (editorsToClose.isEmpty()) + return true; + + SplitterOrView *currentSplitterOrView = this->currentSplitterOrView(); + + bool closingFailed = false; + QList acceptedEditors; + //ask all core listeners to check whether the editor can be closed + const QList listeners = + pluginManager()->getObjects(); + foreach (IEditor *editor, editorsToClose) { + bool editorAccepted = true; + if (m_d->m_editorModel->isDuplicate(editor)) + editor = m_d->m_editorModel->originalForDuplicate(editor); + foreach (ICoreListener *listener, listeners) { + if (!listener->editorAboutToClose(editor)) { + editorAccepted = false; + closingFailed = false; + break; + } + } + if (editorAccepted) + acceptedEditors.append(editor); + } + if (acceptedEditors.isEmpty()) + return false; + //ask whether to save modified files + if (askAboutModifiedEditors) { + bool cancelled = false; + QList list = m_d->m_core->fileManager()-> + saveModifiedFiles(filesForEditors(acceptedEditors), &cancelled); + if (cancelled) + return false; + if (!list.isEmpty()) { + closingFailed = true; + QSet skipSet = editorsForFiles(list).toSet(); + acceptedEditors = acceptedEditors.toSet().subtract(skipSet).toList(); + } + } + if (acceptedEditors.isEmpty()) + return false; + + // add duplicates + foreach(IEditor *editor, acceptedEditors) + acceptedEditors += m_d->m_editorModel->duplicatesFor(editor); + + QList closedViews; + + // remove the editors + foreach (IEditor *editor, acceptedEditors) { + emit editorAboutToClose(editor); + if (!editor->file()->fileName().isEmpty()) { + QByteArray state = editor->saveState(); + if (!state.isEmpty()) + m_d->m_editorStates.insert(editor->file()->fileName(), QVariant(state)); + } + + removeEditor(editor); + if (SplitterOrView *view = m_d->m_splitter->findView(editor)) { + if (editor == view->view()->currentEditor()) + closedViews += view->view(); + view->view()->removeEditor(editor); + } + } + + foreach (EditorView *view, closedViews) { + IEditor *newCurrent = view->currentEditor(); + if (!newCurrent) + newCurrent = pickUnusedEditor(); + if (newCurrent) { + activateEditor(view, newCurrent, NoActivate); + } else { + QModelIndex idx = m_d->m_editorModel->firstRestoredEditor(); + if (idx.isValid()) + activateEditor(idx, view, NoActivate); + } + } + + emit editorsClosed(acceptedEditors); + + foreach (IEditor *editor, acceptedEditors) { + delete editor; + } + + if (currentSplitterOrView) { + if (IEditor *editor = currentSplitterOrView->editor()) + activateEditor(currentSplitterOrView->view(), editor); + } + + if (!currentEditor()) + emit currentEditorChanged(0); + + return !closingFailed; +} + +void EditorManager::closeDuplicate(Core::IEditor *editor) +{ + + IEditor *original = editor; + if (m_d->m_editorModel->isDuplicate(editor)) + original= m_d->m_editorModel->originalForDuplicate(editor); + QList duplicates = m_d->m_editorModel->duplicatesFor(original); + + if (duplicates.isEmpty()) { + closeEditor(editor); + return; + } + + if (original== editor) + m_d->m_editorModel->makeOriginal(duplicates.first()); + + SplitterOrView *currentSplitterOrView = this->currentSplitterOrView(); + + emit editorAboutToClose(editor); + + EditorView *view = m_d->m_splitter->findView(editor)->view(); + removeEditor(editor); + view->removeEditor(editor); + + IEditor *newCurrent = view->currentEditor(); + if (!newCurrent) + newCurrent = pickUnusedEditor(); + if (newCurrent) { + activateEditor(view, newCurrent, NoActivate); + } else { + QModelIndex idx = m_d->m_editorModel->firstRestoredEditor(); + if (idx.isValid()) + activateEditor(idx, view, NoActivate); + } + + emit editorsClosed(QList() << editor); + delete editor; + if (currentSplitterOrView) { + if (IEditor *currentEditor = currentSplitterOrView->editor()) + activateEditor(currentSplitterOrView->view(), currentEditor); + } +} + +Core::IEditor *EditorManager::pickUnusedEditor() const +{ + foreach (IEditor *editor, openedEditors()) { + SplitterOrView *view = m_d->m_splitter->findView(editor); + if (!view || view->editor() != editor) + return editor; + } + return 0; +} + +Core::IEditor *EditorManager::activateEditor(const QModelIndex &index, Internal::EditorView *view, OpenEditorFlags flags) +{ + IEditor *editor = index.data(Qt::UserRole).value(); + if (editor) { + return activateEditor(view, editor, flags); + } + + QString fileName = index.data(Qt::UserRole + 1).toString(); + QByteArray kind = index.data(Qt::UserRole + 2).toByteArray(); + return openEditor(view, fileName, kind, flags); +} + +Core::IEditor *EditorManager::placeEditor(Core::Internal::EditorView *view, Core::IEditor *editor) +{ + Q_ASSERT(view && editor); + + if (view->currentEditor() && view->currentEditor()->file() == editor->file()) + editor = view->currentEditor(); + + if (!view->hasEditor(editor)) { + bool duplicateSupported = editor->duplicateSupported(); + if (SplitterOrView *sourceView = m_d->m_splitter->findView(editor)) { + if (editor != sourceView->editor() || !duplicateSupported) { + sourceView->view()->removeEditor(editor); + view->addEditor(editor); + view->setCurrentEditor(editor); + if (!sourceView->editor()) { + if (IEditor *replacement = pickUnusedEditor()) { + sourceView->view()->addEditor(replacement); + } + } + return editor; + } else if (duplicateSupported) { + editor = duplicateEditor(editor); + Q_ASSERT(editor); + m_d->m_editorModel->makeOriginal(editor); + } + } + view->addEditor(editor); + } + return editor; +} + +Core::IEditor *EditorManager::activateEditor(Core::IEditor *editor, OpenEditorFlags flags) +{ + return activateEditor(0, editor, flags); +} + +Core::IEditor *EditorManager::activateEditor(Core::Internal::EditorView *view, Core::IEditor *editor, OpenEditorFlags flags) +{ + if (!view) + view = currentEditorView(); + + Q_ASSERT(view); + + if (!editor) { + if (!m_d->m_currentEditor) + setCurrentEditor(0, (flags & IgnoreNavigationHistory)); + return 0; + } + + editor = placeEditor(view, editor); + + if (!(flags & NoActivate)) { + setCurrentEditor(editor, (flags & IgnoreNavigationHistory)); + if (!(flags & NoModeSwitch)) + ensureEditorManagerVisible(); + if (isVisible()) + editor->widget()->setFocus(); + } + return editor; +} + +Core::IEditor *EditorManager::activateEditor(Core::Internal::EditorView *view, Core::IFile *file, OpenEditorFlags flags) +{ + QList editors = editorsForFile(file); + Q_ASSERT(!editors.isEmpty()); + return activateEditor(view, editors.first(), flags); +} + +/* For something that has a 'QStringList mimeTypes' (IEditorFactory + * or IExternalEditor), find the one best matching the mimetype passed in. + * Recurse over the parent classes of the mimetype to find them. */ +template +static void mimeTypeFactoryRecursion(const MimeDatabase *db, + const MimeType &mimeType, + const QList &allFactories, + bool firstMatchOnly, + QList *list) +{ + typedef typename QList::const_iterator EditorFactoryLikeListConstIterator; + // Loop factories to find type + const QString type = mimeType.type(); + const EditorFactoryLikeListConstIterator fcend = allFactories.constEnd(); + for (EditorFactoryLikeListConstIterator fit = allFactories.constBegin(); fit != fcend; ++fit) { + // Exclude duplicates when recursing over xml or C++ -> C -> text. + EditorFactoryLike *factory = *fit; + if (!list->contains(factory) && factory->mimeTypes().contains(type)) { + list->push_back(*fit); + if (firstMatchOnly) + return; + break; + } + } + // Any parent mime type classes? -> recurse + QStringList parentTypes = mimeType.subClassesOf(); + if (parentTypes.empty()) + return; + const QStringList::const_iterator pcend = parentTypes .constEnd(); + for (QStringList::const_iterator pit = parentTypes .constBegin(); pit != pcend; ++pit) { + if (const MimeType parent = db->findByType(*pit)) + mimeTypeFactoryRecursion(db, parent, allFactories, firstMatchOnly, list); + } +} + +EditorManager::EditorFactoryList + EditorManager::editorFactories(const MimeType &mimeType, bool bestMatchOnly) const +{ + EditorFactoryList rc; + const EditorFactoryList allFactories = pluginManager()->getObjects(); + mimeTypeFactoryRecursion(m_d->m_core->mimeDatabase(), mimeType, allFactories, bestMatchOnly, &rc); + if (debugEditorManager) + qDebug() << Q_FUNC_INFO << mimeType.type() << " returns " << rc; + return rc; +} + +EditorManager::ExternalEditorList + EditorManager::externalEditors(const MimeType &mimeType, bool bestMatchOnly) const +{ + ExternalEditorList rc; + const ExternalEditorList allEditors = pluginManager()->getObjects(); + mimeTypeFactoryRecursion(m_d->m_core->mimeDatabase(), mimeType, allEditors, bestMatchOnly, &rc); + if (debugEditorManager) + qDebug() << Q_FUNC_INFO << mimeType.type() << " returns " << rc; + return rc; +} + +/* For something that has a 'QString kind' (IEditorFactory + * or IExternalEditor), find the one matching a kind. */ +template + inline EditorFactoryLike *findByKind(ExtensionSystem::PluginManager *pm, + const QString &kind) +{ + const QList factories = pm->template getObjects(); + foreach(EditorFactoryLike *efl, factories) + if (kind == efl->kind()) + return efl; + return 0; +} + +IEditor *EditorManager::createEditor(const QString &editorKind, + const QString &fileName) +{ + typedef QList FactoryList; + if (debugEditorManager) + qDebug() << Q_FUNC_INFO << editorKind << fileName; + + + EditorFactoryList factories; + if (editorKind.isEmpty()) { + // Find by mime type + MimeType mimeType = m_d->m_core->mimeDatabase()->findByFile(QFileInfo(fileName)); + if (!mimeType) { + qWarning("%s unable to determine mime type of %s/%s. Falling back to text/plain", + Q_FUNC_INFO, fileName.toUtf8().constData(), editorKind.toUtf8().constData()); + mimeType = m_d->m_core->mimeDatabase()->findByType(QLatin1String("text/plain")); + } + factories = editorFactories(mimeType, true); + } else { + // Find by editor kind + if (IEditorFactory *factory = findByKind(pluginManager(), editorKind)) + factories.push_back(factory); + } + if (factories.empty()) { + qWarning("%s: unable to find an editor factory for the file '%s', editor kind '%s'.", + Q_FUNC_INFO, fileName.toUtf8().constData(), editorKind.toUtf8().constData()); + return 0; + } + + IEditor *editor = factories.front()->createEditor(this); + if (editor) + connect(editor, SIGNAL(changed()), this, SLOT(updateActions())); + if (editor) + emit editorCreated(editor, fileName); + return editor; +} + +void EditorManager::addEditor(IEditor *editor, bool isDuplicate) +{ + if (!editor) + return; + m_d->m_core->addContextObject(editor); + + m_d->m_editorModel->addEditor(editor, isDuplicate); + if (!isDuplicate) { + m_d->m_core->fileManager()->addFile(editor->file()); + if (!editor->isTemporary()) { + m_d->m_core->fileManager()->addToRecentFiles(editor->file()->fileName()); + } + } + emit editorOpened(editor); +} + +// Run the OpenWithDialog and return the editor kind +// selected by the user. +QString EditorManager::getOpenWithEditorKind(const QString &fileName, + bool *isExternalEditor) const +{ + // Collect editors that can open the file + const MimeType mt = m_d->m_core->mimeDatabase()->findByFile(fileName); + if (!mt) + return QString(); + QStringList allEditorKinds; + QStringList externalEditorKinds; + // Built-in + const EditorFactoryList editors = editorFactories(mt, false); + const int size = editors.size(); + for (int i = 0; i < size; i++) { + allEditorKinds.push_back(editors.at(i)->kind()); + } + // External editors + const ExternalEditorList exEditors = externalEditors(mt, false); + const int esize = exEditors.size(); + for (int i = 0; i < esize; i++) { + externalEditorKinds.push_back(exEditors.at(i)->kind()); + allEditorKinds.push_back(exEditors.at(i)->kind()); + } + if (allEditorKinds.empty()) + return QString(); + // Run dialog. + OpenWithDialog dialog(fileName, m_d->m_core->mainWindow()); + dialog.setEditors(allEditorKinds); + dialog.setCurrentEditor(0); + if (dialog.exec() != QDialog::Accepted) + return QString(); + const QString selectedKind = dialog.editor(); + if (isExternalEditor) + *isExternalEditor = externalEditorKinds.contains(selectedKind); + return selectedKind; +} + +static QString formatFileFilters(const Core::ICore *core, QString *selectedFilter) +{ + QString rc; + // Compile list of filter strings. If we find a glob matching all files, + // put it last and set it as default selectedFilter. + QStringList filters = core->mimeDatabase()->filterStrings(); + filters.sort(); + selectedFilter->clear(); + if (filters.empty()) + return rc; + const QString filterSeparator = QLatin1String(";;"); + bool hasAllFilter = false; + const int size = filters.size(); + for (int i = 0; i < size; i++) { + const QString &filterString = filters.at(i); + if (filterString.isEmpty()) { // binary editor + hasAllFilter = true; + } else { + if (!rc.isEmpty()) + rc += filterSeparator; + rc += filterString; + } + } + if (hasAllFilter) { + // prepend all files filter + // prepending instead of appending to work around a but in Qt/Mac + QString allFilesFilter = EditorManager::tr("All Files (*)"); + if (!rc.isEmpty()) + allFilesFilter += filterSeparator; + rc.prepend(allFilesFilter); + *selectedFilter = allFilesFilter; + } else { + *selectedFilter = filters.front(); + } + return rc; +} + +IEditor *EditorManager::openEditor(const QString &fileName, const QString &editorKind, + EditorManager::OpenEditorFlags flags) +{ + return openEditor(0, fileName, editorKind, flags); +} + +IEditor *EditorManager::openEditor(Core::Internal::EditorView *view, const QString &fileName, + const QString &editorKind, EditorManager::OpenEditorFlags flags) +{ + if (debugEditorManager) + qDebug() << Q_FUNC_INFO << fileName << editorKind; + + if (fileName.isEmpty()) + return 0; + + const QList editors = editorsForFileName(fileName); + if (!editors.isEmpty()) { + return activateEditor(view, editors.first(), flags); + } + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + IEditor *editor = createEditor(editorKind, fileName); + if (!editor || !editor->open(fileName)) { + QApplication::restoreOverrideCursor(); + QMessageBox::critical(m_d->m_core->mainWindow(), tr("Opening File"), tr("Cannot open file %1!").arg(QDir::toNativeSeparators(fileName))); + delete editor; + editor = 0; + return 0; + } + addEditor(editor); + + IEditor *result= activateEditor(view, editor, flags); + if (editor == result) + restoreEditorState(editor); + QApplication::restoreOverrideCursor(); + return result; +} + +bool EditorManager::openExternalEditor(const QString &fileName, const QString &editorKind) +{ + IExternalEditor *ee = findByKind(pluginManager(), editorKind); + if (!ee) + return false; + QString errorMessage; + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + const bool ok = ee->startEditor(fileName, &errorMessage); + QApplication::restoreOverrideCursor(); + if (!ok) + QMessageBox::critical(m_d->m_core->mainWindow(), tr("Opening File"), errorMessage); + return ok; +} + +QStringList EditorManager::getOpenFileNames() const +{ + static QString dir = QDir::homePath(); + if (m_d->fileFilters.isEmpty()) + m_d->fileFilters = formatFileFilters(m_d->m_core, &m_d->selectedFilter); + + QString currentFile = ICore::instance()->fileManager()->currentFile(); + if (!currentFile.isEmpty()) { + const QFileInfo fi(currentFile); + dir = fi.absolutePath(); + } + + QStringList files = QFileDialog::getOpenFileNames(m_d->m_core->mainWindow(), tr("Open File"), + dir, m_d->fileFilters, &m_d->selectedFilter); + if (!files.isEmpty()) + dir = QFileInfo(files.at(0)).absolutePath(); + return files; +} + +void EditorManager::ensureEditorManagerVisible() +{ + if (!isVisible()) + m_d->m_core->modeManager()->activateMode(Constants::MODE_EDIT); +} + +IEditor *EditorManager::openEditorWithContents(const QString &editorKind, + QString *titlePattern, + const QString &contents) +{ + if (debugEditorManager) + qDebug() << Q_FUNC_INFO << editorKind << titlePattern << contents; + + if (editorKind.isEmpty()) + return 0; + + QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); + IEditor *edt = createEditor(editorKind); + if (!edt) { + QApplication::restoreOverrideCursor(); + return 0; + } + + if (!edt->createNew(contents)) { + QApplication::restoreOverrideCursor(); + delete edt; + edt = 0; + return 0; + } + + QString title = edt->displayName(); + + if (title.isEmpty() && titlePattern) { + const QChar dollar = QLatin1Char('$'); + const QChar dot = QLatin1Char('.'); + + QString base = *titlePattern; + if (base.isEmpty()) + base = QLatin1String("unnamed$"); + if (base.contains(dollar)) { + int i = 1; + QSet docnames; + foreach (IEditor *editor, openedEditors()) { + QString name = editor->file()->fileName(); + if (name.isEmpty()) { + name = editor->displayName(); + name.remove(QLatin1Char('*')); + } else { + name = QFileInfo(name).completeBaseName(); + } + docnames << name; + } + + do { + title = base; + title.replace(QString(dollar), QString::number(i++)); + } while (docnames.contains(title)); + } else { + title = *titlePattern; + } + } + *titlePattern = title; + edt->setDisplayName(title); + addEditor(edt); + QApplication::restoreOverrideCursor(); + return edt; +} + +bool EditorManager::hasEditor(const QString &fileName) const +{ + return !editorsForFileName(fileName).isEmpty(); +} + +void EditorManager::restoreEditorState(IEditor *editor) +{ + QTC_ASSERT(editor, return); + QString fileName = editor->file()->fileName(); + if (m_d->m_editorStates.contains(fileName)) + editor->restoreState(m_d->m_editorStates.value(fileName).toByteArray()); +} + +bool EditorManager::saveEditor(IEditor *editor) +{ + return saveFile(editor); +} + +bool EditorManager::saveFile(IEditor *editor) +{ + if (!editor) + editor = currentEditor(); + if (!editor) + return false; + + IFile *file = editor->file(); + file->checkPermissions(); + + const QString &fileName = file->fileName(); + + if (fileName.isEmpty()) + return saveFileAs(editor); + + bool success = false; + + // try saving, no matter what isReadOnly tells us + m_d->m_core->fileManager()->blockFileChange(file); + success = file->save(fileName); + m_d->m_core->fileManager()->unblockFileChange(file); + + if (!success) { + MakeWritableResult answer = + makeEditorWritable(editor); + if (answer == Failed) + return false; + if (answer == SavedAs) + return true; + + file->checkPermissions(); + + m_d->m_core->fileManager()->blockFileChange(file); + success = file->save(fileName); + m_d->m_core->fileManager()->unblockFileChange(file); + } + + if (success && !editor->isTemporary()) + m_d->m_core->fileManager()->addToRecentFiles(editor->file()->fileName()); + + return success; +} + +EditorManager::ReadOnlyAction + EditorManager::promptReadOnlyFile(const QString &fileName, + const IVersionControl *versionControl, + QWidget *parent, + bool displaySaveAsButton) +{ + QMessageBox msgBox(QMessageBox::Question, tr("File is Read Only"), + tr("The file %1 is read only.").arg(QDir::toNativeSeparators(fileName)), + QMessageBox::Cancel, parent); + + QPushButton *sccButton = 0; + if (versionControl && versionControl->supportsOperation(IVersionControl::OpenOperation)) + sccButton = msgBox.addButton(tr("Open with VCS (%1)").arg(versionControl->name()), QMessageBox::AcceptRole); + + QPushButton *makeWritableButton = msgBox.addButton(tr("Make writable"), QMessageBox::AcceptRole); + + QPushButton *saveAsButton = 0; + if (displaySaveAsButton) + saveAsButton = msgBox.addButton(tr("Save as ..."), QMessageBox::ActionRole); + + msgBox.setDefaultButton(sccButton ? sccButton : makeWritableButton); + msgBox.exec(); + + QAbstractButton *clickedButton = msgBox.clickedButton(); + if (clickedButton == sccButton) + return RO_OpenVCS; + if (clickedButton == makeWritableButton) + return RO_MakeWriteable; + if (clickedButton == saveAsButton) + return RO_SaveAs; + return RO_Cancel; +} + + +MakeWritableResult +EditorManager::makeEditorWritable(IEditor *editor) +{ + if (!editor || !editor->file()) + return Failed; + QString directory = QFileInfo(editor->file()->fileName()).absolutePath(); + IVersionControl *versionControl = m_d->m_core->vcsManager()->findVersionControlForDirectory(directory); + IFile *file = editor->file(); + const QString &fileName = file->fileName(); + + switch (promptReadOnlyFile(fileName, versionControl, m_d->m_core->mainWindow(), true)) { + case RO_OpenVCS: + if (!versionControl->vcsOpen(fileName)) { + QMessageBox::warning(m_d->m_core->mainWindow(), tr("Failed!"), tr("Could not open the file for editing with SCC.")); + return Failed; + } + file->checkPermissions(); + return OpenedWithVersionControl; + case RO_MakeWriteable: { + const bool permsOk = QFile::setPermissions(fileName, QFile::permissions(fileName) | QFile::WriteUser); + if (!permsOk) { + QMessageBox::warning(m_d->m_core->mainWindow(), tr("Failed!"), tr("Could not set permissions to writable.")); + return Failed; + } + } + file->checkPermissions(); + return MadeWritable; + case RO_SaveAs : + return saveFileAs(editor) ? SavedAs : Failed; + case RO_Cancel: + break; + } + return Failed; +} + +bool EditorManager::saveFileAs(IEditor *editor) +{ + if (!editor) + editor = currentEditor(); + if (!editor) + return false; + + QString absoluteFilePath = m_d->m_core->fileManager()->getSaveAsFileName(editor->file()); + if (absoluteFilePath.isEmpty()) + return false; + if (absoluteFilePath != editor->file()->fileName()) { + const QList existList = editorsForFileName(absoluteFilePath); + if (!existList.isEmpty()) { + closeEditors(existList, false); + } + } + + m_d->m_core->fileManager()->blockFileChange(editor->file()); + const bool success = editor->file()->save(absoluteFilePath); + m_d->m_core->fileManager()->unblockFileChange(editor->file()); + editor->file()->checkPermissions(); + + if (success && !editor->isTemporary()) + m_d->m_core->fileManager()->addToRecentFiles(editor->file()->fileName()); + + updateActions(); + return success; +} + +void EditorManager::gotoNextDocHistory() +{ + OpenEditorsWindow *dialog = windowPopup(); + if (dialog->isVisible()) { + dialog->selectNextEditor(); + } else { + EditorView *view = currentEditorView(); + dialog->setEditors(m_d->m_view, view, m_d->m_editorModel); + dialog->selectNextEditor(); + showWindowPopup(); + } +} + +void EditorManager::gotoPreviousDocHistory() +{ + OpenEditorsWindow *dialog = windowPopup(); + if (dialog->isVisible()) { + dialog->selectPreviousEditor(); + } else { + EditorView *view = currentEditorView(); + dialog->setEditors(m_d->m_view, view, m_d->m_editorModel); + dialog->selectPreviousEditor(); + showWindowPopup(); + } +} + +void EditorManager::makeCurrentEditorWritable() +{ + if (IEditor* curEditor = currentEditor()) + makeEditorWritable(curEditor); +} + +void EditorManager::updateActions() +{ + QString fName; + IEditor *curEditor = currentEditor(); + int openedCount = openedEditors().count() + m_d->m_editorModel->restoredEditorCount(); + if (curEditor) { + if (!curEditor->file()->fileName().isEmpty()) { + QFileInfo fi(curEditor->file()->fileName()); + fName = fi.fileName(); + } else { + fName = curEditor->displayName(); + } + + + if (curEditor->file()->isModified() && curEditor->file()->isReadOnly()) { + // we are about to change a read-only file, warn user + showEditorInfoBar(QLatin1String("Core.EditorManager.MakeWritable"), + tr("Warning: You are changing a read-only file."), + tr("Make writable"), this, SLOT(makeCurrentEditorWritable())); + } else { + hideEditorInfoBar(QLatin1String("Core.EditorManager.MakeWritable")); + } + } + + m_d->m_saveAction->setEnabled(curEditor != 0 && curEditor->file()->isModified()); + m_d->m_saveAsAction->setEnabled(curEditor != 0 && curEditor->file()->isSaveAsAllowed()); + m_d->m_revertToSavedAction->setEnabled(curEditor != 0 + && !curEditor->file()->fileName().isEmpty() && curEditor->file()->isModified()); + + QString quotedName; + if (!fName.isEmpty()) + quotedName = '"' + fName + '"'; + m_d->m_saveAsAction->setText(tr("Save %1 As...").arg(quotedName)); + m_d->m_saveAction->setText(tr("&Save %1").arg(quotedName)); + m_d->m_revertToSavedAction->setText(tr("Revert %1 to Saved").arg(quotedName)); + + + m_d->m_closeCurrentEditorAction->setEnabled(curEditor != 0); + m_d->m_closeCurrentEditorAction->setText(tr("Close %1").arg(quotedName)); + m_d->m_closeAllEditorsAction->setEnabled(openedCount > 0); + m_d->m_closeOtherEditorsAction->setEnabled(openedCount > 1); + m_d->m_closeOtherEditorsAction->setText((openedCount > 1 ? tr("Close All Except %1").arg(quotedName) : tr("Close Others"))); + + m_d->m_gotoNextDocHistoryAction->setEnabled(m_d->m_editorModel->rowCount() != 0); + m_d->m_gotoPreviousDocHistoryAction->setEnabled(m_d->m_editorModel->rowCount() != 0); + EditorView *view = currentEditorView(); + m_d->m_goBackAction->setEnabled(view ? view->canGoBack() : false); + m_d->m_goForwardAction->setEnabled(view ? view->canGoForward() : false); + + bool hasSplitter = m_d->m_splitter->isSplitter(); + m_d->m_removeCurrentSplitAction->setEnabled(hasSplitter); + m_d->m_removeAllSplitsAction->setEnabled(hasSplitter); + m_d->m_gotoOtherSplitAction->setEnabled(hasSplitter); + + m_d->m_openInExternalEditorAction->setEnabled(curEditor != 0); +} + +QList EditorManager::openedEditors() const +{ + return m_d->m_editorModel->editors(); +} + +OpenEditorsModel *EditorManager::openedEditorsModel() const +{ + return m_d->m_editorModel; +} + +void EditorManager::addCurrentPositionToNavigationHistory(IEditor *editor, const QByteArray &saveState) +{ + currentEditorView()->addCurrentPositionToNavigationHistory(editor, saveState); + updateActions(); +} + +void EditorManager::goBackInNavigationHistory() +{ + currentEditorView()->goBackInNavigationHistory(); + updateActions(); + ensureEditorManagerVisible(); + return; +} + +void EditorManager::goForwardInNavigationHistory() +{ + currentEditorView()->goForwardInNavigationHistory(); + updateActions(); + ensureEditorManagerVisible(); +} + +OpenEditorsWindow *EditorManager::windowPopup() const +{ + return m_d->m_windowPopup; +} + +void EditorManager::showWindowPopup() const +{ + const QPoint p(mapToGlobal(QPoint(0, 0))); + m_d->m_windowPopup->move((width()-m_d->m_windowPopup->width())/2 + p.x(), + (height()-m_d->m_windowPopup->height())/2 + p.y()); + m_d->m_windowPopup->setVisible(true); +} + +QByteArray EditorManager::saveState() const +{ + QByteArray bytes; + QDataStream stream(&bytes, QIODevice::WriteOnly); + + stream << QByteArray("EditorManagerV4"); + + QList editors = openedEditors(); + foreach (IEditor *editor, editors) { + if (!editor->file()->fileName().isEmpty()) { + QByteArray state = editor->saveState(); + if (!state.isEmpty()) + m_d->m_editorStates.insert(editor->file()->fileName(), QVariant(state)); + } + } + + stream << m_d->m_editorStates; + + QList entries = m_d->m_editorModel->entries(); + stream << entries.count(); + + foreach (OpenEditorsModel::Entry entry, entries) { + stream << entry.fileName() << entry.displayName() << entry.kind(); + } + + stream << m_d->m_splitter->saveState(); + + return bytes; +} + +bool EditorManager::restoreState(const QByteArray &state) +{ + closeAllEditors(true); + removeAllSplits(); + QDataStream stream(state); + + QByteArray version; + stream >> version; + + if (version != "EditorManagerV4") + return false; + + QMap editorstates; + + QApplication::setOverrideCursor(Qt::WaitCursor); + + stream >> editorstates; + + QMapIterator i(editorstates); + while (i.hasNext()) { + i.next(); + m_d->m_editorStates.insert(i.key(), i.value()); + } + + int editorCount = 0; + stream >> editorCount; + while (--editorCount >= 0) { + QString fileName; + stream >> fileName; + QString displayName; + stream >> displayName; + QByteArray kind; + stream >> kind; + + if (!fileName.isEmpty() && !displayName.isEmpty()){ + m_d->m_editorModel->addRestoredEditor(fileName, displayName, kind); + } + } + + QByteArray splitterstates; + stream >> splitterstates; + m_d->m_splitter->restoreState(splitterstates); + + // splitting and stuff results in focus trouble, that's why we set the focus again after restoration + ensureEditorManagerVisible(); + if (m_d->m_currentEditor) { + m_d->m_currentEditor->widget()->setFocus(); + } else if (Core::Internal::SplitterOrView *view = currentSplitterOrView()) { + if (IEditor *e = view->editor()) + e->widget()->setFocus(); + else if (view->view()) + view->view()->setFocus(); + } + + QApplication::restoreOverrideCursor(); + + return true; +} + +static const char * const documentStatesKey = "EditorManager/DocumentStates"; +static const char * const externalEditorKey = "EditorManager/ExternalEditorCommand"; +static const char * const reloadBehaviorKey = "EditorManager/ReloadBehavior"; + +void EditorManager::saveSettings() +{ + SettingsDatabase *settings = m_d->m_core->settingsDatabase(); + settings->setValue(QLatin1String(documentStatesKey), m_d->m_editorStates); + settings->setValue(QLatin1String(externalEditorKey), m_d->m_externalEditor); + settings->setValue(QLatin1String(reloadBehaviorKey), m_d->m_reloadBehavior); +} + +void EditorManager::readSettings() +{ + // Backward compatibility to old locations for these settings + QSettings *qs = m_d->m_core->settings(); + if (qs->contains(QLatin1String(documentStatesKey))) { + m_d->m_editorStates = qs->value(QLatin1String(documentStatesKey)) + .value >(); + qs->remove(QLatin1String(documentStatesKey)); + } + if (qs->contains(QLatin1String(externalEditorKey))) { + m_d->m_externalEditor = qs->value(QLatin1String(externalEditorKey)).toString(); + qs->remove(QLatin1String(externalEditorKey)); + } + + SettingsDatabase *settings = m_d->m_core->settingsDatabase(); + if (settings->contains(QLatin1String(documentStatesKey))) + m_d->m_editorStates = settings->value(QLatin1String(documentStatesKey)) + .value >(); + if (settings->contains(QLatin1String(externalEditorKey))) + m_d->m_externalEditor = settings->value(QLatin1String(externalEditorKey)).toString(); + + if (settings->contains(QLatin1String(reloadBehaviorKey))) + m_d->m_reloadBehavior = (IFile::ReloadBehavior)settings->value(QLatin1String(reloadBehaviorKey)).toInt(); +} + + +void EditorManager::revertToSaved() +{ + IEditor *currEditor = currentEditor(); + if (!currEditor) + return; + const QString fileName = currEditor->file()->fileName(); + if (fileName.isEmpty()) + return; + if (currEditor->file()->isModified()) { + QMessageBox msgBox(QMessageBox::Question, tr("Revert to Saved"), + tr("You will lose your current changes if you proceed reverting %1.").arg(QDir::toNativeSeparators(fileName)), + QMessageBox::Yes|QMessageBox::No, m_d->m_core->mainWindow()); + msgBox.button(QMessageBox::Yes)->setText(tr("Proceed")); + msgBox.button(QMessageBox::No)->setText(tr("Cancel")); + msgBox.setDefaultButton(QMessageBox::No); + msgBox.setEscapeButton(QMessageBox::No); + if (msgBox.exec() == QMessageBox::No) + return; + + } + IFile::ReloadBehavior temp = IFile::ReloadAll; + currEditor->file()->modified(&temp); +} + +void EditorManager::showEditorInfoBar(const QString &kind, + const QString &infoText, + const QString &buttonText, + QObject *object, const char *member) +{ + + currentEditorView()->showEditorInfoBar(kind, infoText, buttonText, object, member); +} + + +void EditorManager::hideEditorInfoBar(const QString &kind) +{ + Core::Internal::EditorView *cev = currentEditorView(); + if (cev) + cev->hideEditorInfoBar(kind); +} + +void EditorManager::showEditorStatusBar(const QString &kind, + const QString &infoText, + const QString &buttonText, + QObject *object, const char *member) +{ + + currentEditorView()->showEditorStatusBar(kind, infoText, buttonText, object, member); +} + +void EditorManager::hideEditorStatusBar(const QString &kind) +{ + currentEditorView()->hideEditorStatusBar(kind); +} + +QString EditorManager::externalEditorHelpText() const +{ + QString help = tr( + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "" + "
VariableExpands to
%ffile name
%lcurrent line number
%ccurrent column number
%xeditor's x position on screen
%yeditor's y position on screen
%weditor's width in pixels
%heditor's height in pixels
%Weditor's width in characters
%Heditor's height in characters
%%%
"); + return help; +} + +void EditorManager::openInExternalEditor() +{ + QString command = m_d->m_externalEditor; + if (command.isEmpty()) + command = defaultExternalEditor(); + + if (command.isEmpty()) + return; + + IEditor *editor = currentEditor(); + if (!editor) + return; + if (editor->file()->isModified()) { + bool cancelled = false; + QList list = m_d->m_core->fileManager()-> + saveModifiedFiles(QList() << editor->file(), &cancelled); + if (cancelled) + return; + } + + QRect rect = editor->widget()->rect(); + QFont font = editor->widget()->font(); + QFontMetrics fm(font); + rect.moveTo(editor->widget()->mapToGlobal(QPoint(0,0))); + + QString pre = command; + QString cmd; + for (int i = 0; i < pre.size(); ++i) { + QChar c = pre.at(i); + if (c == QLatin1Char('%') && i < pre.size()-1) { + c = pre.at(++i); + QString s; + if (c == QLatin1Char('f')) + s = editor->file()->fileName(); + else if (c == QLatin1Char('l')) + s = QString::number(editor->currentLine()); + else if (c == QLatin1Char('c')) + s = QString::number(editor->currentColumn()); + else if (c == QLatin1Char('x')) + s = QString::number(rect.x()); + else if (c == QLatin1Char('y')) + s = QString::number(rect.y()); + else if (c == QLatin1Char('w')) + s = QString::number(rect.width()); + else if (c == QLatin1Char('h')) + s = QString::number(rect.height()); + else if (c == QLatin1Char('W')) + s = QString::number(rect.width() / fm.width(QLatin1Char('x'))); + else if (c == QLatin1Char('H')) + s = QString::number(rect.height() / fm.lineSpacing()); + else if (c == QLatin1Char('%')) + s = c; + else { + s = QLatin1Char('%'); + cmd += c; + } + cmd += s; + continue; + + } + cmd += c; + } + + QProcess::startDetached(cmd); +} + +void EditorManager::setExternalEditor(const QString &editor) +{ + if (editor.isEmpty() || editor == defaultExternalEditor()) + m_d->m_externalEditor = defaultExternalEditor(); + else + m_d->m_externalEditor = editor; +} + +QString EditorManager::externalEditor() const +{ + if (m_d->m_externalEditor.isEmpty()) + return defaultExternalEditor(); + return m_d->m_externalEditor; +} + +void EditorManager::setReloadBehavior(IFile::ReloadBehavior behavior) +{ + m_d->m_reloadBehavior = behavior; +} + +IFile::ReloadBehavior EditorManager::reloadBehavior() const +{ + return m_d->m_reloadBehavior; +} + +Core::IEditor *EditorManager::duplicateEditor(Core::IEditor *editor) +{ + if (!editor->duplicateSupported()) + return 0; + + IEditor *duplicate = editor->duplicate(0); + duplicate->restoreState(editor->saveState()); + emit editorCreated(duplicate, duplicate->file()->fileName()); + addEditor(duplicate, true); + return duplicate; +} + +void EditorManager::split(Qt::Orientation orientation) +{ + SplitterOrView *view = m_d->m_currentView; + if (!view) + view = m_d->m_currentEditor ? m_d->m_splitter->findView(m_d->m_currentEditor) + : m_d->m_splitter->findFirstView(); + if (view && !view->splitter()) { + view->split(orientation); + } + updateActions(); +} + +void EditorManager::split() +{ + split(Qt::Vertical); +} + +void EditorManager::splitSideBySide() +{ + split(Qt::Horizontal); +} + +void EditorManager::removeCurrentSplit() +{ + SplitterOrView *viewToClose = m_d->m_currentView; + if (!viewToClose && m_d->m_currentEditor) + viewToClose = m_d->m_splitter->findView(m_d->m_currentEditor); + + if (!viewToClose || viewToClose->isSplitter() || viewToClose == m_d->m_splitter) + return; + + closeView(viewToClose->view()); + updateActions(); +} + +void EditorManager::removeAllSplits() +{ + if (!m_d->m_splitter->isSplitter()) + return; + IEditor *editor = m_d->m_currentEditor; + m_d->m_currentEditor = 0; // trigger update below + if (editor && m_d->m_editorModel->isDuplicate(editor)) + editor = m_d->m_editorModel->originalForDuplicate(editor); + m_d->m_splitter->unsplitAll(); + if (!editor) + editor = pickUnusedEditor(); + activateEditor(editor); +} + +void EditorManager::gotoOtherSplit() +{ + if (m_d->m_splitter->isSplitter()) { + SplitterOrView *currentView = m_d->m_currentView; + if (!currentView && m_d->m_currentEditor) + currentView = m_d->m_splitter->findView(m_d->m_currentEditor); + if (!currentView) + currentView = m_d->m_splitter->findFirstView(); + SplitterOrView *view = m_d->m_splitter->findNextView(currentView); + if (!view) + view = m_d->m_splitter->findFirstView(); + if (view) { + if (IEditor *editor = view->editor()) { + setCurrentEditor(editor, true); + editor->widget()->setFocus(); + } else { + setCurrentView(view); + } + } + } +} +//===================EditorClosingCoreListener====================== + +EditorClosingCoreListener::EditorClosingCoreListener(EditorManager *em) + : m_em(em) +{ +} + +bool EditorClosingCoreListener::editorAboutToClose(IEditor *) +{ + return true; +} + +bool EditorClosingCoreListener::coreAboutToClose() +{ + // Do not ask for files to save. + // MainWindow::closeEvent has already done that. + return m_em->closeAllEditors(false); +} diff --git a/ground/src/plugins/coreplugin/editormanager/editorview.cpp b/ground/src/plugins/coreplugin/editormanager/editorview.cpp index 951484aa4..e86b6701f 100644 --- a/ground/src/plugins/coreplugin/editormanager/editorview.cpp +++ b/ground/src/plugins/coreplugin/editormanager/editorview.cpp @@ -1,1012 +1,1012 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://qt.nokia.com/contact. -** -**************************************************************************/ - -#include "editorview.h" -#include "editormanager.h" -#include "coreimpl.h" -#include "minisplitter.h" -#include "openeditorsmodel.h" -#include -#include -#include - -#include -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef Q_WS_MAC -#include -#endif - -Q_DECLARE_METATYPE(Core::IEditor *) - -using namespace Core; -using namespace Core::Internal; - - -// ================EditorView==================== - -EditorView::EditorView(OpenEditorsModel *model, QWidget *parent) : - QWidget(parent), - m_model(model), - m_toolBar(new QWidget), - m_container(new QStackedWidget(this)), - m_editorList(new QComboBox), - m_closeButton(new QToolButton), - m_lockButton(new QToolButton), - m_defaultToolBar(new QWidget(this)), - m_infoWidget(new QFrame(this)), - m_editorForInfoWidget(0), - m_statusHLine(new QFrame(this)), - m_statusWidget(new QFrame(this)), - m_currentNavigationHistoryPosition(0) -{ - - m_goBackAction = new QAction(QIcon(QLatin1String(":/help/images/previous.png")), tr("Go Back"), this); - connect(m_goBackAction, SIGNAL(triggered()), this, SLOT(goBackInNavigationHistory())); - m_goForwardAction = new QAction(QIcon(QLatin1String(":/help/images/next.png")), tr("Go Forward"), this); - connect(m_goForwardAction, SIGNAL(triggered()), this, SLOT(goForwardInNavigationHistory())); - - QVBoxLayout *tl = new QVBoxLayout(this); - tl->setSpacing(0); - tl->setMargin(0); - { - if (!m_model) { - m_model = CoreImpl::instance()->editorManager()->openedEditorsModel(); - } - - QToolButton *backButton = new QToolButton; - backButton->setDefaultAction(m_goBackAction); - - QToolButton *forwardButton= new QToolButton; - forwardButton->setDefaultAction(m_goForwardAction); - - m_editorList->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); - m_editorList->setMinimumContentsLength(20); - m_editorList->setModel(m_model); - m_editorList->setMaxVisibleItems(40); - m_editorList->setContextMenuPolicy(Qt::CustomContextMenu); - - m_defaultToolBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - m_activeToolBar = m_defaultToolBar; - - QHBoxLayout *toolBarLayout = new QHBoxLayout; - toolBarLayout->setMargin(0); - toolBarLayout->setSpacing(0); - toolBarLayout->addWidget(m_defaultToolBar); - m_toolBar->setLayout(toolBarLayout); - m_toolBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); - - m_lockButton->setAutoRaise(true); - - m_closeButton->setAutoRaise(true); - m_closeButton->setIcon(QIcon(":/core/images/closebutton.png")); - - - QHBoxLayout *toplayout = new QHBoxLayout; - toplayout->setSpacing(0); - toplayout->setMargin(0); - toplayout->addWidget(backButton); - toplayout->addWidget(forwardButton); - toplayout->addWidget(m_editorList); - toplayout->addWidget(m_toolBar, 1); // Custom toolbar stretches - toplayout->addWidget(m_lockButton); - toplayout->addWidget(m_closeButton); - - Utils::StyledBar *top = new Utils::StyledBar; - top->setLayout(toplayout); - tl->addWidget(top); - - connect(m_editorList, SIGNAL(activated(int)), this, SLOT(listSelectionActivated(int))); - connect(m_editorList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(listContextMenu(QPoint))); - connect(m_lockButton, SIGNAL(clicked()), this, SLOT(makeEditorWritable())); - connect(m_closeButton, SIGNAL(clicked()), this, SLOT(closeView()), Qt::QueuedConnection); - } - { - m_infoWidget->setFrameStyle(QFrame::Panel | QFrame::Raised); - m_infoWidget->setLineWidth(1); - m_infoWidget->setForegroundRole(QPalette::ToolTipText); - m_infoWidget->setBackgroundRole(QPalette::ToolTipBase); - m_infoWidget->setAutoFillBackground(true); - - QHBoxLayout *hbox = new QHBoxLayout(m_infoWidget); - hbox->setMargin(2); - m_infoWidgetLabel = new QLabel("Placeholder"); - m_infoWidgetLabel->setForegroundRole(QPalette::ToolTipText); - hbox->addWidget(m_infoWidgetLabel); - hbox->addStretch(1); - - m_infoWidgetButton = new QToolButton; - m_infoWidgetButton->setText(tr("Placeholder")); - hbox->addWidget(m_infoWidgetButton); - - QToolButton *closeButton = new QToolButton; - closeButton->setAutoRaise(true); - closeButton->setIcon(QIcon(":/core/images/clear.png")); - closeButton->setToolTip(tr("Close")); - connect(closeButton, SIGNAL(clicked()), m_infoWidget, SLOT(hide())); - - hbox->addWidget(closeButton); - - m_infoWidget->setVisible(false); - tl->addWidget(m_infoWidget); - } - - tl->addWidget(m_container); - - tl->addWidget(new FindToolBarPlaceHolder(this)); - - { - m_statusHLine->setFrameStyle(QFrame::HLine); - - m_statusWidget->setFrameStyle(QFrame::Panel | QFrame::Raised); - m_statusWidget->setLineWidth(1); - //m_statusWidget->setForegroundRole(QPalette::ToolTipText); - //m_statusWidget->setBackgroundRole(QPalette::ToolTipBase); - m_statusWidget->setAutoFillBackground(true); - - - QHBoxLayout *hbox = new QHBoxLayout(m_statusWidget); - hbox->setMargin(2); - m_statusWidgetLabel = new QLabel("Placeholder"); - m_statusWidgetLabel->setForegroundRole(QPalette::ToolTipText); - hbox->addWidget(m_statusWidgetLabel); - hbox->addStretch(1); - - m_statusWidgetButton = new QToolButton; - m_statusWidgetButton->setText(tr("Placeholder")); - hbox->addWidget(m_statusWidgetButton); - - m_statusHLine->setVisible(false); - m_statusWidget->setVisible(false); - tl->addWidget(m_statusHLine); - tl->addWidget(m_statusWidget); - } - - - ActionManager *am = ICore::instance()->actionManager(); - connect(am->command(Constants::CLOSE), SIGNAL(keySequenceChanged()), - this, SLOT(updateActionShortcuts())); - connect(am->command(Constants::GO_BACK), SIGNAL(keySequenceChanged()), - this, SLOT(updateActionShortcuts())); - connect(am->command(Constants::GO_FORWARD), SIGNAL(keySequenceChanged()), - this, SLOT(updateActionShortcuts())); - - updateActionShortcuts(); - updateActions(); -} - -EditorView::~EditorView() -{ -} - -void EditorView::showEditorInfoBar(const QString &kind, - const QString &infoText, - const QString &buttonText, - QObject *object, const char *member) -{ - m_infoWidgetKind = kind; - m_infoWidgetLabel->setText(infoText); - m_infoWidgetButton->setText(buttonText); - m_infoWidgetButton->disconnect(); - if (object && member) - connect(m_infoWidgetButton, SIGNAL(clicked()), object, member); - m_infoWidget->setVisible(true); - m_editorForInfoWidget = currentEditor(); -} - -void EditorView::hideEditorInfoBar(const QString &kind) -{ - if (kind == m_infoWidgetKind) - m_infoWidget->setVisible(false); -} - -void EditorView::showEditorStatusBar(const QString &kind, - const QString &infoText, - const QString &buttonText, - QObject *object, const char *member) -{ - m_statusWidgetKind = kind; - m_statusWidgetLabel->setText(infoText); - m_statusWidgetButton->setText(buttonText); - m_statusWidgetButton->disconnect(); - if (object && member) - connect(m_statusWidgetButton, SIGNAL(clicked()), object, member); - m_statusWidget->setVisible(true); - m_statusHLine->setVisible(true); - //m_editorForInfoWidget = currentEditor(); -} - -void EditorView::hideEditorStatusBar(const QString &kind) -{ - if (kind == m_statusWidgetKind) { - m_statusWidget->setVisible(false); - m_statusHLine->setVisible(false); - } -} - -void EditorView::addEditor(IEditor *editor) -{ - if (m_editors.contains(editor)) - return; - - m_editors.append(editor); - - m_container->addWidget(editor->widget()); - m_widgetEditorMap.insert(editor->widget(), editor); - - QWidget *toolBar = editor->toolBar(); - if (toolBar) { - toolBar->setVisible(false); // will be made visible in setCurrentEditor - m_toolBar->layout()->addWidget(toolBar); - } - connect(editor, SIGNAL(changed()), this, SLOT(checkEditorStatus())); - - if (editor == currentEditor()) - setCurrentEditor(editor); -} - -bool EditorView::hasEditor(IEditor *editor) const -{ - return m_editors.contains(editor); -} - -void EditorView::closeView() -{ - EditorManager *em = CoreImpl::instance()->editorManager(); - if (IEditor *editor = currentEditor()) { - em->closeDuplicate(editor); - } -} - -void EditorView::removeEditor(IEditor *editor) -{ - QTC_ASSERT(editor, return); - if (!m_editors.contains(editor)) - return; - - const int index = m_container->indexOf(editor->widget()); - QTC_ASSERT((index != -1), return); - bool wasCurrent = (index == m_container->currentIndex()); - m_editors.removeAll(editor); - - m_container->removeWidget(editor->widget()); - m_widgetEditorMap.remove(editor->widget()); - editor->widget()->setParent(0); - disconnect(editor, SIGNAL(changed()), this, SLOT(checkEditorStatus())); - QWidget *toolBar = editor->toolBar(); - if (toolBar != 0) { - if (m_activeToolBar == toolBar) { - m_activeToolBar = m_defaultToolBar; - m_activeToolBar->setVisible(true); - } - m_toolBar->layout()->removeWidget(toolBar); - toolBar->setVisible(false); - toolBar->setParent(0); - } - if (wasCurrent) - setCurrentEditor(m_editors.count() ? m_editors.last() : 0); -} - -IEditor *EditorView::currentEditor() const -{ - if (m_container->count() > 0) - return m_widgetEditorMap.value(m_container->currentWidget()); - return 0; -} - -void EditorView::setCurrentEditor(IEditor *editor) -{ - if (!editor || m_container->count() <= 0 - || m_container->indexOf(editor->widget()) == -1) { - updateEditorStatus(0); - // ### TODO the combo box m_editorList should show an empty item - return; - } - - m_editors.removeAll(editor); - m_editors.append(editor); - - const int idx = m_container->indexOf(editor->widget()); - QTC_ASSERT(idx >= 0, return); - m_container->setCurrentIndex(idx); - m_editorList->setCurrentIndex(m_model->indexOf(editor).row()); - updateEditorStatus(editor); - updateToolBar(editor); - updateEditorHistory(editor); - - // FIXME: this keeps the editor hidden if switching from A to B and back - if (editor != m_editorForInfoWidget) { - m_infoWidget->hide(); - m_editorForInfoWidget = 0; - } -} - -void EditorView::checkEditorStatus() -{ - IEditor *editor = qobject_cast(sender()); - if (editor == currentEditor()) - updateEditorStatus(editor); -} - -void EditorView::updateEditorStatus(IEditor *editor) -{ - static const QIcon lockedIcon(QLatin1String(":/core/images/locked.png")); - static const QIcon unlockedIcon(QLatin1String(":/core/images/unlocked.png")); - - m_lockButton->setVisible(editor != 0); - - if (!editor) { - m_editorList->setToolTip(QString()); - return; - } - - if (editor->file()->isReadOnly()) { - m_lockButton->setIcon(lockedIcon); - m_lockButton->setEnabled(!editor->file()->fileName().isEmpty()); - m_lockButton->setToolTip(tr("Make writable")); - } else { - m_lockButton->setIcon(unlockedIcon); - m_lockButton->setEnabled(false); - m_lockButton->setToolTip(tr("File is writable")); - } - if (currentEditor() == editor) - m_editorList->setToolTip( - editor->file()->fileName().isEmpty() - ? editor->displayName() - : QDir::toNativeSeparators(editor->file()->fileName()) - ); - -} - -void EditorView::updateToolBar(IEditor *editor) -{ - QWidget *toolBar = editor->toolBar(); - if (!toolBar) - toolBar = m_defaultToolBar; - if (m_activeToolBar == toolBar) - return; - toolBar->setVisible(true); - m_activeToolBar->setVisible(false); - m_activeToolBar = toolBar; -} - -int EditorView::editorCount() const -{ - return m_container->count(); -} - -QList EditorView::editors() const -{ - return m_widgetEditorMap.values(); -} - - -void EditorView::makeEditorWritable() -{ - CoreImpl::instance()->editorManager()->makeEditorWritable(currentEditor()); -} - -void EditorView::listSelectionActivated(int index) -{ - EditorManager *em = CoreImpl::instance()->editorManager(); - QAbstractItemModel *model = m_editorList->model(); - if (IEditor *editor = model->data(model->index(index, 0), Qt::UserRole).value()) { - em->activateEditor(this, editor); - } else { - em->activateEditor(model->index(index, 0), this); - } -} - -void EditorView::listContextMenu(QPoint pos) -{ - QModelIndex index = m_model->index(m_editorList->currentIndex(), 0); - QString fileName = m_model->data(index, Qt::UserRole + 1).toString(); - if (fileName.isEmpty()) - return; - QMenu menu; - menu.addAction(tr("Copy full path to clipboard")); - if (menu.exec(m_editorList->mapToGlobal(pos))) { - QApplication::clipboard()->setText(QDir::toNativeSeparators(fileName)); - } -} - -void EditorView::updateEditorHistory(IEditor *editor) -{ - if (!editor) - return; - IFile *file = editor->file(); - - if (!file) - return; - - QString fileName = file->fileName(); - QByteArray state = editor->saveState(); - - EditLocation location; - location.file = file; - location.fileName = file->fileName(); - location.kind = editor->kind(); - location.state = QVariant(state); - - for(int i = 0; i < m_editorHistory.size(); ++i) { - if (m_editorHistory.at(i).file == 0 - || m_editorHistory.at(i).file == file - ){ - m_editorHistory.removeAt(i--); - continue; - } - } - m_editorHistory.prepend(location); -} - -void EditorView::addCurrentPositionToNavigationHistory(IEditor *editor, const QByteArray &saveState) -{ - if (editor && editor != currentEditor()) { - return; // we only save editor sate for the current editor, when the user interacts - } - - if (!editor) - editor = currentEditor(); - if (!editor) - return; - IFile *file = editor->file(); - - if (!file) - return; - - QString fileName = file->fileName(); - QByteArray state; - if (saveState.isNull()) { - state = editor->saveState(); - } else { - state = saveState; - } - - EditLocation location; - location.file = file; - location.fileName = file->fileName(); - location.kind = editor->kind(); - location.state = QVariant(state); - m_currentNavigationHistoryPosition = qMin(m_currentNavigationHistoryPosition, m_navigationHistory.size()); // paranoia - m_navigationHistory.insert(m_currentNavigationHistoryPosition, location); - ++m_currentNavigationHistoryPosition; - - while (m_navigationHistory.size() >= 30) { - if (m_currentNavigationHistoryPosition > 15) { - m_navigationHistory.takeFirst(); - --m_currentNavigationHistoryPosition; - } else { - m_navigationHistory.takeLast(); - } - } - updateActions(); -} - -void EditorView::updateActions() -{ - m_goBackAction->setEnabled(canGoBack()); - m_goForwardAction->setEnabled(canGoForward()); -} - -void EditorView::updateActionShortcuts() -{ - ActionManager *am = ICore::instance()->actionManager(); - m_closeButton->setToolTip(am->command(Constants::CLOSE)->stringWithAppendedShortcut(EditorManager::tr("Close"))); - m_goBackAction->setToolTip(am->command(Constants::GO_BACK)->action()->toolTip()); - m_goForwardAction->setToolTip(am->command(Constants::GO_FORWARD)->action()->toolTip()); -} - -void EditorView::copyNavigationHistoryFrom(EditorView* other) -{ - if (!other) - return; - m_currentNavigationHistoryPosition = other->m_currentNavigationHistoryPosition; - m_navigationHistory = other->m_navigationHistory; - m_editorHistory = other->m_editorHistory; - updateActions(); -} - -void EditorView::updateCurrentPositionInNavigationHistory() -{ - IEditor *editor = currentEditor(); - if (!editor || !editor->file()) - return; - - IFile *file = editor->file(); - EditLocation *location; - if (m_currentNavigationHistoryPosition < m_navigationHistory.size()) { - location = &m_navigationHistory[m_currentNavigationHistoryPosition]; - } else { - m_navigationHistory.append(EditLocation()); - location = &m_navigationHistory[m_navigationHistory.size()-1]; - } - location->file = file; - location->fileName = file->fileName(); - location->kind = editor->kind(); - location->state = QVariant(editor->saveState()); -} - -void EditorView::goBackInNavigationHistory() -{ - EditorManager *em = CoreImpl::instance()->editorManager(); - updateCurrentPositionInNavigationHistory(); - while (m_currentNavigationHistoryPosition > 0) { - --m_currentNavigationHistoryPosition; - EditLocation location = m_navigationHistory.at(m_currentNavigationHistoryPosition); - IEditor *editor; - if (location.file) { - editor = em->activateEditor(this, location.file, EditorManager::IgnoreNavigationHistory); - } else { - editor = em->openEditor(this, location.fileName, location.kind, EditorManager::IgnoreNavigationHistory); - if (!editor) { - m_navigationHistory.removeAt(m_currentNavigationHistoryPosition); - continue; - } - } - editor->restoreState(location.state.toByteArray()); - break; - } - updateActions(); -} - -void EditorView::goForwardInNavigationHistory() -{ - EditorManager *em = CoreImpl::instance()->editorManager(); - updateCurrentPositionInNavigationHistory(); - if (m_currentNavigationHistoryPosition >= m_navigationHistory.size()-1) - return; - ++m_currentNavigationHistoryPosition; - EditLocation location = m_navigationHistory.at(m_currentNavigationHistoryPosition); - IEditor *editor; - if (location.file) { - editor = em->activateEditor(this, location.file, EditorManager::IgnoreNavigationHistory); - } else { - editor = em->openEditor(this, location.fileName, location.kind, EditorManager::IgnoreNavigationHistory); - if (!editor) { - //TODO - qDebug() << Q_FUNC_INFO << "can't open file" << location.fileName; - return; - } - } - editor->restoreState(location.state.toByteArray()); - updateActions(); -} - - -SplitterOrView::SplitterOrView(OpenEditorsModel *model) -{ - Q_ASSERT(model); - m_isRoot = true; - m_layout = new QStackedLayout(this); - m_view = new EditorView(model); - m_splitter = 0; - m_layout->addWidget(m_view); -} - -SplitterOrView::SplitterOrView(Core::IEditor *editor) -{ - m_isRoot = false; - m_layout = new QStackedLayout(this); - m_view = new EditorView(); - if (editor) - m_view->addEditor(editor); - m_splitter = 0; - m_layout->addWidget(m_view); -} - -SplitterOrView::~SplitterOrView() -{ - delete m_layout; - m_layout = 0; - delete m_view; - m_view = 0; - delete m_splitter; - m_splitter = 0; -} - -void SplitterOrView::mousePressEvent(QMouseEvent *e) -{ - if (e->button() != Qt::LeftButton) - return; - setFocus(Qt::MouseFocusReason); - CoreImpl::instance()->editorManager()->setCurrentView(this); -} - -void SplitterOrView::paintEvent(QPaintEvent *) -{ - if (CoreImpl::instance()->editorManager()->currentSplitterOrView() != this) - return; - - if (!m_view || hasEditors()) - return; - - // Discreet indication where an editor would be if there is none - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing, true); - painter.setPen(Qt::NoPen); - QColor shadeBrush(Qt::black); - shadeBrush.setAlpha(10); - painter.setBrush(shadeBrush); - const int r = 3; - painter.drawRoundedRect(rect().adjusted(r, r, -r, -r), r * 2, r * 2); - -#if 0 - if (hasFocus()) { -#ifdef Q_WS_MAC - // With QMacStyle, we have to draw our own focus rect, since I didn't find - // a way to draw the nice mac focus rect _inside_ this widget - if (qobject_cast(style())) { - painter.setPen(Qt::DotLine); - painter.setBrush(Qt::NoBrush); - painter.setOpacity(0.75); - painter.drawRect(rect()); - } else { -#endif - QStyleOptionFocusRect option; - option.initFrom(this); - option.backgroundColor = palette().color(QPalette::Background); - - // Some styles require a certain state flag in order to draw the focus rect - option.state |= QStyle::State_KeyboardFocusChange; - - style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter); -#ifdef Q_WS_MAC - } -#endif - } -#endif -} - -SplitterOrView *SplitterOrView::findFirstView() -{ - if (m_splitter) { - for (int i = 0; i < m_splitter->count(); ++i) { - if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) - if (SplitterOrView *result = splitterOrView->findFirstView()) - return result; - } - return 0; - } - return this; -} - -SplitterOrView *SplitterOrView::findEmptyView() -{ - if (m_splitter) { - for (int i = 0; i < m_splitter->count(); ++i) { - if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) - if (SplitterOrView *result = splitterOrView->findEmptyView()) - return result; - } - return 0; - } - if (!hasEditors()) - return this; - return 0; -} - -SplitterOrView *SplitterOrView::findView(Core::IEditor *editor) -{ - if (!editor || hasEditor(editor)) - return this; - if (m_splitter) { - for (int i = 0; i < m_splitter->count(); ++i) { - if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) - if (SplitterOrView *result = splitterOrView->findView(editor)) - return result; - } - } - return 0; -} - -SplitterOrView *SplitterOrView::findView(EditorView *view) -{ - if (view == m_view) - return this; - if (m_splitter) { - for (int i = 0; i < m_splitter->count(); ++i) { - if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) - if (SplitterOrView *result = splitterOrView->findView(view)) - return result; - } - } - return 0; -} - -SplitterOrView *SplitterOrView::findSplitter(Core::IEditor *editor) -{ - if (m_splitter) { - for (int i = 0; i < m_splitter->count(); ++i) { - if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) { - if (splitterOrView->hasEditor(editor)) - return this; - if (SplitterOrView *result = splitterOrView->findSplitter(editor)) - return result; - } - } - } - return 0; -} - -SplitterOrView *SplitterOrView::findSplitter(SplitterOrView *child) -{ - if (m_splitter) { - for (int i = 0; i < m_splitter->count(); ++i) { - if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) { - if (splitterOrView == child) - return this; - if (SplitterOrView *result = splitterOrView->findSplitter(child)) - return result; - } - } - } - return 0; -} - -SplitterOrView *SplitterOrView::findNextView(SplitterOrView *view) -{ - bool found = false; - return findNextView_helper(view, &found); -} - -SplitterOrView *SplitterOrView::findNextView_helper(SplitterOrView *view, bool *found) -{ - if (*found && m_view) { - return this; - } - - if (this == view) { - *found = true; - return 0; - } - - if (m_splitter) { - for (int i = 0; i < m_splitter->count(); ++i) { - if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) { - if (SplitterOrView *result = splitterOrView->findNextView_helper(view, found)) - return result; - } - } - } - return 0; -} - -QSize SplitterOrView::minimumSizeHint() const -{ - if (m_splitter) - return m_splitter->minimumSizeHint(); - return QSize(64, 64); -} - -QSplitter *SplitterOrView::takeSplitter() -{ - QSplitter *oldSplitter = m_splitter; - if (m_splitter) - m_layout->removeWidget(m_splitter); - m_splitter = 0; - return oldSplitter; -} - -EditorView *SplitterOrView::takeView() -{ - EditorView *oldView = m_view; - if (m_view) - m_layout->removeWidget(m_view); - m_view = 0; - return oldView; -} - -void SplitterOrView::split(Qt::Orientation orientation) -{ - Q_ASSERT(m_view && m_splitter == 0); - m_splitter = new MiniSplitter(this); - m_splitter->setOrientation(orientation); - m_layout->addWidget(m_splitter); - EditorManager *em = CoreImpl::instance()->editorManager(); - Core::IEditor *e = m_view->currentEditor(); - - SplitterOrView *view = 0; - SplitterOrView *otherView = 0; - if (e) { - - m_view->removeEditor(e); - m_splitter->addWidget((view = new SplitterOrView(e))); - if (e->duplicateSupported()) { - Core::IEditor *duplicate = em->duplicateEditor(e); - m_splitter->addWidget((otherView = new SplitterOrView(duplicate))); - } else { - m_splitter->addWidget((otherView = new SplitterOrView())); - } - } else { - m_splitter->addWidget((otherView = new SplitterOrView())); - m_splitter->addWidget((view = new SplitterOrView())); - } - - m_layout->setCurrentWidget(m_splitter); - - view->view()->copyNavigationHistoryFrom(m_view); - view->view()->setCurrentEditor(view->view()->currentEditor()); - otherView->view()->copyNavigationHistoryFrom(m_view); - otherView->view()->setCurrentEditor(otherView->view()->currentEditor()); - - if (m_view && !m_isRoot) { - em->emptyView(m_view); - delete m_view; - m_view = 0; - } - - if (e) - em->activateEditor(view->view(), e); - else - em->setCurrentView(view); -} - -void SplitterOrView::unsplitAll() -{ - m_splitter->hide(); - m_layout->removeWidget(m_splitter); // workaround Qt bug - unsplitAll_helper(); - delete m_splitter; - m_splitter = 0; -} - -void SplitterOrView::unsplitAll_helper() -{ - if (!m_isRoot && m_view) - CoreImpl::instance()->editorManager()->emptyView(m_view); - if (m_splitter) { - for (int i = 0; i < m_splitter->count(); ++i) { - if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) { - splitterOrView->unsplitAll_helper(); - } - } - } -} - -void SplitterOrView::unsplit() -{ - if (!m_splitter) - return; - - Q_ASSERT(m_splitter->count() == 1); - EditorManager *em = CoreImpl::instance()->editorManager(); - SplitterOrView *childSplitterOrView = qobject_cast(m_splitter->widget(0)); - QSplitter *oldSplitter = m_splitter; - m_splitter = 0; - - if (childSplitterOrView->isSplitter()) { - Q_ASSERT(childSplitterOrView->view() == 0); - m_splitter = childSplitterOrView->takeSplitter(); - m_layout->addWidget(m_splitter); - m_layout->setCurrentWidget(m_splitter); - } else { - EditorView *childView = childSplitterOrView->view(); - Q_ASSERT(childView); - if (m_view) { - m_view->copyNavigationHistoryFrom(childView); - if (IEditor *e = childView->currentEditor()) { - childView->removeEditor(e); - m_view->addEditor(e); - m_view->setCurrentEditor(e); - } - em->emptyView(childView); - } else { - m_view = childSplitterOrView->takeView(); - m_layout->addWidget(m_view); - } - m_layout->setCurrentWidget(m_view); - } - delete oldSplitter; - em->setCurrentView(findFirstView()); -} - - -QByteArray SplitterOrView::saveState() const -{ - QByteArray bytes; - QDataStream stream(&bytes, QIODevice::WriteOnly); - - if (m_splitter) { - stream << QByteArray("splitter") - << (qint32)m_splitter->orientation() - << m_splitter->saveState() - << static_cast(m_splitter->widget(0))->saveState() - << static_cast(m_splitter->widget(1))->saveState(); - } else { - IEditor* e = editor(); - EditorManager *em = CoreImpl::instance()->editorManager(); - - if (e && e == em->currentEditor()) { - stream << QByteArray("currenteditor") - << e->file()->fileName() << e->kind() << e->saveState(); - } else if (e) { - stream << QByteArray("editor") - << e->file()->fileName() << e->kind() << e->saveState(); - } else { - stream << QByteArray("empty"); - } - } - return bytes; -} - -void SplitterOrView::restoreState(const QByteArray &state) -{ - QDataStream stream(state); - QByteArray mode; - stream >> mode; - if (mode == "splitter") { - qint32 orientation; - QByteArray splitter, first, second; - stream >> orientation >> splitter >> first >> second; - split((Qt::Orientation)orientation); - m_splitter->restoreState(splitter); - static_cast(m_splitter->widget(0))->restoreState(first); - static_cast(m_splitter->widget(1))->restoreState(second); - } else if (mode == "editor" || mode == "currenteditor") { - EditorManager *em = CoreImpl::instance()->editorManager(); - QString fileName; - QByteArray kind; - QByteArray editorState; - stream >> fileName >> kind >> editorState; - IEditor *e = em->openEditor(view(), fileName, kind, Core::EditorManager::IgnoreNavigationHistory - | Core::EditorManager::NoActivate); - - if (!e) { - QModelIndex idx = em->openedEditorsModel()->firstRestoredEditor(); - if (idx.isValid()) - em->activateEditor(idx, view(), Core::EditorManager::IgnoreNavigationHistory - | Core::EditorManager::NoActivate); - } - - if (e) { - e->restoreState(editorState); - if (mode == "currenteditor") - em->setCurrentEditor(e); - } - } -} +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "editorview.h" +#include "editormanager.h" +#include "coreimpl.h" +#include "minisplitter.h" +#include "openeditorsmodel.h" +#include +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_WS_MAC +#include +#endif + +Q_DECLARE_METATYPE(Core::IEditor *) + +using namespace Core; +using namespace Core::Internal; + + +// ================EditorView==================== + +EditorView::EditorView(OpenEditorsModel *model, QWidget *parent) : + QWidget(parent), + m_model(model), + m_toolBar(new QWidget), + m_container(new QStackedWidget(this)), + m_editorList(new QComboBox), + m_closeButton(new QToolButton), + m_lockButton(new QToolButton), + m_defaultToolBar(new QWidget(this)), + m_infoWidget(new QFrame(this)), + m_editorForInfoWidget(0), + m_statusHLine(new QFrame(this)), + m_statusWidget(new QFrame(this)), + m_currentNavigationHistoryPosition(0) +{ + + m_goBackAction = new QAction(QIcon(QLatin1String(":/help/images/previous.png")), tr("Go Back"), this); + connect(m_goBackAction, SIGNAL(triggered()), this, SLOT(goBackInNavigationHistory())); + m_goForwardAction = new QAction(QIcon(QLatin1String(":/help/images/next.png")), tr("Go Forward"), this); + connect(m_goForwardAction, SIGNAL(triggered()), this, SLOT(goForwardInNavigationHistory())); + + QVBoxLayout *tl = new QVBoxLayout(this); + tl->setSpacing(0); + tl->setMargin(0); + { + if (!m_model) { + m_model = CoreImpl::instance()->editorManager()->openedEditorsModel(); + } + + QToolButton *backButton = new QToolButton; + backButton->setDefaultAction(m_goBackAction); + + QToolButton *forwardButton= new QToolButton; + forwardButton->setDefaultAction(m_goForwardAction); + + m_editorList->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + m_editorList->setMinimumContentsLength(20); + m_editorList->setModel(m_model); + m_editorList->setMaxVisibleItems(40); + m_editorList->setContextMenuPolicy(Qt::CustomContextMenu); + + m_defaultToolBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + m_activeToolBar = m_defaultToolBar; + + QHBoxLayout *toolBarLayout = new QHBoxLayout; + toolBarLayout->setMargin(0); + toolBarLayout->setSpacing(0); + toolBarLayout->addWidget(m_defaultToolBar); + m_toolBar->setLayout(toolBarLayout); + m_toolBar->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); + + m_lockButton->setAutoRaise(true); + + m_closeButton->setAutoRaise(true); + m_closeButton->setIcon(QIcon(":/core/images/closebutton.png")); + + + QHBoxLayout *toplayout = new QHBoxLayout; + toplayout->setSpacing(0); + toplayout->setMargin(0); + toplayout->addWidget(backButton); + toplayout->addWidget(forwardButton); + toplayout->addWidget(m_editorList); + toplayout->addWidget(m_toolBar, 1); // Custom toolbar stretches + toplayout->addWidget(m_lockButton); + toplayout->addWidget(m_closeButton); + + Utils::StyledBar *top = new Utils::StyledBar; + top->setLayout(toplayout); + tl->addWidget(top); + + connect(m_editorList, SIGNAL(activated(int)), this, SLOT(listSelectionActivated(int))); + connect(m_editorList, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(listContextMenu(QPoint))); + connect(m_lockButton, SIGNAL(clicked()), this, SLOT(makeEditorWritable())); + connect(m_closeButton, SIGNAL(clicked()), this, SLOT(closeView()), Qt::QueuedConnection); + } + { + m_infoWidget->setFrameStyle(QFrame::Panel | QFrame::Raised); + m_infoWidget->setLineWidth(1); + m_infoWidget->setForegroundRole(QPalette::ToolTipText); + m_infoWidget->setBackgroundRole(QPalette::ToolTipBase); + m_infoWidget->setAutoFillBackground(true); + + QHBoxLayout *hbox = new QHBoxLayout(m_infoWidget); + hbox->setMargin(2); + m_infoWidgetLabel = new QLabel("Placeholder"); + m_infoWidgetLabel->setForegroundRole(QPalette::ToolTipText); + hbox->addWidget(m_infoWidgetLabel); + hbox->addStretch(1); + + m_infoWidgetButton = new QToolButton; + m_infoWidgetButton->setText(tr("Placeholder")); + hbox->addWidget(m_infoWidgetButton); + + QToolButton *closeButton = new QToolButton; + closeButton->setAutoRaise(true); + closeButton->setIcon(QIcon(":/core/images/clear.png")); + closeButton->setToolTip(tr("Close")); + connect(closeButton, SIGNAL(clicked()), m_infoWidget, SLOT(hide())); + + hbox->addWidget(closeButton); + + m_infoWidget->setVisible(false); + tl->addWidget(m_infoWidget); + } + + tl->addWidget(m_container); + + tl->addWidget(new FindToolBarPlaceHolder(this)); + + { + m_statusHLine->setFrameStyle(QFrame::HLine); + + m_statusWidget->setFrameStyle(QFrame::Panel | QFrame::Raised); + m_statusWidget->setLineWidth(1); + //m_statusWidget->setForegroundRole(QPalette::ToolTipText); + //m_statusWidget->setBackgroundRole(QPalette::ToolTipBase); + m_statusWidget->setAutoFillBackground(true); + + + QHBoxLayout *hbox = new QHBoxLayout(m_statusWidget); + hbox->setMargin(2); + m_statusWidgetLabel = new QLabel("Placeholder"); + m_statusWidgetLabel->setForegroundRole(QPalette::ToolTipText); + hbox->addWidget(m_statusWidgetLabel); + hbox->addStretch(1); + + m_statusWidgetButton = new QToolButton; + m_statusWidgetButton->setText(tr("Placeholder")); + hbox->addWidget(m_statusWidgetButton); + + m_statusHLine->setVisible(false); + m_statusWidget->setVisible(false); + tl->addWidget(m_statusHLine); + tl->addWidget(m_statusWidget); + } + + + ActionManager *am = ICore::instance()->actionManager(); + connect(am->command(Constants::CLOSE), SIGNAL(keySequenceChanged()), + this, SLOT(updateActionShortcuts())); + connect(am->command(Constants::GO_BACK), SIGNAL(keySequenceChanged()), + this, SLOT(updateActionShortcuts())); + connect(am->command(Constants::GO_FORWARD), SIGNAL(keySequenceChanged()), + this, SLOT(updateActionShortcuts())); + + updateActionShortcuts(); + updateActions(); +} + +EditorView::~EditorView() +{ +} + +void EditorView::showEditorInfoBar(const QString &kind, + const QString &infoText, + const QString &buttonText, + QObject *object, const char *member) +{ + m_infoWidgetKind = kind; + m_infoWidgetLabel->setText(infoText); + m_infoWidgetButton->setText(buttonText); + m_infoWidgetButton->disconnect(); + if (object && member) + connect(m_infoWidgetButton, SIGNAL(clicked()), object, member); + m_infoWidget->setVisible(true); + m_editorForInfoWidget = currentEditor(); +} + +void EditorView::hideEditorInfoBar(const QString &kind) +{ + if (kind == m_infoWidgetKind) + m_infoWidget->setVisible(false); +} + +void EditorView::showEditorStatusBar(const QString &kind, + const QString &infoText, + const QString &buttonText, + QObject *object, const char *member) +{ + m_statusWidgetKind = kind; + m_statusWidgetLabel->setText(infoText); + m_statusWidgetButton->setText(buttonText); + m_statusWidgetButton->disconnect(); + if (object && member) + connect(m_statusWidgetButton, SIGNAL(clicked()), object, member); + m_statusWidget->setVisible(true); + m_statusHLine->setVisible(true); + //m_editorForInfoWidget = currentEditor(); +} + +void EditorView::hideEditorStatusBar(const QString &kind) +{ + if (kind == m_statusWidgetKind) { + m_statusWidget->setVisible(false); + m_statusHLine->setVisible(false); + } +} + +void EditorView::addEditor(IEditor *editor) +{ + if (m_editors.contains(editor)) + return; + + m_editors.append(editor); + + m_container->addWidget(editor->widget()); + m_widgetEditorMap.insert(editor->widget(), editor); + + QWidget *toolBar = editor->toolBar(); + if (toolBar) { + toolBar->setVisible(false); // will be made visible in setCurrentEditor + m_toolBar->layout()->addWidget(toolBar); + } + connect(editor, SIGNAL(changed()), this, SLOT(checkEditorStatus())); + + if (editor == currentEditor()) + setCurrentEditor(editor); +} + +bool EditorView::hasEditor(IEditor *editor) const +{ + return m_editors.contains(editor); +} + +void EditorView::closeView() +{ + EditorManager *em = CoreImpl::instance()->editorManager(); + if (IEditor *editor = currentEditor()) { + em->closeDuplicate(editor); + } +} + +void EditorView::removeEditor(IEditor *editor) +{ + QTC_ASSERT(editor, return); + if (!m_editors.contains(editor)) + return; + + const int index = m_container->indexOf(editor->widget()); + QTC_ASSERT((index != -1), return); + bool wasCurrent = (index == m_container->currentIndex()); + m_editors.removeAll(editor); + + m_container->removeWidget(editor->widget()); + m_widgetEditorMap.remove(editor->widget()); + editor->widget()->setParent(0); + disconnect(editor, SIGNAL(changed()), this, SLOT(checkEditorStatus())); + QWidget *toolBar = editor->toolBar(); + if (toolBar != 0) { + if (m_activeToolBar == toolBar) { + m_activeToolBar = m_defaultToolBar; + m_activeToolBar->setVisible(true); + } + m_toolBar->layout()->removeWidget(toolBar); + toolBar->setVisible(false); + toolBar->setParent(0); + } + if (wasCurrent) + setCurrentEditor(m_editors.count() ? m_editors.last() : 0); +} + +IEditor *EditorView::currentEditor() const +{ + if (m_container->count() > 0) + return m_widgetEditorMap.value(m_container->currentWidget()); + return 0; +} + +void EditorView::setCurrentEditor(IEditor *editor) +{ + if (!editor || m_container->count() <= 0 + || m_container->indexOf(editor->widget()) == -1) { + updateEditorStatus(0); + // ### TODO the combo box m_editorList should show an empty item + return; + } + + m_editors.removeAll(editor); + m_editors.append(editor); + + const int idx = m_container->indexOf(editor->widget()); + QTC_ASSERT(idx >= 0, return); + m_container->setCurrentIndex(idx); + m_editorList->setCurrentIndex(m_model->indexOf(editor).row()); + updateEditorStatus(editor); + updateToolBar(editor); + updateEditorHistory(editor); + + // FIXME: this keeps the editor hidden if switching from A to B and back + if (editor != m_editorForInfoWidget) { + m_infoWidget->hide(); + m_editorForInfoWidget = 0; + } +} + +void EditorView::checkEditorStatus() +{ + IEditor *editor = qobject_cast(sender()); + if (editor == currentEditor()) + updateEditorStatus(editor); +} + +void EditorView::updateEditorStatus(IEditor *editor) +{ + static const QIcon lockedIcon(QLatin1String(":/core/images/locked.png")); + static const QIcon unlockedIcon(QLatin1String(":/core/images/unlocked.png")); + + m_lockButton->setVisible(editor != 0); + + if (!editor) { + m_editorList->setToolTip(QString()); + return; + } + + if (editor->file()->isReadOnly()) { + m_lockButton->setIcon(lockedIcon); + m_lockButton->setEnabled(!editor->file()->fileName().isEmpty()); + m_lockButton->setToolTip(tr("Make writable")); + } else { + m_lockButton->setIcon(unlockedIcon); + m_lockButton->setEnabled(false); + m_lockButton->setToolTip(tr("File is writable")); + } + if (currentEditor() == editor) + m_editorList->setToolTip( + editor->file()->fileName().isEmpty() + ? editor->displayName() + : QDir::toNativeSeparators(editor->file()->fileName()) + ); + +} + +void EditorView::updateToolBar(IEditor *editor) +{ + QWidget *toolBar = editor->toolBar(); + if (!toolBar) + toolBar = m_defaultToolBar; + if (m_activeToolBar == toolBar) + return; + toolBar->setVisible(true); + m_activeToolBar->setVisible(false); + m_activeToolBar = toolBar; +} + +int EditorView::editorCount() const +{ + return m_container->count(); +} + +QList EditorView::editors() const +{ + return m_widgetEditorMap.values(); +} + + +void EditorView::makeEditorWritable() +{ + CoreImpl::instance()->editorManager()->makeEditorWritable(currentEditor()); +} + +void EditorView::listSelectionActivated(int index) +{ + EditorManager *em = CoreImpl::instance()->editorManager(); + QAbstractItemModel *model = m_editorList->model(); + if (IEditor *editor = model->data(model->index(index, 0), Qt::UserRole).value()) { + em->activateEditor(this, editor); + } else { + em->activateEditor(model->index(index, 0), this); + } +} + +void EditorView::listContextMenu(QPoint pos) +{ + QModelIndex index = m_model->index(m_editorList->currentIndex(), 0); + QString fileName = m_model->data(index, Qt::UserRole + 1).toString(); + if (fileName.isEmpty()) + return; + QMenu menu; + menu.addAction(tr("Copy full path to clipboard")); + if (menu.exec(m_editorList->mapToGlobal(pos))) { + QApplication::clipboard()->setText(QDir::toNativeSeparators(fileName)); + } +} + +void EditorView::updateEditorHistory(IEditor *editor) +{ + if (!editor) + return; + IFile *file = editor->file(); + + if (!file) + return; + + QString fileName = file->fileName(); + QByteArray state = editor->saveState(); + + EditLocation location; + location.file = file; + location.fileName = file->fileName(); + location.kind = editor->kind(); + location.state = QVariant(state); + + for(int i = 0; i < m_editorHistory.size(); ++i) { + if (m_editorHistory.at(i).file == 0 + || m_editorHistory.at(i).file == file + ){ + m_editorHistory.removeAt(i--); + continue; + } + } + m_editorHistory.prepend(location); +} + +void EditorView::addCurrentPositionToNavigationHistory(IEditor *editor, const QByteArray &saveState) +{ + if (editor && editor != currentEditor()) { + return; // we only save editor sate for the current editor, when the user interacts + } + + if (!editor) + editor = currentEditor(); + if (!editor) + return; + IFile *file = editor->file(); + + if (!file) + return; + + QString fileName = file->fileName(); + QByteArray state; + if (saveState.isNull()) { + state = editor->saveState(); + } else { + state = saveState; + } + + EditLocation location; + location.file = file; + location.fileName = file->fileName(); + location.kind = editor->kind(); + location.state = QVariant(state); + m_currentNavigationHistoryPosition = qMin(m_currentNavigationHistoryPosition, m_navigationHistory.size()); // paranoia + m_navigationHistory.insert(m_currentNavigationHistoryPosition, location); + ++m_currentNavigationHistoryPosition; + + while (m_navigationHistory.size() >= 30) { + if (m_currentNavigationHistoryPosition > 15) { + m_navigationHistory.takeFirst(); + --m_currentNavigationHistoryPosition; + } else { + m_navigationHistory.takeLast(); + } + } + updateActions(); +} + +void EditorView::updateActions() +{ + m_goBackAction->setEnabled(canGoBack()); + m_goForwardAction->setEnabled(canGoForward()); +} + +void EditorView::updateActionShortcuts() +{ + ActionManager *am = ICore::instance()->actionManager(); + m_closeButton->setToolTip(am->command(Constants::CLOSE)->stringWithAppendedShortcut(EditorManager::tr("Close"))); + m_goBackAction->setToolTip(am->command(Constants::GO_BACK)->action()->toolTip()); + m_goForwardAction->setToolTip(am->command(Constants::GO_FORWARD)->action()->toolTip()); +} + +void EditorView::copyNavigationHistoryFrom(EditorView* other) +{ + if (!other) + return; + m_currentNavigationHistoryPosition = other->m_currentNavigationHistoryPosition; + m_navigationHistory = other->m_navigationHistory; + m_editorHistory = other->m_editorHistory; + updateActions(); +} + +void EditorView::updateCurrentPositionInNavigationHistory() +{ + IEditor *editor = currentEditor(); + if (!editor || !editor->file()) + return; + + IFile *file = editor->file(); + EditLocation *location; + if (m_currentNavigationHistoryPosition < m_navigationHistory.size()) { + location = &m_navigationHistory[m_currentNavigationHistoryPosition]; + } else { + m_navigationHistory.append(EditLocation()); + location = &m_navigationHistory[m_navigationHistory.size()-1]; + } + location->file = file; + location->fileName = file->fileName(); + location->kind = editor->kind(); + location->state = QVariant(editor->saveState()); +} + +void EditorView::goBackInNavigationHistory() +{ + EditorManager *em = CoreImpl::instance()->editorManager(); + updateCurrentPositionInNavigationHistory(); + while (m_currentNavigationHistoryPosition > 0) { + --m_currentNavigationHistoryPosition; + EditLocation location = m_navigationHistory.at(m_currentNavigationHistoryPosition); + IEditor *editor; + if (location.file) { + editor = em->activateEditor(this, location.file, EditorManager::IgnoreNavigationHistory); + } else { + editor = em->openEditor(this, location.fileName, location.kind, EditorManager::IgnoreNavigationHistory); + if (!editor) { + m_navigationHistory.removeAt(m_currentNavigationHistoryPosition); + continue; + } + } + editor->restoreState(location.state.toByteArray()); + break; + } + updateActions(); +} + +void EditorView::goForwardInNavigationHistory() +{ + EditorManager *em = CoreImpl::instance()->editorManager(); + updateCurrentPositionInNavigationHistory(); + if (m_currentNavigationHistoryPosition >= m_navigationHistory.size()-1) + return; + ++m_currentNavigationHistoryPosition; + EditLocation location = m_navigationHistory.at(m_currentNavigationHistoryPosition); + IEditor *editor; + if (location.file) { + editor = em->activateEditor(this, location.file, EditorManager::IgnoreNavigationHistory); + } else { + editor = em->openEditor(this, location.fileName, location.kind, EditorManager::IgnoreNavigationHistory); + if (!editor) { + //TODO + qDebug() << Q_FUNC_INFO << "can't open file" << location.fileName; + return; + } + } + editor->restoreState(location.state.toByteArray()); + updateActions(); +} + + +SplitterOrView::SplitterOrView(OpenEditorsModel *model) +{ + Q_ASSERT(model); + m_isRoot = true; + m_layout = new QStackedLayout(this); + m_view = new EditorView(model); + m_splitter = 0; + m_layout->addWidget(m_view); +} + +SplitterOrView::SplitterOrView(Core::IEditor *editor) +{ + m_isRoot = false; + m_layout = new QStackedLayout(this); + m_view = new EditorView(); + if (editor) + m_view->addEditor(editor); + m_splitter = 0; + m_layout->addWidget(m_view); +} + +SplitterOrView::~SplitterOrView() +{ + delete m_layout; + m_layout = 0; + delete m_view; + m_view = 0; + delete m_splitter; + m_splitter = 0; +} + +void SplitterOrView::mousePressEvent(QMouseEvent *e) +{ + if (e->button() != Qt::LeftButton) + return; + setFocus(Qt::MouseFocusReason); + CoreImpl::instance()->editorManager()->setCurrentView(this); +} + +void SplitterOrView::paintEvent(QPaintEvent *) +{ + if (CoreImpl::instance()->editorManager()->currentSplitterOrView() != this) + return; + + if (!m_view || hasEditors()) + return; + + // Discreet indication where an editor would be if there is none + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing, true); + painter.setPen(Qt::NoPen); + QColor shadeBrush(Qt::black); + shadeBrush.setAlpha(10); + painter.setBrush(shadeBrush); + const int r = 3; + painter.drawRoundedRect(rect().adjusted(r, r, -r, -r), r * 2, r * 2); + +#if 0 + if (hasFocus()) { +#ifdef Q_WS_MAC + // With QMacStyle, we have to draw our own focus rect, since I didn't find + // a way to draw the nice mac focus rect _insGCS_ this widget + if (qobject_cast(style())) { + painter.setPen(Qt::DotLine); + painter.setBrush(Qt::NoBrush); + painter.setOpacity(0.75); + painter.drawRect(rect()); + } else { +#endif + QStyleOptionFocusRect option; + option.initFrom(this); + option.backgroundColor = palette().color(QPalette::Background); + + // Some styles require a certain state flag in order to draw the focus rect + option.state |= QStyle::State_KeyboardFocusChange; + + style()->drawPrimitive(QStyle::PE_FrameFocusRect, &option, &painter); +#ifdef Q_WS_MAC + } +#endif + } +#endif +} + +SplitterOrView *SplitterOrView::findFirstView() +{ + if (m_splitter) { + for (int i = 0; i < m_splitter->count(); ++i) { + if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) + if (SplitterOrView *result = splitterOrView->findFirstView()) + return result; + } + return 0; + } + return this; +} + +SplitterOrView *SplitterOrView::findEmptyView() +{ + if (m_splitter) { + for (int i = 0; i < m_splitter->count(); ++i) { + if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) + if (SplitterOrView *result = splitterOrView->findEmptyView()) + return result; + } + return 0; + } + if (!hasEditors()) + return this; + return 0; +} + +SplitterOrView *SplitterOrView::findView(Core::IEditor *editor) +{ + if (!editor || hasEditor(editor)) + return this; + if (m_splitter) { + for (int i = 0; i < m_splitter->count(); ++i) { + if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) + if (SplitterOrView *result = splitterOrView->findView(editor)) + return result; + } + } + return 0; +} + +SplitterOrView *SplitterOrView::findView(EditorView *view) +{ + if (view == m_view) + return this; + if (m_splitter) { + for (int i = 0; i < m_splitter->count(); ++i) { + if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) + if (SplitterOrView *result = splitterOrView->findView(view)) + return result; + } + } + return 0; +} + +SplitterOrView *SplitterOrView::findSplitter(Core::IEditor *editor) +{ + if (m_splitter) { + for (int i = 0; i < m_splitter->count(); ++i) { + if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) { + if (splitterOrView->hasEditor(editor)) + return this; + if (SplitterOrView *result = splitterOrView->findSplitter(editor)) + return result; + } + } + } + return 0; +} + +SplitterOrView *SplitterOrView::findSplitter(SplitterOrView *child) +{ + if (m_splitter) { + for (int i = 0; i < m_splitter->count(); ++i) { + if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) { + if (splitterOrView == child) + return this; + if (SplitterOrView *result = splitterOrView->findSplitter(child)) + return result; + } + } + } + return 0; +} + +SplitterOrView *SplitterOrView::findNextView(SplitterOrView *view) +{ + bool found = false; + return findNextView_helper(view, &found); +} + +SplitterOrView *SplitterOrView::findNextView_helper(SplitterOrView *view, bool *found) +{ + if (*found && m_view) { + return this; + } + + if (this == view) { + *found = true; + return 0; + } + + if (m_splitter) { + for (int i = 0; i < m_splitter->count(); ++i) { + if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) { + if (SplitterOrView *result = splitterOrView->findNextView_helper(view, found)) + return result; + } + } + } + return 0; +} + +QSize SplitterOrView::minimumSizeHint() const +{ + if (m_splitter) + return m_splitter->minimumSizeHint(); + return QSize(64, 64); +} + +QSplitter *SplitterOrView::takeSplitter() +{ + QSplitter *oldSplitter = m_splitter; + if (m_splitter) + m_layout->removeWidget(m_splitter); + m_splitter = 0; + return oldSplitter; +} + +EditorView *SplitterOrView::takeView() +{ + EditorView *oldView = m_view; + if (m_view) + m_layout->removeWidget(m_view); + m_view = 0; + return oldView; +} + +void SplitterOrView::split(Qt::Orientation orientation) +{ + Q_ASSERT(m_view && m_splitter == 0); + m_splitter = new MiniSplitter(this); + m_splitter->setOrientation(orientation); + m_layout->addWidget(m_splitter); + EditorManager *em = CoreImpl::instance()->editorManager(); + Core::IEditor *e = m_view->currentEditor(); + + SplitterOrView *view = 0; + SplitterOrView *otherView = 0; + if (e) { + + m_view->removeEditor(e); + m_splitter->addWidget((view = new SplitterOrView(e))); + if (e->duplicateSupported()) { + Core::IEditor *duplicate = em->duplicateEditor(e); + m_splitter->addWidget((otherView = new SplitterOrView(duplicate))); + } else { + m_splitter->addWidget((otherView = new SplitterOrView())); + } + } else { + m_splitter->addWidget((otherView = new SplitterOrView())); + m_splitter->addWidget((view = new SplitterOrView())); + } + + m_layout->setCurrentWidget(m_splitter); + + view->view()->copyNavigationHistoryFrom(m_view); + view->view()->setCurrentEditor(view->view()->currentEditor()); + otherView->view()->copyNavigationHistoryFrom(m_view); + otherView->view()->setCurrentEditor(otherView->view()->currentEditor()); + + if (m_view && !m_isRoot) { + em->emptyView(m_view); + delete m_view; + m_view = 0; + } + + if (e) + em->activateEditor(view->view(), e); + else + em->setCurrentView(view); +} + +void SplitterOrView::unsplitAll() +{ + m_splitter->hide(); + m_layout->removeWidget(m_splitter); // workaround Qt bug + unsplitAll_helper(); + delete m_splitter; + m_splitter = 0; +} + +void SplitterOrView::unsplitAll_helper() +{ + if (!m_isRoot && m_view) + CoreImpl::instance()->editorManager()->emptyView(m_view); + if (m_splitter) { + for (int i = 0; i < m_splitter->count(); ++i) { + if (SplitterOrView *splitterOrView = qobject_cast(m_splitter->widget(i))) { + splitterOrView->unsplitAll_helper(); + } + } + } +} + +void SplitterOrView::unsplit() +{ + if (!m_splitter) + return; + + Q_ASSERT(m_splitter->count() == 1); + EditorManager *em = CoreImpl::instance()->editorManager(); + SplitterOrView *childSplitterOrView = qobject_cast(m_splitter->widget(0)); + QSplitter *oldSplitter = m_splitter; + m_splitter = 0; + + if (childSplitterOrView->isSplitter()) { + Q_ASSERT(childSplitterOrView->view() == 0); + m_splitter = childSplitterOrView->takeSplitter(); + m_layout->addWidget(m_splitter); + m_layout->setCurrentWidget(m_splitter); + } else { + EditorView *childView = childSplitterOrView->view(); + Q_ASSERT(childView); + if (m_view) { + m_view->copyNavigationHistoryFrom(childView); + if (IEditor *e = childView->currentEditor()) { + childView->removeEditor(e); + m_view->addEditor(e); + m_view->setCurrentEditor(e); + } + em->emptyView(childView); + } else { + m_view = childSplitterOrView->takeView(); + m_layout->addWidget(m_view); + } + m_layout->setCurrentWidget(m_view); + } + delete oldSplitter; + em->setCurrentView(findFirstView()); +} + + +QByteArray SplitterOrView::saveState() const +{ + QByteArray bytes; + QDataStream stream(&bytes, QIODevice::WriteOnly); + + if (m_splitter) { + stream << QByteArray("splitter") + << (qint32)m_splitter->orientation() + << m_splitter->saveState() + << static_cast(m_splitter->widget(0))->saveState() + << static_cast(m_splitter->widget(1))->saveState(); + } else { + IEditor* e = editor(); + EditorManager *em = CoreImpl::instance()->editorManager(); + + if (e && e == em->currentEditor()) { + stream << QByteArray("currenteditor") + << e->file()->fileName() << e->kind() << e->saveState(); + } else if (e) { + stream << QByteArray("editor") + << e->file()->fileName() << e->kind() << e->saveState(); + } else { + stream << QByteArray("empty"); + } + } + return bytes; +} + +void SplitterOrView::restoreState(const QByteArray &state) +{ + QDataStream stream(state); + QByteArray mode; + stream >> mode; + if (mode == "splitter") { + qint32 orientation; + QByteArray splitter, first, second; + stream >> orientation >> splitter >> first >> second; + split((Qt::Orientation)orientation); + m_splitter->restoreState(splitter); + static_cast(m_splitter->widget(0))->restoreState(first); + static_cast(m_splitter->widget(1))->restoreState(second); + } else if (mode == "editor" || mode == "currenteditor") { + EditorManager *em = CoreImpl::instance()->editorManager(); + QString fileName; + QByteArray kind; + QByteArray editorState; + stream >> fileName >> kind >> editorState; + IEditor *e = em->openEditor(view(), fileName, kind, Core::EditorManager::IgnoreNavigationHistory + | Core::EditorManager::NoActivate); + + if (!e) { + QModelIndex idx = em->openedEditorsModel()->firstRestoredEditor(); + if (idx.isValid()) + em->activateEditor(idx, view(), Core::EditorManager::IgnoreNavigationHistory + | Core::EditorManager::NoActivate); + } + + if (e) { + e->restoreState(editorState); + if (mode == "currenteditor") + em->setCurrentEditor(e); + } + } +} diff --git a/ground/src/plugins/coreplugin/mainwindow.cpp b/ground/src/plugins/coreplugin/mainwindow.cpp index 1404a4236..028fd513b 100644 --- a/ground/src/plugins/coreplugin/mainwindow.cpp +++ b/ground/src/plugins/coreplugin/mainwindow.cpp @@ -159,7 +159,7 @@ MainWindow::MainWindow() : qApp->setWindowIcon(QIcon(":/core/images/qtcreator_logo_128.png")); #endif QCoreApplication::setApplicationName(QLatin1String("OpenPilotGCS")); - QCoreApplication::setApplicationVersion(QLatin1String(Core::Constants::IDE_VERSION_LONG)); + QCoreApplication::setApplicationVersion(QLatin1String(Core::Constants::GCS_VERSION_LONG)); QCoreApplication::setOrganizationName(QLatin1String("OpenPilot")); QSettings::setDefaultFormat(QSettings::IniFormat); QString baseName = qApp->style()->objectName(); diff --git a/ground/src/plugins/coreplugin/versiondialog.cpp b/ground/src/plugins/coreplugin/versiondialog.cpp index d951d171b..419b7a655 100644 --- a/ground/src/plugins/coreplugin/versiondialog.cpp +++ b/ground/src/plugins/coreplugin/versiondialog.cpp @@ -1,105 +1,105 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://qt.nokia.com/contact. -** -**************************************************************************/ - -#include "versiondialog.h" - -#include "coreconstants.h" -#include "icore.h" - -#include - -#include -#include -#include - -#include -#include -#include -#include -#include - -using namespace Core; -using namespace Core::Internal; -using namespace Core::Constants; - -VersionDialog::VersionDialog(QWidget *parent) - : QDialog(parent) -{ - // We need to set the window icon explicitly here since for some reason the - // application icon isn't used when the size of the dialog is fixed (at least not on X11/GNOME) - setWindowIcon(QIcon(":/core/images/qtcreator_logo_128.png")); - - setWindowTitle(tr("About Qt Creator")); - setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); - QGridLayout *layout = new QGridLayout(this); - layout->setSizeConstraint(QLayout::SetFixedSize); - - QString version = QLatin1String(IDE_VERSION_LONG); - version += QDate(2007, 25, 10).toString(Qt::SystemLocaleDate); - - QString ideRev; -#ifdef IDE_REVISION - //: This gets conditionally inserted as argument %8 into the description string. - ideRev = tr("From revision %1
").arg(QString::fromLatin1(IDE_REVISION_STR).left(10)); -#endif - - const QString description = tr( - "

Qt Creator %1

" - "Based on Qt %2 (%3 bit)
" - "
" - "Built on %4 at %5
" - "
" - "%8" - "
" - "Copyright 2008-%6 %7. All rights reserved.
" - "
" - "The program is provided AS IS with NO WARRANTY OF ANY KIND, " - "INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A " - "PARTICULAR PURPOSE.
") - .arg(version, QLatin1String(QT_VERSION_STR), QString::number(QSysInfo::WordSize), - QLatin1String(__DATE__), QLatin1String(__TIME__), QLatin1String(IDE_YEAR), - (QLatin1String(IDE_AUTHOR)), ideRev); - - QLabel *copyRightLabel = new QLabel(description); - copyRightLabel->setWordWrap(true); - copyRightLabel->setOpenExternalLinks(true); - copyRightLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); - - QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); - QPushButton *closeButton = buttonBox->button(QDialogButtonBox::Close); - QTC_ASSERT(closeButton, /**/); - buttonBox->addButton(closeButton, QDialogButtonBox::ButtonRole(QDialogButtonBox::RejectRole | QDialogButtonBox::AcceptRole)); - connect(buttonBox , SIGNAL(rejected()), this, SLOT(reject())); - - QLabel *logoLabel = new QLabel; - logoLabel->setPixmap(QPixmap(QLatin1String(":/core/images/qtcreator_logo_128.png"))); - layout->addWidget(logoLabel , 0, 0, 1, 1); - layout->addWidget(copyRightLabel, 0, 1, 4, 4); - layout->addWidget(buttonBox, 4, 0, 1, 5); -} +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include "versiondialog.h" + +#include "coreconstants.h" +#include "icore.h" + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +using namespace Core; +using namespace Core::Internal; +using namespace Core::Constants; + +VersionDialog::VersionDialog(QWidget *parent) + : QDialog(parent) +{ + // We need to set the window icon explicitly here since for some reason the + // application icon isn't used when the size of the dialog is fixed (at least not on X11/GNOME) + setWindowIcon(QIcon(":/core/images/qtcreator_logo_128.png")); + + setWindowTitle(tr("About Qt Creator")); + setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint); + QGridLayout *layout = new QGridLayout(this); + layout->setSizeConstraint(QLayout::SetFixedSize); + + QString version = QLatin1String(GCS_VERSION_LONG); + version += QDate(2007, 25, 10).toString(Qt::SystemLocaleDate); + + QString ideRev; +#ifdef GCS_REVISION + //: This gets conditionally inserted as argument %8 into the description string. + ideRev = tr("From revision %1
").arg(QString::fromLatin1(GCS_REVISION_STR).left(10)); +#endif + + const QString description = tr( + "

Qt Creator %1

" + "Based on Qt %2 (%3 bit)
" + "
" + "Built on %4 at %5
" + "
" + "%8" + "
" + "Copyright 2008-%6 %7. All rights reserved.
" + "
" + "The program is provided AS IS with NO WARRANTY OF ANY KIND, " + "INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A " + "PARTICULAR PURPOSE.
") + .arg(version, QLatin1String(QT_VERSION_STR), QString::number(QSysInfo::WordSize), + QLatin1String(__DATE__), QLatin1String(__TIME__), QLatin1String(GCS_YEAR), + (QLatin1String(GCS_AUTHOR)), ideRev); + + QLabel *copyRightLabel = new QLabel(description); + copyRightLabel->setWordWrap(true); + copyRightLabel->setOpenExternalLinks(true); + copyRightLabel->setTextInteractionFlags(Qt::TextBrowserInteraction); + + QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close); + QPushButton *closeButton = buttonBox->button(QDialogButtonBox::Close); + QTC_ASSERT(closeButton, /**/); + buttonBox->addButton(closeButton, QDialogButtonBox::ButtonRole(QDialogButtonBox::RejectRole | QDialogButtonBox::AcceptRole)); + connect(buttonBox , SIGNAL(rejected()), this, SLOT(reject())); + + QLabel *logoLabel = new QLabel; + logoLabel->setPixmap(QPixmap(QLatin1String(":/core/images/qtcreator_logo_128.png"))); + layout->addWidget(logoLabel , 0, 0, 1, 1); + layout->addWidget(copyRightLabel, 0, 1, 4, 4); + layout->addWidget(buttonBox, 4, 0, 1, 5); +} diff --git a/ground/src/plugins/welcome/Welcome.pluginspec b/ground/src/plugins/welcome/Welcome.pluginspec index f627ac415..2b6591162 100644 --- a/ground/src/plugins/welcome/Welcome.pluginspec +++ b/ground/src/plugins/welcome/Welcome.pluginspec @@ -1,4 +1,4 @@ - + The OpenPilot Project (C) 2010 OpenPilot Project @@ -12,6 +12,6 @@ will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. Default Welcome Screen Plugin http://www.openpilot.org - + diff --git a/ground/src/plugins/welcome/rssfetcher.cpp b/ground/src/plugins/welcome/rssfetcher.cpp index 6f14715b7..5f1a4470a 100644 --- a/ground/src/plugins/welcome/rssfetcher.cpp +++ b/ground/src/plugins/welcome/rssfetcher.cpp @@ -1,187 +1,187 @@ -/************************************************************************** -** -** This file is part of Qt Creator -** -** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). -** -** Contact: Nokia Corporation (qt-info@nokia.com) -** -** Commercial Usage -** -** Licensees holding valid Qt Commercial licenses may use this file in -** accordance with the Qt Commercial License Agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and Nokia. -** -** GNU Lesser General Public License Usage -** -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 2.1 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. -** -** If you are unsure which license is appropriate for your use, please -** contact the sales department at http://qt.nokia.com/contact. -** -**************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "rssfetcher.h" - -#ifdef Q_OS_UNIX -#include -#endif - -using namespace Welcome::Internal; - -static const QString getOsString() -{ - QString osString; -#if defined(Q_OS_WIN) - switch (QSysInfo::WindowsVersion) { - case (QSysInfo::WV_4_0): - osString += QLatin1String("WinNT4.0"); - break; - case (QSysInfo::WV_5_0): - osString += QLatin1String("Windows NT 5.0"); - break; - case (QSysInfo::WV_5_1): - osString += QLatin1String("Windows NT 5.1"); - break; - case (QSysInfo::WV_5_2): - osString += QLatin1String("Windows NT 5.2"); - break; - case (QSysInfo::WV_6_0): - osString += QLatin1String("Windows NT 6.0"); - break; - case (QSysInfo::WV_6_1): - osString += QLatin1String("Windows NT 6.1"); - break; - default: - osString += QLatin1String("Windows NT (Unknown)"); - break; - } -#elif defined (Q_OS_MAC) - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) - osString += QLatin1String("PPC "); - else - osString += QLatin1String("Intel "); - osString += QLatin1String("Mac OS X "); - switch (QSysInfo::MacintoshVersion) { - case (QSysInfo::MV_10_3): - osString += QLatin1String("10_3"); - break; - case (QSysInfo::MV_10_4): - osString += QLatin1String("10_4"); - break; - case (QSysInfo::MV_10_5): - osString += QLatin1String("10_5"); - break; - case (QSysInfo::MV_10_6): - osString += QLatin1String("10_6"); - break; - default: - osString += QLatin1String("(Unknown)"); - break; - } -#elif defined (Q_OS_UNIX) - struct utsname uts; - if (uname(&uts) == 0) - osString += QString("%1 %2").arg(QLatin1String(uts.sysname)) - .arg(QLatin1String(uts.release)); - else - osString += QLatin1String("Unix (Unknown)"); -#else - ossttring = QLatin1String("Unknown OS"); -#endif - return osString; -} - -RSSFetcher::RSSFetcher(int maxItems, QObject *parent) - : QObject(parent), m_items(0), m_maxItems(maxItems) -{ - connect(&m_http, SIGNAL(readyRead(const QHttpResponseHeader &)), - this, SLOT(readData(const QHttpResponseHeader &))); - - connect(&m_http, SIGNAL(requestFinished(int, bool)), - this, SLOT(finished(int, bool))); -} - -void RSSFetcher::fetch(const QUrl &url) -{ - QList proxies = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(url)); - if (proxies.count() > 0) - m_http.setProxy(proxies.first()); - m_http.setHost(url.host()); - QString agentStr = QString("Qt-Creator/%1 (QHttp %2; %3; %4; %5 bit)") - .arg(Core::Constants::IDE_VERSION_LONG).arg(qVersion()) - .arg(getOsString()).arg(QLocale::system().name()) - .arg(QSysInfo::WordSize); - QHttpRequestHeader header("GET", url.path()); - //qDebug() << agentStr; - header.setValue("User-Agent", agentStr); - header.setValue("Host", url.host()); - m_connectionId = m_http.request(header); -} - -void RSSFetcher::readData(const QHttpResponseHeader &resp) -{ - if (resp.statusCode() != 200) - m_http.abort(); - else { - m_xml.addData(m_http.readAll()); - parseXml(); - } -} - -void RSSFetcher::finished(int id, bool error) -{ - Q_UNUSED(id) - m_items = 0; - emit finished(error); -} - -void RSSFetcher::parseXml() -{ - while (!m_xml.atEnd()) { - m_xml.readNext(); - if (m_xml.isStartElement()) { - if (m_xml.name() == "item") { - m_titleString.clear(); - m_descriptionString.clear(); - m_linkString.clear(); - } - m_currentTag = m_xml.name().toString(); - } else if (m_xml.isEndElement()) { - if (m_xml.name() == "item") { - m_items++; - if (m_items > m_maxItems) - return; - emit newsItemReady(m_titleString, m_descriptionString, m_linkString); - } - - } else if (m_xml.isCharacters() && !m_xml.isWhitespace()) { - if (m_currentTag == "title") - m_titleString += m_xml.text().toString(); - else if (m_currentTag == "description") - m_descriptionString += m_xml.text().toString(); - else if (m_currentTag == "link") - m_linkString += m_xml.text().toString(); - } - } - if (m_xml.error() && m_xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) { - qWarning() << "XML ERROR:" << m_xml.lineNumber() << ": " << m_xml.errorString(); - m_http.abort(); - } -} +/************************************************************************** +** +** This file is part of Qt Creator +** +** Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies). +** +** Contact: Nokia Corporation (qt-info@nokia.com) +** +** Commercial Usage +** +** Licensees holding valid Qt Commercial licenses may use this file in +** accordance with the Qt Commercial License Agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Nokia. +** +** GNU Lesser General Public License Usage +** +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 2.1 requirements +** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** If you are unsure which license is appropriate for your use, please +** contact the sales department at http://qt.nokia.com/contact. +** +**************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "rssfetcher.h" + +#ifdef Q_OS_UNIX +#include +#endif + +using namespace Welcome::Internal; + +static const QString getOsString() +{ + QString osString; +#if defined(Q_OS_WIN) + switch (QSysInfo::WindowsVersion) { + case (QSysInfo::WV_4_0): + osString += QLatin1String("WinNT4.0"); + break; + case (QSysInfo::WV_5_0): + osString += QLatin1String("Windows NT 5.0"); + break; + case (QSysInfo::WV_5_1): + osString += QLatin1String("Windows NT 5.1"); + break; + case (QSysInfo::WV_5_2): + osString += QLatin1String("Windows NT 5.2"); + break; + case (QSysInfo::WV_6_0): + osString += QLatin1String("Windows NT 6.0"); + break; + case (QSysInfo::WV_6_1): + osString += QLatin1String("Windows NT 6.1"); + break; + default: + osString += QLatin1String("Windows NT (Unknown)"); + break; + } +#elif defined (Q_OS_MAC) + if (QSysInfo::ByteOrder == QSysInfo::BigEndian) + osString += QLatin1String("PPC "); + else + osString += QLatin1String("Intel "); + osString += QLatin1String("Mac OS X "); + switch (QSysInfo::MacintoshVersion) { + case (QSysInfo::MV_10_3): + osString += QLatin1String("10_3"); + break; + case (QSysInfo::MV_10_4): + osString += QLatin1String("10_4"); + break; + case (QSysInfo::MV_10_5): + osString += QLatin1String("10_5"); + break; + case (QSysInfo::MV_10_6): + osString += QLatin1String("10_6"); + break; + default: + osString += QLatin1String("(Unknown)"); + break; + } +#elif defined (Q_OS_UNIX) + struct utsname uts; + if (uname(&uts) == 0) + osString += QString("%1 %2").arg(QLatin1String(uts.sysname)) + .arg(QLatin1String(uts.release)); + else + osString += QLatin1String("Unix (Unknown)"); +#else + ossttring = QLatin1String("Unknown OS"); +#endif + return osString; +} + +RSSFetcher::RSSFetcher(int maxItems, QObject *parent) + : QObject(parent), m_items(0), m_maxItems(maxItems) +{ + connect(&m_http, SIGNAL(readyRead(const QHttpResponseHeader &)), + this, SLOT(readData(const QHttpResponseHeader &))); + + connect(&m_http, SIGNAL(requestFinished(int, bool)), + this, SLOT(finished(int, bool))); +} + +void RSSFetcher::fetch(const QUrl &url) +{ + QList proxies = QNetworkProxyFactory::systemProxyForQuery(QNetworkProxyQuery(url)); + if (proxies.count() > 0) + m_http.setProxy(proxies.first()); + m_http.setHost(url.host()); + QString agentStr = QString("Qt-Creator/%1 (QHttp %2; %3; %4; %5 bit)") + .arg(Core::Constants::GCS_VERSION_LONG).arg(qVersion()) + .arg(getOsString()).arg(QLocale::system().name()) + .arg(QSysInfo::WordSize); + QHttpRequestHeader header("GET", url.path()); + //qDebug() << agentStr; + header.setValue("User-Agent", agentStr); + header.setValue("Host", url.host()); + m_connectionId = m_http.request(header); +} + +void RSSFetcher::readData(const QHttpResponseHeader &resp) +{ + if (resp.statusCode() != 200) + m_http.abort(); + else { + m_xml.addData(m_http.readAll()); + parseXml(); + } +} + +void RSSFetcher::finished(int id, bool error) +{ + Q_UNUSED(id) + m_items = 0; + emit finished(error); +} + +void RSSFetcher::parseXml() +{ + while (!m_xml.atEnd()) { + m_xml.readNext(); + if (m_xml.isStartElement()) { + if (m_xml.name() == "item") { + m_titleString.clear(); + m_descriptionString.clear(); + m_linkString.clear(); + } + m_currentTag = m_xml.name().toString(); + } else if (m_xml.isEndElement()) { + if (m_xml.name() == "item") { + m_items++; + if (m_items > m_maxItems) + return; + emit newsItemReady(m_titleString, m_descriptionString, m_linkString); + } + + } else if (m_xml.isCharacters() && !m_xml.isWhitespace()) { + if (m_currentTag == "title") + m_titleString += m_xml.text().toString(); + else if (m_currentTag == "description") + m_descriptionString += m_xml.text().toString(); + else if (m_currentTag == "link") + m_linkString += m_xml.text().toString(); + } + } + if (m_xml.error() && m_xml.error() != QXmlStreamReader::PrematureEndOfDocumentError) { + qWarning() << "XML ERROR:" << m_xml.lineNumber() << ": " << m_xml.errorString(); + m_http.abort(); + } +} diff --git a/ground/src/rpath.pri b/ground/src/rpath.pri index c29753b2a..6d769360e 100644 --- a/ground/src/rpath.pri +++ b/ground/src/rpath.pri @@ -4,8 +4,8 @@ macx { #do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR # this expands to $ORIGIN (after qmake and make), it does NOT read a qmake var QMAKE_RPATHDIR += \$\$ORIGIN/../$$GCS_LIBRARY_BASENAME/openpilotgcs - IDE_PLUGIN_RPATH = $$join(QMAKE_RPATHDIR, ":") + GCS_PLUGIN_RPATH = $$join(QMAKE_RPATHDIR, ":") - QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${IDE_PLUGIN_RPATH}\' + QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${GCS_PLUGIN_RPATH}\' QMAKE_RPATHDIR = }