1
0
mirror of https://bitbucket.org/librepilot/librepilot.git synced 2024-11-29 07:24:13 +01:00

Branding again....

git-svn-id: svn://svn.openpilot.org/OpenPilot/trunk@169 ebee16cc-31ac-478f-84a7-5cbb03baadba
This commit is contained in:
dankers 2010-02-04 06:12:53 +00:00 committed by dankers
parent 3ffbcb4c0d
commit 690f4cced5
7 changed files with 1993 additions and 1990 deletions

View File

@ -1,48 +1,51 @@
<RCC>
<qresource prefix="/core" >
<file>images/clean_pane_small.png</file>
<file>images/clear.png</file>
<file>images/closebutton.png</file>
<file>images/dir.png</file>
<file>images/editcopy.png</file>
<file>images/editcut.png</file>
<file>images/editpaste.png</file>
<file>images/empty14.png</file>
<file>images/filenew.png</file>
<file>images/fileopen.png</file>
<file>images/filesave.png</file>
<file>images/find.png</file>
<file>images/findnext.png</file>
<file>images/qtcreator_logo_128.png</file>
<file>images/qtcreator_logo_32.png</file>
<file>images/inputfield.png</file>
<file>images/inputfield_disabled.png</file>
<file>images/linkicon.png</file>
<file>images/locked.png</file>
<file>images/magnifier.png</file>
<file>images/minus.png</file>
<file>images/next.png</file>
<file>images/panel_button.png</file>
<file>images/panel_button_checked.png</file>
<file>images/panel_button_checked_hover.png</file>
<file>images/panel_button_hover.png</file>
<file>images/panel_button_pressed.png</file>
<file>images/plus.png</file>
<file>images/prev.png</file>
<file>images/pushbutton.png</file>
<file>images/pushbutton_hover.png</file>
<file>images/pushbutton_pressed.png</file>
<file>images/qtwatermark.png</file>
<file>images/redo.png</file>
<file>images/replace.png</file>
<file>images/reset.png</file>
<file>images/sidebaricon.png</file>
<file>images/splitbutton_horizontal.png</file>
<file>images/statusbar.png</file>
<file>images/undo.png</file>
<file>images/unknownfile.png</file>
<file>images/unlocked.png</file>
<file>images/extension.png</file>
<file>images/darkclosebutton.png</file>
</qresource>
</RCC>
<RCC>
<qresource prefix="/core" >
<file>images/openpilot_logo_256.png</file>
<file>images/openpilot_logo_128.png</file>
<file>images/openpilot_logo_64.png</file>
<file>images/clean_pane_small.png</file>
<file>images/clear.png</file>
<file>images/closebutton.png</file>
<file>images/dir.png</file>
<file>images/editcopy.png</file>
<file>images/editcut.png</file>
<file>images/editpaste.png</file>
<file>images/empty14.png</file>
<file>images/filenew.png</file>
<file>images/fileopen.png</file>
<file>images/filesave.png</file>
<file>images/find.png</file>
<file>images/findnext.png</file>
<file>images/qtcreator_logo_128.png</file>
<file>images/qtcreator_logo_32.png</file>
<file>images/inputfield.png</file>
<file>images/inputfield_disabled.png</file>
<file>images/linkicon.png</file>
<file>images/locked.png</file>
<file>images/magnifier.png</file>
<file>images/minus.png</file>
<file>images/next.png</file>
<file>images/panel_button.png</file>
<file>images/panel_button_checked.png</file>
<file>images/panel_button_checked_hover.png</file>
<file>images/panel_button_hover.png</file>
<file>images/panel_button_pressed.png</file>
<file>images/plus.png</file>
<file>images/prev.png</file>
<file>images/pushbutton.png</file>
<file>images/pushbutton_hover.png</file>
<file>images/pushbutton_pressed.png</file>
<file>images/qtwatermark.png</file>
<file>images/redo.png</file>
<file>images/replace.png</file>
<file>images/reset.png</file>
<file>images/sidebaricon.png</file>
<file>images/splitbutton_horizontal.png</file>
<file>images/statusbar.png</file>
<file>images/undo.png</file>
<file>images/unknownfile.png</file>
<file>images/unlocked.png</file>
<file>images/extension.png</file>
<file>images/darkclosebutton.png</file>
</qresource>
</RCC>

View File

@ -122,7 +122,7 @@ 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 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";

View File

@ -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_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);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -156,7 +156,7 @@ MainWindow::MainWindow() :
setWindowTitle(tr("OpenPilot GCS"));
#ifndef Q_WS_MAC
qApp->setWindowIcon(QIcon(":/core/images/qtcreator_logo_128.png"));
qApp->setWindowIcon(QIcon(":/core/images/openpilot_logo_128.png"));
#endif
QCoreApplication::setApplicationName(QLatin1String("OpenPilotGCS"));
QCoreApplication::setApplicationVersion(QLatin1String(Core::Constants::GCS_VERSION_LONG));
@ -733,9 +733,9 @@ void MainWindow::registerDefaultActions()
// About IDE Action
#ifdef Q_WS_MAC
tmpaction = new QAction(tr("About &Qt Creator"), this); // it's convention not to add dots to the about menu
tmpaction = new QAction(tr("About &OpenPilot GCS"), this); // it's convention not to add dots to the about menu
#else
tmpaction = new QAction(tr("About &Qt Creator..."), this);
tmpaction = new QAction(tr("About &OpenPilot GCS..."), this);
#endif
cmd = am->registerAction(tmpaction, Constants::ABOUT_QTCREATOR, m_globalContext);
mhelp->addAction(cmd, Constants::G_HELP_ABOUT);

View File

@ -98,7 +98,7 @@ VersionDialog::VersionDialog(QWidget *parent)
connect(buttonBox , SIGNAL(rejected()), this, SLOT(reject()));
QLabel *logoLabel = new QLabel;
logoLabel->setPixmap(QPixmap(QLatin1String(":/core/images/qtcreator_logo_128.png")));
logoLabel->setPixmap(QPixmap(QLatin1String(":/core/images/openpilot_logo_128.png")));
layout->addWidget(logoLabel , 0, 0, 1, 1);
layout->addWidget(copyRightLabel, 0, 1, 4, 4);
layout->addWidget(buttonBox, 4, 0, 1, 5);