mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-01-29 14:52:12 +01:00
Build system branding
git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@167 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
parent
f45670c82e
commit
0703a7df2e
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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 \
|
||||
|
@ -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 <QtCore/QMetaProperty>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QTextStream>
|
||||
#include <QtCore/QWriteLocker>
|
||||
#include <QtDebug>
|
||||
#ifdef WITH_TESTS
|
||||
#include <QTest>
|
||||
#endif
|
||||
|
||||
typedef QList<ExtensionSystem::PluginSpec *> 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<MimeTypeHandler *> mimeHandlers =
|
||||
ExtensionSystem::PluginManager::instance()->getObjects<MimeTypeHandler>();
|
||||
\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<T *> 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<QObject *> 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<QObject *> 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<PluginSpec *> 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<PluginSpec *> PluginManager::plugins() const
|
||||
{
|
||||
return d->pluginSpecs;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool PluginManager::parseOptions(const QStringList &args, const QMap<QString, bool> &appOptions, QMap<QString, QString> *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 <plugin>), 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<QString, bool> &appOptions,
|
||||
QMap<QString, QString> *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 <plugin>"),
|
||||
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<PluginSpec *> queue = loadQueue();
|
||||
foreach (PluginSpec *spec, queue) {
|
||||
loadPlugin(spec, PluginSpec::Stopped);
|
||||
}
|
||||
QListIterator<PluginSpec *> 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<PluginSpec *> queue = loadQueue();
|
||||
foreach (PluginSpec *spec, queue) {
|
||||
loadPlugin(spec, PluginSpec::Loaded);
|
||||
}
|
||||
foreach (PluginSpec *spec, queue) {
|
||||
loadPlugin(spec, PluginSpec::Initialized);
|
||||
}
|
||||
QListIterator<PluginSpec *> it(queue);
|
||||
it.toBack();
|
||||
while (it.hasPrevious()) {
|
||||
loadPlugin(it.previous(), PluginSpec::Running);
|
||||
}
|
||||
emit q->pluginsChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn void PluginManagerPrivate::loadQueue()
|
||||
\internal
|
||||
*/
|
||||
QList<PluginSpec *> PluginManagerPrivate::loadQueue()
|
||||
{
|
||||
QList<PluginSpec *> queue;
|
||||
foreach (PluginSpec *spec, pluginSpecs) {
|
||||
QList<PluginSpec *> circularityCheckQueue;
|
||||
loadQueue(spec, queue, circularityCheckQueue);
|
||||
}
|
||||
return queue;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queue, QList<PluginSpec *> &circularityCheckQueue)
|
||||
\internal
|
||||
*/
|
||||
bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queue,
|
||||
QList<PluginSpec *> &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 <QtCore/QMetaProperty>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QTextStream>
|
||||
#include <QtCore/QWriteLocker>
|
||||
#include <QtDebug>
|
||||
#ifdef WITH_TESTS
|
||||
#include <QTest>
|
||||
#endif
|
||||
|
||||
typedef QList<ExtensionSystem::PluginSpec *> 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<MimeTypeHandler *> mimeHandlers =
|
||||
ExtensionSystem::PluginManager::instance()->getObjects<MimeTypeHandler>();
|
||||
\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<T *> 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<QObject *> 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<QObject *> 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<PluginSpec *> 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<PluginSpec *> PluginManager::plugins() const
|
||||
{
|
||||
return d->pluginSpecs;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool PluginManager::parseOptions(const QStringList &args, const QMap<QString, bool> &appOptions, QMap<QString, QString> *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 <plugin>), 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<QString, bool> &appOptions,
|
||||
QMap<QString, QString> *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 <plugin>"),
|
||||
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<PluginSpec *> queue = loadQueue();
|
||||
foreach (PluginSpec *spec, queue) {
|
||||
loadPlugin(spec, PluginSpec::Stopped);
|
||||
}
|
||||
QListIterator<PluginSpec *> 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<PluginSpec *> queue = loadQueue();
|
||||
foreach (PluginSpec *spec, queue) {
|
||||
loadPlugin(spec, PluginSpec::Loaded);
|
||||
}
|
||||
foreach (PluginSpec *spec, queue) {
|
||||
loadPlugin(spec, PluginSpec::Initialized);
|
||||
}
|
||||
QListIterator<PluginSpec *> it(queue);
|
||||
it.toBack();
|
||||
while (it.hasPrevious()) {
|
||||
loadPlugin(it.previous(), PluginSpec::Running);
|
||||
}
|
||||
emit q->pluginsChanged();
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn void PluginManagerPrivate::loadQueue()
|
||||
\internal
|
||||
*/
|
||||
QList<PluginSpec *> PluginManagerPrivate::loadQueue()
|
||||
{
|
||||
QList<PluginSpec *> queue;
|
||||
foreach (PluginSpec *spec, pluginSpecs) {
|
||||
QList<PluginSpec *> circularityCheckQueue;
|
||||
loadQueue(spec, queue, circularityCheckQueue);
|
||||
}
|
||||
return queue;
|
||||
}
|
||||
|
||||
/*!
|
||||
\fn bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queue, QList<PluginSpec *> &circularityCheckQueue)
|
||||
\internal
|
||||
*/
|
||||
bool PluginManagerPrivate::loadQueue(PluginSpec *spec, QList<PluginSpec *> &queue,
|
||||
QList<PluginSpec *> &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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
<plugin name="Core" version="1.1" compatVersion="1.1">
|
||||
<plugin name="Core" version="1.3.1" compatVersion="1.3.1">
|
||||
<vendor>The OpenPilot Project</vendor>
|
||||
<copyright>(C) 2010 OpenPilot Project</copyright>
|
||||
<license>
|
||||
|
@ -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
|
||||
|
@ -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 <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/modemanager.h>
|
||||
#include <coreplugin/uniqueidmanager.h>
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/editormanager/ieditorfactory.h>
|
||||
#include <coreplugin/editormanager/iexternaleditor.h>
|
||||
#include <coreplugin/baseview.h>
|
||||
#include <coreplugin/imode.h>
|
||||
#include <coreplugin/settingsdatabase.h>
|
||||
#include <coreplugin/variablemanager.h>
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <utils/consoleprocess.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QSettings>
|
||||
|
||||
#include <QtGui/QAction>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QFileDialog>
|
||||
#include <QtGui/QLayout>
|
||||
#include <QtGui/QMainWindow>
|
||||
#include <QtGui/QMenu>
|
||||
#include <QtGui/QMessageBox>
|
||||
#include <QtGui/QPushButton>
|
||||
#include <QtGui/QSplitter>
|
||||
#include <QtGui/QStackedLayout>
|
||||
|
||||
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<IEditor> m_currentEditor;
|
||||
QPointer<SplitterOrView> 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<QString, QVariant> 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<int> &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<int> gc = QList<int>() << Constants::C_GLOBAL_ID;
|
||||
const QList<int> editManagerContext =
|
||||
QList<int>() << 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<int> 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<IEditor*>(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<IEditor *> EditorManager::editorsForFileName(const QString &filename) const
|
||||
{
|
||||
QList<IEditor *> found;
|
||||
QString fixedname = FileManager::fixFileName(filename);
|
||||
foreach (IEditor *editor, openedEditors()) {
|
||||
if (fixedname == FileManager::fixFileName(editor->file()->fileName()))
|
||||
found << editor;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
QList<IEditor *> EditorManager::editorsForFile(IFile *file) const
|
||||
{
|
||||
QList<IEditor *> 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<IEditor *> 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<IEditor *>() << 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<IEditor*>
|
||||
EditorManager::editorsForFiles(QList<IFile*> files) const
|
||||
{
|
||||
const QList<IEditor *> editors = openedEditors();
|
||||
QSet<IEditor *> found;
|
||||
foreach (IFile *file, files) {
|
||||
foreach (IEditor *editor, editors) {
|
||||
if (editor->file() == file && !found.contains(editor)) {
|
||||
found << editor;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found.toList();
|
||||
}
|
||||
|
||||
QList<IFile *> EditorManager::filesForEditors(QList<IEditor *> editors) const
|
||||
{
|
||||
QSet<IEditor *> handledEditors;
|
||||
QList<IFile *> 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<IEditor*> 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<IEditor *>() << editor);
|
||||
}
|
||||
|
||||
void EditorManager::closeEditor(const QModelIndex &index)
|
||||
{
|
||||
IEditor *editor = index.data(Qt::UserRole).value<Core::IEditor*>();
|
||||
if (editor)
|
||||
closeEditor(editor);
|
||||
else
|
||||
m_d->m_editorModel->removeEditor(index);
|
||||
}
|
||||
|
||||
bool EditorManager::closeEditors(const QList<IEditor*> editorsToClose, bool askAboutModifiedEditors)
|
||||
{
|
||||
if (editorsToClose.isEmpty())
|
||||
return true;
|
||||
|
||||
SplitterOrView *currentSplitterOrView = this->currentSplitterOrView();
|
||||
|
||||
bool closingFailed = false;
|
||||
QList<IEditor*> acceptedEditors;
|
||||
//ask all core listeners to check whether the editor can be closed
|
||||
const QList<ICoreListener *> listeners =
|
||||
pluginManager()->getObjects<ICoreListener>();
|
||||
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<IFile*> list = m_d->m_core->fileManager()->
|
||||
saveModifiedFiles(filesForEditors(acceptedEditors), &cancelled);
|
||||
if (cancelled)
|
||||
return false;
|
||||
if (!list.isEmpty()) {
|
||||
closingFailed = true;
|
||||
QSet<IEditor*> 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<EditorView*> 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<IEditor *> 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<IEditor*>() << 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<IEditor*>();
|
||||
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<IEditor*> 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 <class EditorFactoryLike>
|
||||
static void mimeTypeFactoryRecursion(const MimeDatabase *db,
|
||||
const MimeType &mimeType,
|
||||
const QList<EditorFactoryLike*> &allFactories,
|
||||
bool firstMatchOnly,
|
||||
QList<EditorFactoryLike*> *list)
|
||||
{
|
||||
typedef typename QList<EditorFactoryLike*>::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<IEditorFactory>();
|
||||
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<IExternalEditor>();
|
||||
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 <class EditorFactoryLike>
|
||||
inline EditorFactoryLike *findByKind(ExtensionSystem::PluginManager *pm,
|
||||
const QString &kind)
|
||||
{
|
||||
const QList<EditorFactoryLike *> factories = pm->template getObjects<EditorFactoryLike>();
|
||||
foreach(EditorFactoryLike *efl, factories)
|
||||
if (kind == efl->kind())
|
||||
return efl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
IEditor *EditorManager::createEditor(const QString &editorKind,
|
||||
const QString &fileName)
|
||||
{
|
||||
typedef QList<IEditorFactory*> 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<IEditorFactory>(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<IEditor *> 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<IExternalEditor>(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<QString> 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<IEditor *> 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("<b>Warning:</b> 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<IEditor*> 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<IEditor *> 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<OpenEditorsModel::Entry> 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<QString, QVariant> editorstates;
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
stream >> editorstates;
|
||||
|
||||
QMapIterator<QString, QVariant> 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<QMap<QString, QVariant> >();
|
||||
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<QMap<QString, QVariant> >();
|
||||
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(
|
||||
"<table border=1 cellspacing=0 cellpadding=3>"
|
||||
"<tr><th>Variable</th><th>Expands to</th></tr>"
|
||||
"<tr><td>%f</td><td>file name</td></tr>"
|
||||
"<tr><td>%l</td><td>current line number</td></tr>"
|
||||
"<tr><td>%c</td><td>current column number</td></tr>"
|
||||
"<tr><td>%x</td><td>editor's x position on screen</td></tr>"
|
||||
"<tr><td>%y</td><td>editor's y position on screen</td></tr>"
|
||||
"<tr><td>%w</td><td>editor's width in pixels</td></tr>"
|
||||
"<tr><td>%h</td><td>editor's height in pixels</td></tr>"
|
||||
"<tr><td>%W</td><td>editor's width in characters</td></tr>"
|
||||
"<tr><td>%H</td><td>editor's height in characters</td></tr>"
|
||||
"<tr><td>%%</td><td>%</td></tr>"
|
||||
"</table>");
|
||||
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<IFile*> list = m_d->m_core->fileManager()->
|
||||
saveModifiedFiles(QList<IFile*>() << 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 <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/modemanager.h>
|
||||
#include <coreplugin/uniqueidmanager.h>
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/editormanager/ieditorfactory.h>
|
||||
#include <coreplugin/editormanager/iexternaleditor.h>
|
||||
#include <coreplugin/baseview.h>
|
||||
#include <coreplugin/imode.h>
|
||||
#include <coreplugin/settingsdatabase.h>
|
||||
#include <coreplugin/variablemanager.h>
|
||||
|
||||
#include <extensionsystem/pluginmanager.h>
|
||||
|
||||
#include <utils/consoleprocess.h>
|
||||
#include <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtCore/QProcess>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QSettings>
|
||||
|
||||
#include <QtGui/QAction>
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QFileDialog>
|
||||
#include <QtGui/QLayout>
|
||||
#include <QtGui/QMainWindow>
|
||||
#include <QtGui/QMenu>
|
||||
#include <QtGui/QMessageBox>
|
||||
#include <QtGui/QPushButton>
|
||||
#include <QtGui/QSplitter>
|
||||
#include <QtGui/QStackedLayout>
|
||||
|
||||
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<IEditor> m_currentEditor;
|
||||
QPointer<SplitterOrView> 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<QString, QVariant> 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<int> &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<int> gc = QList<int>() << Constants::C_GLOBAL_ID;
|
||||
const QList<int> editManagerContext =
|
||||
QList<int>() << 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<int> 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<IEditor*>(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<IEditor *> EditorManager::editorsForFileName(const QString &filename) const
|
||||
{
|
||||
QList<IEditor *> found;
|
||||
QString fixedname = FileManager::fixFileName(filename);
|
||||
foreach (IEditor *editor, openedEditors()) {
|
||||
if (fixedname == FileManager::fixFileName(editor->file()->fileName()))
|
||||
found << editor;
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
QList<IEditor *> EditorManager::editorsForFile(IFile *file) const
|
||||
{
|
||||
QList<IEditor *> 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<IEditor *> 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<IEditor *>() << 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<IEditor*>
|
||||
EditorManager::editorsForFiles(QList<IFile*> files) const
|
||||
{
|
||||
const QList<IEditor *> editors = openedEditors();
|
||||
QSet<IEditor *> found;
|
||||
foreach (IFile *file, files) {
|
||||
foreach (IEditor *editor, editors) {
|
||||
if (editor->file() == file && !found.contains(editor)) {
|
||||
found << editor;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found.toList();
|
||||
}
|
||||
|
||||
QList<IFile *> EditorManager::filesForEditors(QList<IEditor *> editors) const
|
||||
{
|
||||
QSet<IEditor *> handledEditors;
|
||||
QList<IFile *> 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<IEditor*> 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<IEditor *>() << editor);
|
||||
}
|
||||
|
||||
void EditorManager::closeEditor(const QModelIndex &index)
|
||||
{
|
||||
IEditor *editor = index.data(Qt::UserRole).value<Core::IEditor*>();
|
||||
if (editor)
|
||||
closeEditor(editor);
|
||||
else
|
||||
m_d->m_editorModel->removeEditor(index);
|
||||
}
|
||||
|
||||
bool EditorManager::closeEditors(const QList<IEditor*> editorsToClose, bool askAboutModifiedEditors)
|
||||
{
|
||||
if (editorsToClose.isEmpty())
|
||||
return true;
|
||||
|
||||
SplitterOrView *currentSplitterOrView = this->currentSplitterOrView();
|
||||
|
||||
bool closingFailed = false;
|
||||
QList<IEditor*> acceptedEditors;
|
||||
//ask all core listeners to check whether the editor can be closed
|
||||
const QList<ICoreListener *> listeners =
|
||||
pluginManager()->getObjects<ICoreListener>();
|
||||
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<IFile*> list = m_d->m_core->fileManager()->
|
||||
saveModifiedFiles(filesForEditors(acceptedEditors), &cancelled);
|
||||
if (cancelled)
|
||||
return false;
|
||||
if (!list.isEmpty()) {
|
||||
closingFailed = true;
|
||||
QSet<IEditor*> 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<EditorView*> 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<IEditor *> 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<IEditor*>() << 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<IEditor*>();
|
||||
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<IEditor*> 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 <class EditorFactoryLike>
|
||||
static void mimeTypeFactoryRecursion(const MimeDatabase *db,
|
||||
const MimeType &mimeType,
|
||||
const QList<EditorFactoryLike*> &allFactories,
|
||||
bool firstMatchOnly,
|
||||
QList<EditorFactoryLike*> *list)
|
||||
{
|
||||
typedef typename QList<EditorFactoryLike*>::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<IEditorFactory>();
|
||||
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<IExternalEditor>();
|
||||
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 <class EditorFactoryLike>
|
||||
inline EditorFactoryLike *findByKind(ExtensionSystem::PluginManager *pm,
|
||||
const QString &kind)
|
||||
{
|
||||
const QList<EditorFactoryLike *> factories = pm->template getObjects<EditorFactoryLike>();
|
||||
foreach(EditorFactoryLike *efl, factories)
|
||||
if (kind == efl->kind())
|
||||
return efl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
IEditor *EditorManager::createEditor(const QString &editorKind,
|
||||
const QString &fileName)
|
||||
{
|
||||
typedef QList<IEditorFactory*> 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<IEditorFactory>(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<IEditor *> 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<IExternalEditor>(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<QString> 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<IEditor *> 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("<b>Warning:</b> 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<IEditor*> 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<IEditor *> 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<OpenEditorsModel::Entry> 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<QString, QVariant> editorstates;
|
||||
|
||||
QApplication::setOverrideCursor(Qt::WaitCursor);
|
||||
|
||||
stream >> editorstates;
|
||||
|
||||
QMapIterator<QString, QVariant> 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<QMap<QString, QVariant> >();
|
||||
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<QMap<QString, QVariant> >();
|
||||
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(
|
||||
"<table border=1 cellspacing=0 cellpadding=3>"
|
||||
"<tr><th>Variable</th><th>Expands to</th></tr>"
|
||||
"<tr><td>%f</td><td>file name</td></tr>"
|
||||
"<tr><td>%l</td><td>current line number</td></tr>"
|
||||
"<tr><td>%c</td><td>current column number</td></tr>"
|
||||
"<tr><td>%x</td><td>editor's x position on screen</td></tr>"
|
||||
"<tr><td>%y</td><td>editor's y position on screen</td></tr>"
|
||||
"<tr><td>%w</td><td>editor's width in pixels</td></tr>"
|
||||
"<tr><td>%h</td><td>editor's height in pixels</td></tr>"
|
||||
"<tr><td>%W</td><td>editor's width in characters</td></tr>"
|
||||
"<tr><td>%H</td><td>editor's height in characters</td></tr>"
|
||||
"<tr><td>%%</td><td>%</td></tr>"
|
||||
"</table>");
|
||||
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<IFile*> list = m_d->m_core->fileManager()->
|
||||
saveModifiedFiles(QList<IFile*>() << 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);
|
||||
}
|
||||
|
@ -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 <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/editormanager/ieditor.h>
|
||||
|
||||
#include <coreplugin/findplaceholder.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/styledbar.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QMimeData>
|
||||
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QComboBox>
|
||||
#include <QtGui/QHBoxLayout>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QStackedWidget>
|
||||
#include <QtGui/QStyle>
|
||||
#include <QtGui/QStyleOption>
|
||||
#include <QtGui/QToolButton>
|
||||
#include <QtGui/QMenu>
|
||||
#include <QtGui/QClipboard>
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
#include <qmacstyle_mac.h>
|
||||
#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<IEditor *>(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<IEditor *> 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<IEditor*>()) {
|
||||
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<QMacStyle *>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(m_splitter->widget(0))->saveState()
|
||||
<< static_cast<SplitterOrView*>(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<SplitterOrView*>(m_splitter->widget(0))->restoreState(first);
|
||||
static_cast<SplitterOrView*>(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 <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/actionmanager/actionmanager.h>
|
||||
#include <coreplugin/editormanager/ieditor.h>
|
||||
|
||||
#include <coreplugin/findplaceholder.h>
|
||||
#include <utils/qtcassert.h>
|
||||
#include <utils/styledbar.h>
|
||||
|
||||
#include <QtCore/QDebug>
|
||||
#include <QtCore/QDir>
|
||||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QMimeData>
|
||||
|
||||
#include <QtGui/QApplication>
|
||||
#include <QtGui/QComboBox>
|
||||
#include <QtGui/QHBoxLayout>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QMouseEvent>
|
||||
#include <QtGui/QPainter>
|
||||
#include <QtGui/QStackedWidget>
|
||||
#include <QtGui/QStyle>
|
||||
#include <QtGui/QStyleOption>
|
||||
#include <QtGui/QToolButton>
|
||||
#include <QtGui/QMenu>
|
||||
#include <QtGui/QClipboard>
|
||||
|
||||
#ifdef Q_WS_MAC
|
||||
#include <qmacstyle_mac.h>
|
||||
#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<IEditor *>(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<IEditor *> 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<IEditor*>()) {
|
||||
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<QMacStyle *>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(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<SplitterOrView*>(m_splitter->widget(0))->saveState()
|
||||
<< static_cast<SplitterOrView*>(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<SplitterOrView*>(m_splitter->widget(0))->restoreState(first);
|
||||
static_cast<SplitterOrView*>(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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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 <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QDate>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QSysInfo>
|
||||
|
||||
#include <QtGui/QDialogButtonBox>
|
||||
#include <QtGui/QGridLayout>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QPushButton>
|
||||
#include <QtGui/QTextBrowser>
|
||||
|
||||
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<br/>").arg(QString::fromLatin1(IDE_REVISION_STR).left(10));
|
||||
#endif
|
||||
|
||||
const QString description = tr(
|
||||
"<h3>Qt Creator %1</h3>"
|
||||
"Based on Qt %2 (%3 bit)<br/>"
|
||||
"<br/>"
|
||||
"Built on %4 at %5<br />"
|
||||
"<br/>"
|
||||
"%8"
|
||||
"<br/>"
|
||||
"Copyright 2008-%6 %7. All rights reserved.<br/>"
|
||||
"<br/>"
|
||||
"The program is provided AS IS with NO WARRANTY OF ANY KIND, "
|
||||
"INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A "
|
||||
"PARTICULAR PURPOSE.<br/>")
|
||||
.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 <utils/qtcassert.h>
|
||||
|
||||
#include <QtCore/QDate>
|
||||
#include <QtCore/QFile>
|
||||
#include <QtCore/QSysInfo>
|
||||
|
||||
#include <QtGui/QDialogButtonBox>
|
||||
#include <QtGui/QGridLayout>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QPushButton>
|
||||
#include <QtGui/QTextBrowser>
|
||||
|
||||
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<br/>").arg(QString::fromLatin1(GCS_REVISION_STR).left(10));
|
||||
#endif
|
||||
|
||||
const QString description = tr(
|
||||
"<h3>Qt Creator %1</h3>"
|
||||
"Based on Qt %2 (%3 bit)<br/>"
|
||||
"<br/>"
|
||||
"Built on %4 at %5<br />"
|
||||
"<br/>"
|
||||
"%8"
|
||||
"<br/>"
|
||||
"Copyright 2008-%6 %7. All rights reserved.<br/>"
|
||||
"<br/>"
|
||||
"The program is provided AS IS with NO WARRANTY OF ANY KIND, "
|
||||
"INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A "
|
||||
"PARTICULAR PURPOSE.<br/>")
|
||||
.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);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<plugin name="Welcome" version="1.1" compatVersion="1.1">
|
||||
<plugin name="Welcome" version="1.3.1" compatVersion="1.3.1">
|
||||
<vendor>The OpenPilot Project</vendor>
|
||||
<copyright>(C) 2010 OpenPilot Project</copyright>
|
||||
<license>
|
||||
@ -12,6 +12,6 @@ will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.</license>
|
||||
<description>Default Welcome Screen Plugin</description>
|
||||
<url>http://www.openpilot.org</url>
|
||||
<dependencyList>
|
||||
<dependency name="Core" version="1.1"/>
|
||||
<dependency name="Core" version="1.3.1"/>
|
||||
</dependencyList>
|
||||
</plugin>
|
||||
|
@ -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 <QtCore/QDebug>
|
||||
#include <QtCore/QSysInfo>
|
||||
#include <QtCore/QLocale>
|
||||
#include <QtGui/QDesktopServices>
|
||||
#include <QtGui/QLineEdit>
|
||||
#include <QtNetwork/QHttp>
|
||||
#include <QtNetwork/QNetworkProxyFactory>
|
||||
|
||||
#include <coreplugin/coreconstants.h>
|
||||
|
||||
#include "rssfetcher.h"
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <sys/utsname.h>
|
||||
#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<QNetworkProxy> 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 <QtCore/QDebug>
|
||||
#include <QtCore/QSysInfo>
|
||||
#include <QtCore/QLocale>
|
||||
#include <QtGui/QDesktopServices>
|
||||
#include <QtGui/QLineEdit>
|
||||
#include <QtNetwork/QHttp>
|
||||
#include <QtNetwork/QNetworkProxyFactory>
|
||||
|
||||
#include <coreplugin/coreconstants.h>
|
||||
|
||||
#include "rssfetcher.h"
|
||||
|
||||
#ifdef Q_OS_UNIX
|
||||
#include <sys/utsname.h>
|
||||
#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<QNetworkProxy> 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();
|
||||
}
|
||||
}
|
||||
|
@ -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 =
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user