OSDN Git Service

Merge branch 'master' of scm.dev.nokia.troll.no:creator/mainline
[qt-creator-jp/qt-creator-jp.git] / src / plugins / coreplugin / editormanager / editormanager.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** Commercial Usage
10 **
11 ** Licensees holding valid Qt Commercial licenses may use this file in
12 ** accordance with the Qt Commercial License Agreement provided with the
13 ** Software or, alternatively, in accordance with the terms contained in
14 ** a written agreement between you and Nokia.
15 **
16 ** GNU Lesser General Public License Usage
17 **
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** If you are unsure which license is appropriate for your use, please
26 ** contact the sales department at http://qt.nokia.com/contact.
27 **
28 **************************************************************************/
29
30 #include "editormanager.h"
31 #include "editorview.h"
32 #include "openeditorswindow.h"
33 #include "openeditorsview.h"
34 #include "openeditorsmodel.h"
35 #include "openwithdialog.h"
36 #include "filemanager.h"
37 #include "icore.h"
38 #include "ieditor.h"
39 #include "iversioncontrol.h"
40 #include "mimedatabase.h"
41 #include "tabpositionindicator.h"
42 #include "vcsmanager.h"
43
44 #include <coreplugin/editortoolbar.h>
45 #include <coreplugin/coreconstants.h>
46 #include <coreplugin/modemanager.h>
47 #include <coreplugin/actionmanager/actionmanager.h>
48 #include <coreplugin/actionmanager/actioncontainer.h>
49 #include <coreplugin/actionmanager/command.h>
50 #include <coreplugin/editormanager/ieditorfactory.h>
51 #include <coreplugin/editormanager/iexternaleditor.h>
52 #include <coreplugin/icorelistener.h>
53 #include <coreplugin/imode.h>
54 #include <coreplugin/settingsdatabase.h>
55 #include <coreplugin/variablemanager.h>
56 #include <coreplugin/uniqueidmanager.h>
57
58 #include <extensionsystem/pluginmanager.h>
59
60 #include <utils/consoleprocess.h>
61 #include <utils/qtcassert.h>
62
63 #include <QtCore/QDebug>
64 #include <QtCore/QFileInfo>
65 #include <QtCore/QMap>
66 #include <QtCore/QProcess>
67 #include <QtCore/QSet>
68 #include <QtCore/QSettings>
69 #include <QtCore/QTextCodec>
70
71 #include <QtGui/QAction>
72 #include <QtGui/QShortcut>
73 #include <QtGui/QApplication>
74 #include <QtGui/QFileDialog>
75 #include <QtGui/QLayout>
76 #include <QtGui/QMainWindow>
77 #include <QtGui/QMenu>
78 #include <QtGui/QMessageBox>
79 #include <QtGui/QPushButton>
80 #include <QtGui/QSplitter>
81 #include <QtGui/QStackedLayout>
82
83 #include <algorithm>
84
85 Q_DECLARE_METATYPE(Core::IEditor*)
86
87 enum { debugEditorManager=0 };
88
89 static inline ExtensionSystem::PluginManager *pluginManager()
90 {
91     return ExtensionSystem::PluginManager::instance();
92 }
93
94 //===================EditorClosingCoreListener======================
95
96 namespace Core {
97 namespace Internal {
98
99 class EditorClosingCoreListener : public ICoreListener
100 {
101 public:
102     EditorClosingCoreListener(EditorManager *em);
103     bool editorAboutToClose(IEditor *editor);
104     bool coreAboutToClose();
105
106 private:
107     EditorManager *m_em;
108 };
109
110 EditorClosingCoreListener::EditorClosingCoreListener(EditorManager *em)
111         : m_em(em)
112 {
113 }
114
115 bool EditorClosingCoreListener::editorAboutToClose(IEditor *)
116 {
117     return true;
118 }
119
120 bool EditorClosingCoreListener::coreAboutToClose()
121 {
122     // Do not ask for files to save.
123     // MainWindow::closeEvent has already done that.
124     return m_em->closeAllEditors(false);
125 }
126
127 } // namespace Internal
128 } // namespace Core
129
130 using namespace Core;
131 using namespace Core::Internal;
132 using namespace Utils;
133
134 //===================EditorManager=====================
135
136 EditorManagerPlaceHolder *EditorManagerPlaceHolder::m_current = 0;
137
138 EditorManagerPlaceHolder::EditorManagerPlaceHolder(Core::IMode *mode, QWidget *parent)
139     : QWidget(parent), m_mode(mode)
140 {
141     setLayout(new QVBoxLayout);
142     layout()->setMargin(0);
143     connect(Core::ModeManager::instance(), SIGNAL(currentModeChanged(Core::IMode *)),
144             this, SLOT(currentModeChanged(Core::IMode *)));
145
146     currentModeChanged(Core::ModeManager::instance()->currentMode());
147 }
148
149 EditorManagerPlaceHolder::~EditorManagerPlaceHolder()
150 {
151     if (m_current == this) {
152         EditorManager::instance()->setParent(0);
153         EditorManager::instance()->hide();
154     }
155 }
156
157 void EditorManagerPlaceHolder::currentModeChanged(Core::IMode *mode)
158 {
159     if (m_current == this) {
160         m_current = 0;
161         EditorManager::instance()->setParent(0);
162         EditorManager::instance()->hide();
163     }
164     if (m_mode == mode) {
165         m_current = this;
166         layout()->addWidget(EditorManager::instance());
167         EditorManager::instance()->show();
168     }
169 }
170
171 EditorManagerPlaceHolder* EditorManagerPlaceHolder::current()
172 {
173     return m_current;
174 }
175
176 // ---------------- EditorManager
177
178 namespace Core {
179
180
181 struct EditorManagerPrivate {
182     explicit EditorManagerPrivate(ICore *core, QWidget *parent);
183     ~EditorManagerPrivate();
184     Internal::EditorView *m_view;
185     Internal::SplitterOrView *m_splitter;
186     QPointer<IEditor> m_currentEditor;
187     QPointer<SplitterOrView> m_currentView;
188
189     ICore *m_core;
190
191
192     // actions
193     QAction *m_revertToSavedAction;
194     QAction *m_saveAction;
195     QAction *m_saveAsAction;
196     QAction *m_closeCurrentEditorAction;
197     QAction *m_closeAllEditorsAction;
198     QAction *m_closeOtherEditorsAction;
199     QAction *m_gotoNextDocHistoryAction;
200     QAction *m_gotoPreviousDocHistoryAction;
201     QAction *m_goBackAction;
202     QAction *m_goForwardAction;
203     QAction *m_openInExternalEditorAction;
204     QAction *m_splitAction;
205     QAction *m_splitSideBySideAction;
206     QAction *m_removeCurrentSplitAction;
207     QAction *m_removeAllSplitsAction;
208     QAction *m_gotoOtherSplitAction;
209
210     Internal::OpenEditorsWindow *m_windowPopup;
211     Internal::EditorClosingCoreListener *m_coreListener;
212
213     QMap<QString, QVariant> m_editorStates;
214     Internal::OpenEditorsViewFactory *m_openEditorsFactory;
215
216     OpenEditorsModel *m_editorModel;
217     QString m_externalEditor;
218
219     IFile::ReloadSetting m_reloadSetting;
220 };
221 }
222
223 EditorManagerPrivate::EditorManagerPrivate(ICore *core, QWidget *parent) :
224     m_view(0),
225     m_splitter(0),
226     m_core(core),
227     m_revertToSavedAction(new QAction(EditorManager::tr("Revert to Saved"), parent)),
228     m_saveAction(new QAction(parent)),
229     m_saveAsAction(new QAction(parent)),
230     m_closeCurrentEditorAction(new QAction(EditorManager::tr("Close"), parent)),
231     m_closeAllEditorsAction(new QAction(EditorManager::tr("Close All"), parent)),
232     m_closeOtherEditorsAction(new QAction(EditorManager::tr("Close Others"), parent)),
233     m_gotoNextDocHistoryAction(new QAction(EditorManager::tr("Next Open Document in History"), parent)),
234     m_gotoPreviousDocHistoryAction(new QAction(EditorManager::tr("Previous Open Document in History"), parent)),
235     m_goBackAction(new QAction(QIcon(QLatin1String(Constants::ICON_PREV)), EditorManager::tr("Go Back"), parent)),
236     m_goForwardAction(new QAction(QIcon(QLatin1String(Constants::ICON_NEXT)), EditorManager::tr("Go Forward"), parent)),
237     m_openInExternalEditorAction(new QAction(EditorManager::tr("Open in External Editor"), parent)),
238     m_windowPopup(0),
239     m_coreListener(0),
240     m_reloadSetting(IFile::AlwaysAsk)
241 {
242     m_editorModel = new OpenEditorsModel(parent);
243 }
244
245 EditorManagerPrivate::~EditorManagerPrivate()
246 {
247 //    clearNavigationHistory();
248 }
249
250 EditorManager *EditorManager::m_instance = 0;
251
252 static Command *createSeparator(ActionManager *am, QObject *parent,
253                                 const QString &name,
254                                 const Context &context)
255 {
256     QAction *tmpaction = new QAction(parent);
257     tmpaction->setSeparator(true);
258     Command *cmd = am->registerAction(tmpaction, name, context);
259     return cmd;
260 }
261
262 EditorManager::EditorManager(ICore *core, QWidget *parent) :
263     QWidget(parent),
264     m_d(new EditorManagerPrivate(core, parent))
265 {
266     m_instance = this;
267
268     connect(m_d->m_core, SIGNAL(contextAboutToChange(Core::IContext *)),
269             this, SLOT(handleContextChange(Core::IContext *)));
270
271     const Context editManagerContext(Constants::C_EDITORMANAGER);
272     // combined context for edit & design modes
273     const Context editDesignContext(Constants::C_EDITORMANAGER, Constants::C_DESIGN_MODE);
274
275     ActionManager *am = m_d->m_core->actionManager();
276     ActionContainer *mfile = am->actionContainer(Constants::M_FILE);
277
278     // Revert to saved
279     m_d->m_revertToSavedAction->setIcon(QIcon::fromTheme(QLatin1String("document-revert")));
280     Command *cmd = am->registerAction(m_d->m_revertToSavedAction,
281                                        Constants::REVERTTOSAVED, editManagerContext);
282     cmd->setAttribute(Command::CA_UpdateText);
283     cmd->setDefaultText(tr("Revert File to Saved"));
284     mfile->addAction(cmd, Constants::G_FILE_SAVE);
285     connect(m_d->m_revertToSavedAction, SIGNAL(triggered()), this, SLOT(revertToSaved()));
286
287     // Save Action
288     am->registerAction(m_d->m_saveAction, Constants::SAVE, editManagerContext);
289     connect(m_d->m_saveAction, SIGNAL(triggered()), this, SLOT(saveFile()));
290
291     // Save As Action
292     am->registerAction(m_d->m_saveAsAction, Constants::SAVEAS, editManagerContext);
293     connect(m_d->m_saveAsAction, SIGNAL(triggered()), this, SLOT(saveFileAs()));
294
295     // Window Menu
296     ActionContainer *mwindow = am->actionContainer(Constants::M_WINDOW);
297
298     // Window menu separators
299     QAction *tmpaction = new QAction(this);
300     tmpaction->setSeparator(true);
301     cmd = am->registerAction(tmpaction, "QtCreator.Window.Sep.Split", editManagerContext);
302     mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
303
304     tmpaction = new QAction(this);
305     tmpaction->setSeparator(true);
306     cmd = am->registerAction(tmpaction, "QtCreator.Window.Sep.Navigate", editManagerContext);
307     mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
308
309     // Close Action
310     cmd = am->registerAction(m_d->m_closeCurrentEditorAction, Constants::CLOSE, editManagerContext);
311     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+W")));
312     cmd->setAttribute(Core::Command::CA_UpdateText);
313     cmd->setDefaultText(m_d->m_closeCurrentEditorAction->text());
314     mfile->addAction(cmd, Constants::G_FILE_CLOSE);
315     connect(m_d->m_closeCurrentEditorAction, SIGNAL(triggered()), this, SLOT(closeEditor()));
316
317 #ifdef Q_WS_WIN
318     // workaround for QTCREATORBUG-72
319     QShortcut *sc = new QShortcut(parent);
320     cmd = am->registerShortcut(sc, Constants::CLOSE_ALTERNATIVE, editManagerContext);
321     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+F4")));
322     cmd->setDefaultText(EditorManager::tr("Close"));
323     connect(sc, SIGNAL(activated()), this, SLOT(closeEditor()));
324 #endif
325
326     // Close All Action
327     cmd = am->registerAction(m_d->m_closeAllEditorsAction, Constants::CLOSEALL, editManagerContext);
328     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+W")));
329     mfile->addAction(cmd, Constants::G_FILE_CLOSE);
330     connect(m_d->m_closeAllEditorsAction, SIGNAL(triggered()), this, SLOT(closeAllEditors()));
331
332     // Close All Others Action
333     cmd = am->registerAction(m_d->m_closeOtherEditorsAction, Constants::CLOSEOTHERS, editManagerContext);
334     mfile->addAction(cmd, Constants::G_FILE_CLOSE);
335     cmd->setAttribute(Core::Command::CA_UpdateText);
336     connect(m_d->m_closeOtherEditorsAction, SIGNAL(triggered()), this, SLOT(closeOtherEditors()));
337
338     // Goto Previous In History Action
339     cmd = am->registerAction(m_d->m_gotoPreviousDocHistoryAction, Constants::GOTOPREVINHISTORY, editDesignContext);
340 #ifdef Q_WS_MAC
341     cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Tab")));
342 #else
343     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Tab")));
344 #endif
345     mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
346     connect(m_d->m_gotoPreviousDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoPreviousDocHistory()));
347
348     // Goto Next In History Action
349     cmd = am->registerAction(m_d->m_gotoNextDocHistoryAction, Constants::GOTONEXTINHISTORY, editDesignContext);
350 #ifdef Q_WS_MAC
351     cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Shift+Tab")));
352 #else
353     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Shift+Tab")));
354 #endif
355     mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
356     connect(m_d->m_gotoNextDocHistoryAction, SIGNAL(triggered()), this, SLOT(gotoNextDocHistory()));
357
358     // Go back in navigation history
359     cmd = am->registerAction(m_d->m_goBackAction, Constants::GO_BACK, editDesignContext);
360 #ifdef Q_WS_MAC
361     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Left")));
362 #else
363     cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Left")));
364 #endif
365     mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
366     connect(m_d->m_goBackAction, SIGNAL(triggered()), this, SLOT(goBackInNavigationHistory()));
367
368     // Go forward in navigation history
369     cmd = am->registerAction(m_d->m_goForwardAction, Constants::GO_FORWARD, editDesignContext);
370 #ifdef Q_WS_MAC
371     cmd->setDefaultKeySequence(QKeySequence(tr("Ctrl+Alt+Right")));
372 #else
373     cmd->setDefaultKeySequence(QKeySequence(tr("Alt+Right")));
374 #endif
375     mwindow->addAction(cmd, Constants::G_WINDOW_NAVIGATE);
376     connect(m_d->m_goForwardAction, SIGNAL(triggered()), this, SLOT(goForwardInNavigationHistory()));
377
378 #ifdef Q_WS_MAC
379     QString prefix = tr("Meta+E");
380 #else
381     QString prefix = tr("Ctrl+E");
382 #endif
383
384     m_d->m_splitAction = new QAction(tr("Split"), this);
385     cmd = am->registerAction(m_d->m_splitAction, Constants::SPLIT, editManagerContext);
386     cmd->setDefaultKeySequence(QKeySequence(tr("%1,2").arg(prefix)));
387     mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
388     connect(m_d->m_splitAction, SIGNAL(triggered()), this, SLOT(split()));
389
390     m_d->m_splitSideBySideAction = new QAction(tr("Split Side by Side"), this);
391     cmd = am->registerAction(m_d->m_splitSideBySideAction, Constants::SPLIT_SIDE_BY_SIDE, editManagerContext);
392     cmd->setDefaultKeySequence(QKeySequence(tr("%1,3").arg(prefix)));
393     mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
394     connect(m_d->m_splitSideBySideAction, SIGNAL(triggered()), this, SLOT(splitSideBySide()));
395
396     m_d->m_removeCurrentSplitAction = new QAction(tr("Remove Current Split"), this);
397     cmd = am->registerAction(m_d->m_removeCurrentSplitAction, Constants::REMOVE_CURRENT_SPLIT, editManagerContext);
398     cmd->setDefaultKeySequence(QKeySequence(tr("%1,0").arg(prefix)));
399     mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
400     connect(m_d->m_removeCurrentSplitAction, SIGNAL(triggered()), this, SLOT(removeCurrentSplit()));
401
402     m_d->m_removeAllSplitsAction = new QAction(tr("Remove All Splits"), this);
403     cmd = am->registerAction(m_d->m_removeAllSplitsAction, Constants::REMOVE_ALL_SPLITS, editManagerContext);
404     cmd->setDefaultKeySequence(QKeySequence(tr("%1,1").arg(prefix)));
405     mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
406     connect(m_d->m_removeAllSplitsAction, SIGNAL(triggered()), this, SLOT(removeAllSplits()));
407
408     m_d->m_gotoOtherSplitAction = new QAction(tr("Go to Next Split"), this);
409     cmd = am->registerAction(m_d->m_gotoOtherSplitAction, Constants::GOTO_OTHER_SPLIT, editManagerContext);
410     cmd->setDefaultKeySequence(QKeySequence(tr("%1,o").arg(prefix)));
411     mwindow->addAction(cmd, Constants::G_WINDOW_SPLIT);
412     connect(m_d->m_gotoOtherSplitAction, SIGNAL(triggered()), this, SLOT(gotoOtherSplit()));
413
414     ActionContainer *medit = am->actionContainer(Constants::M_EDIT);
415     ActionContainer *advancedMenu = am->createMenu(Constants::M_EDIT_ADVANCED);
416     medit->addMenu(advancedMenu, Constants::G_EDIT_ADVANCED);
417     advancedMenu->menu()->setTitle(tr("&Advanced"));
418     advancedMenu->appendGroup(Constants::G_EDIT_FORMAT);
419     advancedMenu->appendGroup(Constants::G_EDIT_COLLAPSING);
420     advancedMenu->appendGroup(Constants::G_EDIT_BLOCKS);
421     advancedMenu->appendGroup(Constants::G_EDIT_FONT);
422     advancedMenu->appendGroup(Constants::G_EDIT_EDITOR);
423
424     // Advanced menu separators
425     cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Collapsing"), editManagerContext);
426     advancedMenu->addAction(cmd, Constants::G_EDIT_COLLAPSING);
427     cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Blocks"), editManagerContext);
428     advancedMenu->addAction(cmd, Constants::G_EDIT_BLOCKS);
429     cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Font"), editManagerContext);
430     advancedMenu->addAction(cmd, Constants::G_EDIT_FONT);
431     cmd = createSeparator(am, this, QLatin1String("QtCreator.Edit.Sep.Editor"), editManagerContext);
432     advancedMenu->addAction(cmd, Constants::G_EDIT_EDITOR);
433
434     cmd = am->registerAction(m_d->m_openInExternalEditorAction, Constants::OPEN_IN_EXTERNAL_EDITOR, editManagerContext);
435     cmd->setDefaultKeySequence(QKeySequence(tr("Alt+V,Alt+I")));
436     advancedMenu->addAction(cmd, Constants::G_EDIT_EDITOR);
437     connect(m_d->m_openInExternalEditorAction, SIGNAL(triggered()), this, SLOT(openInExternalEditor()));
438
439     // Connect to VariableManager for CURRENT_DOCUMENT variable setting
440     VariableManager::initEditorManagerConnections();
441     // other setup
442     m_d->m_splitter = new SplitterOrView(m_d->m_editorModel);
443     m_d->m_view = m_d->m_splitter->view();
444
445
446     QHBoxLayout *layout = new QHBoxLayout(this);
447     layout->setMargin(0);
448     layout->setSpacing(0);
449     layout->addWidget(m_d->m_splitter);
450
451     updateActions();
452
453     m_d->m_windowPopup = new OpenEditorsWindow(this);
454 }
455
456 EditorManager::~EditorManager()
457 {
458     if (m_d->m_core) {
459         ExtensionSystem::PluginManager *pm = ExtensionSystem::PluginManager::instance();
460         if (m_d->m_coreListener) {
461             pm->removeObject(m_d->m_coreListener);
462             delete m_d->m_coreListener;
463         }
464         pm->removeObject(m_d->m_openEditorsFactory);
465         delete m_d->m_openEditorsFactory;
466     }
467     delete m_d;
468 }
469
470 void EditorManager::init()
471 {
472     m_d->m_coreListener = new EditorClosingCoreListener(this);
473     pluginManager()->addObject(m_d->m_coreListener);
474
475     m_d->m_openEditorsFactory = new OpenEditorsViewFactory();
476     pluginManager()->addObject(m_d->m_openEditorsFactory);
477 }
478
479
480 EditorToolBar *EditorManager::createToolBar(QWidget *parent)
481 {
482     return new EditorToolBar(parent);
483 }
484
485 QString EditorManager::defaultExternalEditor() const
486 {
487 #ifdef Q_OS_UNIX
488     return ConsoleProcess::defaultTerminalEmulator() + QLatin1String(
489 # ifdef Q_OS_MAC
490             " -async"
491 # endif
492             " -geom %Wx%H+%x+%y -e vi %f +%l +\"normal %c|\"");
493 #else
494     return QLatin1String("notepad %f");
495 #endif
496 }
497
498 void EditorManager::removeEditor(IEditor *editor)
499 {
500     bool isDuplicate = m_d->m_editorModel->isDuplicate(editor);
501     m_d->m_editorModel->removeEditor(editor);
502     if (!isDuplicate) {
503         m_d->m_core->fileManager()->removeFile(editor->file());
504     }
505     m_d->m_core->removeContextObject(editor);
506 }
507
508 void EditorManager::handleContextChange(Core::IContext *context)
509 {
510     if (debugEditorManager)
511         qDebug() << Q_FUNC_INFO;
512     IEditor *editor = context ? qobject_cast<IEditor*>(context) : 0;
513     if (editor) {
514         setCurrentEditor(editor);
515     } else {
516         updateActions();
517     }
518 }
519
520 void EditorManager::setCurrentEditor(IEditor *editor, bool ignoreNavigationHistory)
521 {
522     if (editor)
523         setCurrentView(0);
524
525     if (m_d->m_currentEditor == editor)
526         return;
527     if (m_d->m_currentEditor && !ignoreNavigationHistory)
528         addCurrentPositionToNavigationHistory();
529
530     m_d->m_currentEditor = editor;
531     if (editor) {
532         if (SplitterOrView *splitterOrView = m_d->m_splitter->findView(editor))
533             splitterOrView->view()->setCurrentEditor(editor);
534         m_d->m_view->updateEditorHistory(editor); // the global view should have a complete history
535     }
536     updateActions();
537     emit currentEditorChanged(editor);
538 }
539
540
541 void EditorManager::setCurrentView(Core::Internal::SplitterOrView *view)
542 {
543     if (view == m_d->m_currentView)
544         return;
545
546     SplitterOrView *old = m_d->m_currentView;
547     m_d->m_currentView = view;
548
549     if (old)
550         old->update();
551     if (view)
552         view->update();
553
554     if (view && !view->editor())
555         view->setFocus();
556 }
557
558 Core::Internal::SplitterOrView *EditorManager::currentSplitterOrView() const
559 {
560     SplitterOrView *view = m_d->m_currentView;
561     if (!view)
562         view = m_d->m_currentEditor?
563                m_d->m_splitter->findView(m_d->m_currentEditor):
564                m_d->m_splitter->findFirstView();
565     if (!view)
566         return m_d->m_splitter;
567     return view;
568 }
569
570 Core::Internal::EditorView *EditorManager::currentEditorView() const
571 {
572     return currentSplitterOrView()->view();
573 }
574
575 QList<IEditor *> EditorManager::editorsForFileName(const QString &filename) const
576 {
577     QList<IEditor *> found;
578     QString fixedname = FileManager::fixFileName(filename);
579     foreach (IEditor *editor, openedEditors()) {
580         if (fixedname == FileManager::fixFileName(editor->file()->fileName()))
581             found << editor;
582     }
583     return found;
584 }
585
586 QList<IEditor *> EditorManager::editorsForFile(IFile *file) const
587 {
588     QList<IEditor *> found;
589     foreach (IEditor *editor, openedEditors()) {
590         if (editor->file() == file)
591             found << editor;
592     }
593     return found;
594 }
595
596 IEditor *EditorManager::currentEditor() const
597 {
598     return m_d->m_currentEditor;
599 }
600
601 void EditorManager::emptyView(Core::Internal::EditorView *view)
602 {
603     if (!view)
604         return;
605
606     QList<IEditor *> editors = view->editors();
607     foreach (IEditor *editor, editors) {
608         if (!m_d->m_editorModel->isDuplicate(editor)) {
609             editors.removeAll(editor);
610             view->removeEditor(editor);
611             continue;
612         }
613         emit editorAboutToClose(editor);
614         removeEditor(editor);
615         view->removeEditor(editor);
616     }
617     emit editorsClosed(editors);
618     foreach (IEditor *editor, editors) {
619         delete editor;
620     }
621 }
622
623 void EditorManager::closeView(Core::Internal::EditorView *view)
624 {
625     if (!view)
626         return;
627
628     if (view == m_d->m_view) {
629         if (IEditor *e = view->currentEditor())
630             closeEditors(QList<IEditor *>() << e);
631         return;
632     }
633
634     if (IEditor *e = view->currentEditor()) {
635         /*
636            when we are closing a view with an original editor which has
637            duplicates, then make one of the duplicates the original.
638            Otherwise the original would be kept around and the user might
639            experience jumping to a missleading position within the file when
640            visiting the file again. With the code below, the position within
641            the file will be the position of the first duplicate which is still
642            around.
643         */
644         if (!m_d->m_editorModel->isDuplicate(e)) {
645             QList<IEditor *> duplicates = m_d->m_editorModel->duplicatesFor(e);
646             if (!duplicates.isEmpty()) {
647                 m_d->m_editorModel->makeOriginal(duplicates.first());
648             }
649         }
650     }
651
652     emptyView(view);
653
654     SplitterOrView *splitterOrView = m_d->m_splitter->findView(view);
655     Q_ASSERT(splitterOrView);
656     Q_ASSERT(splitterOrView->view() == view);
657     SplitterOrView *splitter = m_d->m_splitter->findSplitter(splitterOrView);
658     Q_ASSERT(splitterOrView->hasEditors() == false);
659     splitterOrView->hide();
660     delete splitterOrView;
661
662     splitter->unsplit();
663
664     SplitterOrView *newCurrent = splitter->findFirstView();
665     if (newCurrent) {
666         if (IEditor *e = newCurrent->editor()) {
667             activateEditor(newCurrent->view(), e);
668         } else {
669             setCurrentView(newCurrent);
670         }
671     }
672 }
673
674 QList<IEditor*>
675     EditorManager::editorsForFiles(QList<IFile*> files) const
676 {
677     const QList<IEditor *> editors = openedEditors();
678     QSet<IEditor *> found;
679     foreach (IFile *file, files) {
680         foreach (IEditor *editor, editors) {
681             if (editor->file() == file && !found.contains(editor)) {
682                     found << editor;
683             }
684         }
685     }
686     return found.toList();
687 }
688
689 QList<IFile *> EditorManager::filesForEditors(QList<IEditor *> editors) const
690 {
691     QSet<IEditor *> handledEditors;
692     QList<IFile *> files;
693     foreach (IEditor *editor, editors) {
694         if (!handledEditors.contains(editor)) {
695             files << editor->file();
696             handledEditors.insert(editor);
697         }
698     }
699     return files;
700 }
701
702 bool EditorManager::closeAllEditors(bool askAboutModifiedEditors)
703 {
704     m_d->m_editorModel->removeAllRestoredEditors();
705     if (closeEditors(openedEditors(), askAboutModifiedEditors)) {
706 //        m_d->clearNavigationHistory();
707         return true;
708     }
709     return false;
710 }
711
712 void EditorManager::closeOtherEditors(IEditor *editor)
713 {
714     m_d->m_editorModel->removeAllRestoredEditors();
715     QList<IEditor*> editors = openedEditors();
716     editors.removeAll(editor);
717     closeEditors(editors, true);
718 }
719
720 void EditorManager::closeOtherEditors()
721 {
722     IEditor *current = currentEditor();
723     QTC_ASSERT(current, return);
724     closeOtherEditors(current);
725 }
726
727 // SLOT connected to action
728 void EditorManager::closeEditor()
729 {
730     if (!m_d->m_currentEditor)
731         return;
732     addCurrentPositionToNavigationHistory();
733     closeEditor(m_d->m_currentEditor);
734 }
735
736 void EditorManager::closeEditor(Core::IEditor *editor)
737 {
738     if (!editor)
739         return;
740     closeEditors(QList<IEditor *>() << editor);
741 }
742
743 void EditorManager::closeEditor(const QModelIndex &index)
744 {
745     IEditor *editor = index.data(Qt::UserRole).value<Core::IEditor*>();
746     if (editor)
747         closeEditor(editor);
748     else
749         m_d->m_editorModel->removeEditor(index);
750 }
751
752 bool EditorManager::closeEditors(const QList<IEditor*> &editorsToClose, bool askAboutModifiedEditors)
753 {
754     if (editorsToClose.isEmpty())
755         return true;
756
757     SplitterOrView *currentSplitterOrView = this->currentSplitterOrView();
758
759     bool closingFailed = false;
760     QList<IEditor*> acceptedEditors;
761     //ask all core listeners to check whether the editor can be closed
762     const QList<ICoreListener *> listeners =
763         pluginManager()->getObjects<ICoreListener>();
764     foreach (IEditor *editor, editorsToClose) {
765         bool editorAccepted = true;
766         if (m_d->m_editorModel->isDuplicate(editor))
767             editor = m_d->m_editorModel->originalForDuplicate(editor);
768         foreach (ICoreListener *listener, listeners) {
769             if (!listener->editorAboutToClose(editor)) {
770                 editorAccepted = false;
771                 closingFailed = false;
772                 break;
773             }
774         }
775         if (editorAccepted)
776             acceptedEditors.append(editor);
777     }
778     if (acceptedEditors.isEmpty())
779         return false;
780     //ask whether to save modified files
781     if (askAboutModifiedEditors) {
782         bool cancelled = false;
783         QList<IFile*> list = m_d->m_core->fileManager()->
784             saveModifiedFiles(filesForEditors(acceptedEditors), &cancelled);
785         if (cancelled)
786             return false;
787         if (!list.isEmpty()) {
788             closingFailed = true;
789             QSet<IEditor*> skipSet = editorsForFiles(list).toSet();
790             acceptedEditors = acceptedEditors.toSet().subtract(skipSet).toList();
791         }
792     }
793     if (acceptedEditors.isEmpty())
794         return false;
795
796     // add duplicates
797     foreach(IEditor *editor, acceptedEditors)
798         acceptedEditors += m_d->m_editorModel->duplicatesFor(editor);
799
800     QList<EditorView*> closedViews;
801
802     // remove the editors
803     foreach (IEditor *editor, acceptedEditors) {
804         emit editorAboutToClose(editor);
805         if (!editor->file()->fileName().isEmpty()) {
806             QByteArray state = editor->saveState();
807             if (!state.isEmpty())
808                 m_d->m_editorStates.insert(editor->file()->fileName(), QVariant(state));
809         }
810
811         removeEditor(editor);
812         if (SplitterOrView *view = m_d->m_splitter->findView(editor)) {
813             if (editor == view->view()->currentEditor())
814                 closedViews += view->view();
815             view->view()->removeEditor(editor);
816         }
817     }
818
819     foreach (EditorView *view, closedViews) {
820         IEditor *newCurrent = view->currentEditor();
821         if (!newCurrent)
822             newCurrent = pickUnusedEditor();
823         if (newCurrent) {
824             activateEditor(view, newCurrent, NoActivate);
825         } else {
826             QModelIndex idx = m_d->m_editorModel->firstRestoredEditor();
827             if (idx.isValid())
828                 activateEditor(idx, view, NoActivate);
829         }
830     }
831
832     emit editorsClosed(acceptedEditors);
833
834     foreach (IEditor *editor, acceptedEditors) {
835         delete editor;
836     }
837
838     if (currentSplitterOrView) {
839         if (IEditor *editor = currentSplitterOrView->editor())
840             activateEditor(currentSplitterOrView->view(), editor);
841     }
842
843     if (!currentEditor()) {
844         emit currentEditorChanged(0);
845         updateActions();
846     }
847
848     return !closingFailed;
849 }
850
851 void EditorManager::closeDuplicate(Core::IEditor *editor)
852 {
853
854     IEditor *original = editor;
855     if (m_d->m_editorModel->isDuplicate(editor))
856         original= m_d->m_editorModel->originalForDuplicate(editor);
857     QList<IEditor *> duplicates = m_d->m_editorModel->duplicatesFor(original);
858
859     if (duplicates.isEmpty()) {
860         closeEditor(editor);
861         return;
862     }
863
864     if (original== editor)
865         m_d->m_editorModel->makeOriginal(duplicates.first());
866
867     SplitterOrView *currentSplitterOrView = this->currentSplitterOrView();
868
869     emit editorAboutToClose(editor);
870
871     if(m_d->m_splitter->findView(editor)) {
872         EditorView *view = m_d->m_splitter->findView(editor)->view();
873         removeEditor(editor);
874         view->removeEditor(editor);
875
876         IEditor *newCurrent = view->currentEditor();
877         if (!newCurrent)
878             newCurrent = pickUnusedEditor();
879         if (newCurrent) {
880             activateEditor(view, newCurrent, NoActivate);
881         } else {
882             QModelIndex idx = m_d->m_editorModel->firstRestoredEditor();
883             if (idx.isValid())
884                 activateEditor(idx, view, NoActivate);
885         }
886     }
887
888     emit editorsClosed(QList<IEditor*>() << editor);
889     delete editor;
890     if (currentSplitterOrView) {
891         if (IEditor *currentEditor = currentSplitterOrView->editor())
892             activateEditor(currentSplitterOrView->view(), currentEditor);
893     }
894 }
895
896 Core::IEditor *EditorManager::pickUnusedEditor() const
897 {
898     foreach (IEditor *editor, openedEditors()) {
899         SplitterOrView *view = m_d->m_splitter->findView(editor);
900         if (!view || view->editor() != editor)
901             return editor;
902     }
903     return 0;
904 }
905
906 Core::IEditor *EditorManager::activateEditor(const QModelIndex &index, Internal::EditorView *view, OpenEditorFlags flags)
907 {
908     IEditor *editor = index.data(Qt::UserRole).value<IEditor*>();
909     if (editor)  {
910         return activateEditor(view, editor, flags);
911     }
912
913     QString fileName = index.data(Qt::UserRole + 1).toString();
914     QString id = index.data(Qt::UserRole + 2).toString();
915     return openEditor(view, fileName, id, flags);
916 }
917
918 Core::IEditor *EditorManager::placeEditor(Core::Internal::EditorView *view, Core::IEditor *editor)
919 {
920     Q_ASSERT(view && editor);
921
922     if (view->currentEditor() && view->currentEditor()->file() == editor->file())
923         editor = view->currentEditor();
924
925     if (!view->hasEditor(editor)) {
926         bool duplicateSupported = editor->duplicateSupported();
927         if (SplitterOrView *sourceView = m_d->m_splitter->findView(editor)) {
928             if (editor != sourceView->editor() || !duplicateSupported) {
929                 sourceView->view()->removeEditor(editor);
930                 view->addEditor(editor);
931                 view->setCurrentEditor(editor);
932                 if (!sourceView->editor()) {
933                     if (IEditor *replacement = pickUnusedEditor()) {
934                         sourceView->view()->addEditor(replacement);
935                     }
936                 }
937                 return editor;
938             } else if (duplicateSupported) {
939                 editor = duplicateEditor(editor);
940                 Q_ASSERT(editor);
941                 m_d->m_editorModel->makeOriginal(editor);
942             }
943         }
944         view->addEditor(editor);
945     }
946     return editor;
947 }
948
949 Core::IEditor *EditorManager::activateEditor(Core::IEditor *editor, OpenEditorFlags flags)
950 {
951     return activateEditor(0, editor, flags);
952 }
953
954 Core::IEditor *EditorManager::activateEditor(Core::Internal::EditorView *view, Core::IEditor *editor, OpenEditorFlags flags)
955 {
956     if (!view)
957         view = currentEditorView();
958
959     Q_ASSERT(view);
960
961     if (!editor) {
962         if (!m_d->m_currentEditor)
963             setCurrentEditor(0, (flags & IgnoreNavigationHistory));
964         return 0;
965     }
966
967     editor = placeEditor(view, editor);
968
969     if (!(flags & NoActivate)) {
970         setCurrentEditor(editor, (flags & IgnoreNavigationHistory));
971         if (flags & ModeSwitch) {
972             switchToPreferedMode();
973         }
974         if (isVisible())
975             editor->widget()->setFocus();
976     }
977     return editor;
978 }
979
980 Core::IEditor *EditorManager::activateEditor(Core::Internal::EditorView *view, Core::IFile *file, OpenEditorFlags flags)
981 {
982     const QList<IEditor*> editors = editorsForFile(file);
983     if (editors.isEmpty())
984         return 0;
985
986     return activateEditor(view, editors.first(), flags);
987 }
988
989 /* For something that has a 'QStringList mimeTypes' (IEditorFactory
990  * or IExternalEditor), find the one best matching the mimetype passed in.
991  *  Recurse over the parent classes of the mimetype to find them. */
992 template <class EditorFactoryLike>
993 static void mimeTypeFactoryRecursion(const MimeDatabase *db,
994                                      const MimeType &mimeType,
995                                      const QList<EditorFactoryLike*> &allFactories,
996                                      bool firstMatchOnly,
997                                      QList<EditorFactoryLike*> *list)
998 {
999     typedef typename QList<EditorFactoryLike*>::const_iterator EditorFactoryLikeListConstIterator;
1000     // Loop factories to find type
1001     const QString type = mimeType.type();
1002     const EditorFactoryLikeListConstIterator fcend = allFactories.constEnd();
1003     for (EditorFactoryLikeListConstIterator fit = allFactories.constBegin(); fit != fcend; ++fit) {
1004         // Exclude duplicates when recursing over xml or C++ -> C -> text.
1005         EditorFactoryLike *factory = *fit;
1006         if (!list->contains(factory) && factory->mimeTypes().contains(type)) {
1007             list->push_back(*fit);
1008             if (firstMatchOnly)
1009                 return;
1010             break;
1011         }
1012     }
1013     // Any parent mime type classes? -> recurse
1014     QStringList parentTypes = mimeType.subClassesOf();
1015     if (parentTypes.empty())
1016         return;
1017     const QStringList::const_iterator pcend = parentTypes .constEnd();
1018     for (QStringList::const_iterator pit = parentTypes .constBegin(); pit != pcend; ++pit) {
1019         if (const MimeType parent = db->findByType(*pit))
1020             mimeTypeFactoryRecursion(db, parent, allFactories, firstMatchOnly, list);
1021     }
1022 }
1023
1024 EditorManager::EditorFactoryList
1025     EditorManager::editorFactories(const MimeType &mimeType, bool bestMatchOnly) const
1026 {
1027     EditorFactoryList rc;
1028     const EditorFactoryList allFactories = pluginManager()->getObjects<IEditorFactory>();
1029     mimeTypeFactoryRecursion(m_d->m_core->mimeDatabase(), mimeType, allFactories, bestMatchOnly, &rc);
1030     if (debugEditorManager)
1031         qDebug() << Q_FUNC_INFO << mimeType.type() << " returns " << rc;
1032     return rc;
1033 }
1034
1035 EditorManager::ExternalEditorList
1036         EditorManager::externalEditors(const MimeType &mimeType, bool bestMatchOnly) const
1037 {
1038     ExternalEditorList rc;
1039     const ExternalEditorList allEditors = pluginManager()->getObjects<IExternalEditor>();
1040     mimeTypeFactoryRecursion(m_d->m_core->mimeDatabase(), mimeType, allEditors, bestMatchOnly, &rc);
1041     if (debugEditorManager)
1042         qDebug() << Q_FUNC_INFO << mimeType.type() << " returns " << rc;
1043     return rc;
1044 }
1045
1046 /* For something that has a 'QString id' (IEditorFactory
1047  * or IExternalEditor), find the one matching a id. */
1048 template <class EditorFactoryLike>
1049         inline EditorFactoryLike *findById(ExtensionSystem::PluginManager *pm,
1050                                              const QString &id)
1051 {
1052     const QList<EditorFactoryLike *> factories = pm->template getObjects<EditorFactoryLike>();
1053     foreach(EditorFactoryLike *efl, factories)
1054         if (id == efl->id())
1055             return efl;
1056     return 0;
1057 }
1058
1059 IEditor *EditorManager::createEditor(const QString &editorId,
1060                                      const QString &fileName)
1061 {
1062     if (debugEditorManager)
1063         qDebug() << Q_FUNC_INFO << editorId << fileName;
1064
1065     EditorFactoryList factories;
1066     if (editorId.isEmpty()) {
1067         const QFileInfo fileInfo(fileName);
1068         // Find by mime type
1069         MimeType mimeType = m_d->m_core->mimeDatabase()->findByFile(fileInfo);
1070         if (!mimeType) {
1071             qWarning("%s unable to determine mime type of %s/%s. Falling back to text/plain",
1072                      Q_FUNC_INFO, fileName.toUtf8().constData(), editorId.toUtf8().constData());
1073             mimeType = m_d->m_core->mimeDatabase()->findByType(QLatin1String("text/plain"));
1074         }
1075         // open text files > 48 MB in binary editor
1076         if (fileInfo.size() >  maxTextFileSize() && mimeType.type().startsWith(QLatin1String("text")))
1077             mimeType = m_d->m_core->mimeDatabase()->findByType(QLatin1String("application/octet-stream"));
1078         factories = editorFactories(mimeType, true);
1079     } else {
1080         // Find by editor id
1081         if (IEditorFactory *factory = findById<IEditorFactory>(pluginManager(), editorId))
1082             factories.push_back(factory);
1083     }
1084     if (factories.empty()) {
1085         qWarning("%s: unable to find an editor factory for the file '%s', editor Id '%s'.",
1086                  Q_FUNC_INFO, fileName.toUtf8().constData(), editorId.toUtf8().constData());
1087         return 0;
1088     }
1089
1090     IEditor *editor = factories.front()->createEditor(this);
1091     if (editor)
1092         connect(editor, SIGNAL(changed()), this, SLOT(updateActions()));
1093     if (editor)
1094         emit editorCreated(editor, fileName);
1095     return editor;
1096 }
1097
1098 void EditorManager::addEditor(IEditor *editor, bool isDuplicate)
1099 {
1100     if (!editor)
1101         return;
1102     m_d->m_core->addContextObject(editor);
1103
1104     m_d->m_editorModel->addEditor(editor, isDuplicate);
1105     if (!isDuplicate) {
1106         const bool isTemporary = editor->isTemporary();
1107         const bool addWatcher = !isTemporary;
1108         m_d->m_core->fileManager()->addFile(editor->file(), addWatcher);
1109         if (!isTemporary)
1110             m_d->m_core->fileManager()->addToRecentFiles(editor->file()->fileName());
1111     }
1112     emit editorOpened(editor);
1113 }
1114
1115 // Run the OpenWithDialog and return the editor id
1116 // selected by the user.
1117 QString EditorManager::getOpenWithEditorId(const QString &fileName,
1118                                            bool *isExternalEditor) const
1119 {
1120     // Collect editors that can open the file
1121     const MimeType mt = m_d->m_core->mimeDatabase()->findByFile(fileName);
1122     if (!mt)
1123         return QString();
1124     QStringList allEditorIds;
1125     QStringList externalEditorIds;
1126     // Built-in
1127     const EditorFactoryList editors = editorFactories(mt, false);
1128     const int size = editors.size();
1129     for (int i = 0; i < size; i++) {
1130         allEditorIds.push_back(editors.at(i)->id());
1131     }
1132     // External editors
1133     const ExternalEditorList exEditors = externalEditors(mt, false);
1134     const int esize = exEditors.size();
1135     for (int i = 0; i < esize; i++) {
1136         externalEditorIds.push_back(exEditors.at(i)->id());
1137         allEditorIds.push_back(exEditors.at(i)->id());
1138     }
1139     if (allEditorIds.empty())
1140         return QString();
1141     // Run dialog.
1142     OpenWithDialog dialog(fileName, m_d->m_core->mainWindow());
1143     dialog.setEditors(allEditorIds);
1144     dialog.setCurrentEditor(0);
1145     if (dialog.exec() != QDialog::Accepted)
1146         return QString();
1147     const QString selectedId = dialog.editor();
1148     if (isExternalEditor)
1149         *isExternalEditor = externalEditorIds.contains(selectedId);
1150     return selectedId;
1151 }
1152
1153 static QString formatFileFilters(const Core::ICore *core, QString *selectedFilter = 0)
1154 {
1155     if (selectedFilter)
1156         selectedFilter->clear();
1157
1158     // Compile list of filter strings, sort, and remove duplicates (different mime types might
1159     // generate the same filter).
1160     QStringList filters = core->mimeDatabase()->filterStrings();
1161     if (filters.empty())
1162         return QString();
1163     filters.sort();
1164     filters.erase(std::unique(filters.begin(), filters.end()), filters.end());
1165
1166     static const QString allFilesFilter =
1167         QCoreApplication::translate("Core", Constants::ALL_FILES_FILTER);
1168     if (selectedFilter)
1169         *selectedFilter = allFilesFilter;
1170
1171     // Prepend all files filter (instead of appending to work around a bug in Qt/Mac).
1172     filters.prepend(allFilesFilter);
1173
1174     return filters.join(QLatin1String(";;"));
1175 }
1176
1177 IEditor *EditorManager::openEditor(const QString &fileName, const QString &editorId,
1178                                    OpenEditorFlags flags, bool *newEditor)
1179 {
1180     return openEditor(0, fileName, editorId, flags, newEditor);
1181 }
1182
1183 int extractLineNumber(QString *fileName)
1184 {
1185     int i = fileName->length() - 1;
1186     for (; i >= 0; --i) {
1187         if (!fileName->at(i).isNumber())
1188             break;
1189     }
1190     if (i == -1)
1191         return -1;
1192     if (fileName->at(i) == ':' || fileName->at(i) == '+') {
1193         int result = fileName->mid(i+1).toInt();
1194         *fileName = fileName->left(i);
1195         return result;
1196     }
1197     return -1;
1198 }
1199
1200 IEditor *EditorManager::openEditor(Core::Internal::EditorView *view, const QString &fileName,
1201                         const QString &editorId, OpenEditorFlags flags, bool *newEditor)
1202 {
1203     if (debugEditorManager)
1204         qDebug() << Q_FUNC_INFO << fileName << editorId;
1205
1206     QString fn = fileName;
1207     int lineNumber = -1;
1208     if (flags && EditorManager::CanContainLineNumber)
1209         lineNumber = extractLineNumber(&fn);
1210
1211     if (fn.isEmpty())
1212         return 0;
1213
1214     if (newEditor)
1215         *newEditor = false;
1216
1217     const QList<IEditor *> editors = editorsForFileName(fn);
1218     if (!editors.isEmpty())
1219         return activateEditor(view, editors.first(), flags);
1220
1221     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1222     IEditor *editor = createEditor(editorId, fn);
1223     // If we could not open the file in the requested editor, fall
1224     // back to the default editor:
1225     if (!editor)
1226         editor = createEditor(QString(), fn);
1227     if (!editor || !editor->open(fn)) {
1228         QApplication::restoreOverrideCursor();
1229         QMessageBox::critical(m_d->m_core->mainWindow(), tr("Opening File"), tr("Cannot open file %1!").arg(QDir::toNativeSeparators(fn)));
1230         delete editor;
1231         editor = 0;
1232         return 0;
1233     }
1234     addEditor(editor);
1235
1236     if (newEditor)
1237         *newEditor = true;
1238
1239     IEditor *result = activateEditor(view, editor, flags);
1240     if (editor == result)
1241         restoreEditorState(editor);
1242
1243     if (flags && EditorManager::CanContainLineNumber)
1244         editor->gotoLine(lineNumber, -1);
1245
1246     QApplication::restoreOverrideCursor();
1247     return result;
1248 }
1249
1250 bool EditorManager::openExternalEditor(const QString &fileName, const QString &editorId)
1251 {
1252     IExternalEditor *ee = findById<IExternalEditor>(pluginManager(), editorId);
1253     if (!ee)
1254         return false;
1255     QString errorMessage;
1256     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1257     const bool ok = ee->startEditor(fileName, &errorMessage);
1258     QApplication::restoreOverrideCursor();
1259     if (!ok)
1260         QMessageBox::critical(m_d->m_core->mainWindow(), tr("Opening File"), errorMessage);
1261     return ok;
1262 }
1263
1264 QStringList EditorManager::getOpenFileNames() const
1265 {
1266     QString selectedFilter;
1267     const QString &fileFilters = formatFileFilters(m_d->m_core, &selectedFilter);
1268     return ICore::instance()->fileManager()->getOpenFileNames(fileFilters,
1269                                                               QString(), &selectedFilter);
1270 }
1271
1272
1273 /// Empty mode == figure out the correct mode from the editor
1274 /// forcePrefered = true, switch to the mode even if the editor is visible in another mode
1275 /// forcePrefered = false, only switch if it is not visible
1276 void EditorManager::switchToPreferedMode()
1277 {
1278     QString preferedMode;
1279     // Figure out prefered mode for editor
1280     if (m_d->m_currentEditor)
1281         preferedMode = m_d->m_currentEditor->preferredModeType();
1282
1283     if (preferedMode.isEmpty())
1284         preferedMode = Constants::MODE_EDIT_TYPE;
1285
1286     if (m_d->m_core->modeManager()->currentMode()->type() != preferedMode) {
1287         m_d->m_core->modeManager()->activateModeType(preferedMode);
1288     }
1289 }
1290
1291 IEditor *EditorManager::openEditorWithContents(const QString &editorId,
1292                                         QString *titlePattern,
1293                                         const QString &contents)
1294 {
1295     if (debugEditorManager)
1296         qDebug() << Q_FUNC_INFO << editorId << titlePattern << contents;
1297
1298     if (editorId.isEmpty())
1299         return 0;
1300
1301     QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
1302     IEditor *edt = createEditor(editorId);
1303     if (!edt) {
1304         QApplication::restoreOverrideCursor();
1305         return 0;
1306     }
1307
1308     if (!edt->createNew(contents)) {
1309         QApplication::restoreOverrideCursor();
1310         delete edt;
1311         edt = 0;
1312         return 0;
1313     }
1314
1315     QString title = edt->displayName();
1316
1317     if (titlePattern) {
1318         const QChar dollar = QLatin1Char('$');
1319         const QChar dot = QLatin1Char('.');
1320
1321         QString base = *titlePattern;
1322         if (base.isEmpty())
1323             base = QLatin1String("unnamed$");
1324         if (base.contains(dollar)) {
1325             int i = 1;
1326             QSet<QString> docnames;
1327             foreach (IEditor *editor, openedEditors()) {
1328                 QString name = editor->file()->fileName();
1329                 if (name.isEmpty()) {
1330                     name = editor->displayName();
1331                     name.remove(QLatin1Char('*'));
1332                 } else {
1333                     name = QFileInfo(name).completeBaseName();
1334                 }
1335                 docnames << name;
1336             }
1337
1338             do {
1339                 title = base;
1340                 title.replace(QString(dollar), QString::number(i++));
1341             } while (docnames.contains(title));
1342         } else {
1343             title = *titlePattern;
1344         }
1345         *titlePattern = title;
1346     }
1347     edt->setDisplayName(title);
1348     addEditor(edt);
1349     QApplication::restoreOverrideCursor();
1350     return edt;
1351 }
1352
1353 bool EditorManager::hasEditor(const QString &fileName) const
1354 {
1355     return !editorsForFileName(fileName).isEmpty();
1356 }
1357
1358 void EditorManager::restoreEditorState(IEditor *editor)
1359 {
1360     QTC_ASSERT(editor, return);
1361     QString fileName = editor->file()->fileName();
1362     editor->restoreState(m_d->m_editorStates.value(fileName).toByteArray());
1363 }
1364
1365 bool EditorManager::saveEditor(IEditor *editor)
1366 {
1367     return saveFile(editor);
1368 }
1369
1370 bool EditorManager::saveFile(IEditor *editor)
1371 {
1372     if (!editor)
1373         editor = currentEditor();
1374     if (!editor)
1375         return false;
1376
1377     IFile *file = editor->file();
1378     file->checkPermissions();
1379
1380     const QString &fileName = file->fileName();
1381
1382     if (fileName.isEmpty())
1383         return saveFileAs(editor);
1384
1385     bool success = false;
1386
1387     // try saving, no matter what isReadOnly tells us
1388     m_d->m_core->fileManager()->blockFileChange(file);
1389     success = file->save(fileName);
1390     m_d->m_core->fileManager()->unblockFileChange(file);
1391
1392     if (!success) {
1393         MakeWritableResult answer =
1394                 makeEditorWritable(editor);
1395         if (answer == Failed)
1396             return false;
1397         if (answer == SavedAs)
1398             return true;
1399
1400         file->checkPermissions();
1401
1402         m_d->m_core->fileManager()->blockFileChange(file);
1403         success = file->save(fileName);
1404         m_d->m_core->fileManager()->unblockFileChange(file);
1405     }
1406
1407     if (success && !editor->isTemporary())
1408         m_d->m_core->fileManager()->addToRecentFiles(editor->file()->fileName());
1409
1410     return success;
1411 }
1412
1413 EditorManager::ReadOnlyAction
1414     EditorManager::promptReadOnlyFile(const QString &fileName,
1415                                       const IVersionControl *versionControl,
1416                                       QWidget *parent,
1417                                       bool displaySaveAsButton)
1418 {
1419     // Version Control: If automatic open is desired, open right away.
1420     bool promptVCS = false;
1421     if (versionControl && versionControl->supportsOperation(IVersionControl::OpenOperation)) {
1422         if (versionControl->settingsFlags() & IVersionControl::AutoOpen)
1423             return RO_OpenVCS;
1424         promptVCS = true;
1425     }
1426
1427     // Create message box.
1428     QMessageBox msgBox(QMessageBox::Question, tr("File is Read Only"),
1429                        tr("The file <i>%1</i> is read only.").arg(QDir::toNativeSeparators(fileName)),
1430                        QMessageBox::Cancel, parent);
1431
1432     QPushButton *vcsButton = 0;
1433     if (promptVCS)
1434         vcsButton = msgBox.addButton(tr("Open with VCS (%1)").arg(versionControl->displayName()), QMessageBox::AcceptRole);
1435
1436     QPushButton *makeWritableButton =  msgBox.addButton(tr("Make writable"), QMessageBox::AcceptRole);
1437
1438     QPushButton *saveAsButton = 0;
1439     if (displaySaveAsButton)
1440         saveAsButton = msgBox.addButton(tr("Save as ..."), QMessageBox::ActionRole);
1441
1442     msgBox.setDefaultButton(vcsButton ? vcsButton : makeWritableButton);
1443     msgBox.exec();
1444
1445     QAbstractButton *clickedButton = msgBox.clickedButton();
1446     if (clickedButton == vcsButton)
1447         return RO_OpenVCS;
1448     if (clickedButton == makeWritableButton)
1449         return RO_MakeWriteable;
1450     if (clickedButton == saveAsButton)
1451         return RO_SaveAs;
1452     return  RO_Cancel;
1453 }
1454
1455
1456 MakeWritableResult
1457 EditorManager::makeEditorWritable(IEditor *editor)
1458 {
1459     if (!editor || !editor->file())
1460         return Failed;
1461     QString directory = QFileInfo(editor->file()->fileName()).absolutePath();
1462     IVersionControl *versionControl = m_d->m_core->vcsManager()->findVersionControlForDirectory(directory);
1463     IFile *file = editor->file();
1464     const QString &fileName = file->fileName();
1465
1466     switch (promptReadOnlyFile(fileName, versionControl, m_d->m_core->mainWindow(), true)) {
1467     case RO_OpenVCS:
1468         if (!versionControl->vcsOpen(fileName)) {
1469             QMessageBox::warning(m_d->m_core->mainWindow(), tr("Failed!"), tr("Could not open the file for editing with SCC."));
1470             return Failed;
1471         }
1472         file->checkPermissions();
1473         return OpenedWithVersionControl;
1474     case RO_MakeWriteable: {
1475         const bool permsOk = QFile::setPermissions(fileName, QFile::permissions(fileName) | QFile::WriteUser);
1476         if (!permsOk) {
1477             QMessageBox::warning(m_d->m_core->mainWindow(), tr("Failed!"),  tr("Could not set permissions to writable."));
1478             return Failed;
1479         }
1480     }
1481         file->checkPermissions();
1482         return MadeWritable;
1483     case RO_SaveAs :
1484         return saveFileAs(editor) ? SavedAs : Failed;
1485     case RO_Cancel:
1486         break;
1487     }
1488     return Failed;
1489 }
1490
1491 bool EditorManager::saveFileAs(IEditor *editor)
1492 {
1493     if (!editor)
1494         editor = currentEditor();
1495     if (!editor)
1496         return false;
1497
1498     IFile *file = editor->file();
1499     const QString &filter = formatFileFilters(m_d->m_core);
1500     QString selectedFilter =
1501         m_d->m_core->mimeDatabase()->findByFile(QFileInfo(file->fileName())).filterString();
1502     const QString &absoluteFilePath =
1503         m_d->m_core->fileManager()->getSaveAsFileName(file, filter, &selectedFilter);
1504
1505     if (absoluteFilePath.isEmpty())
1506         return false;
1507     if (absoluteFilePath != file->fileName()) {
1508         const QList<IEditor *> existList = editorsForFileName(absoluteFilePath);
1509         if (!existList.isEmpty()) {
1510             closeEditors(existList, false);
1511         }
1512     }
1513
1514     m_d->m_core->fileManager()->blockFileChange(file);
1515     const bool success = file->save(absoluteFilePath);
1516     m_d->m_core->fileManager()->unblockFileChange(file);
1517     file->checkPermissions();
1518
1519     // @todo: There is an issue to be treated here. The new file might be of a different mime
1520     // type than the original and thus require a different editor. An alternative strategy
1521     // would be to close the current editor and open a new appropriate one, but this is not
1522     // a good way out either (also the undo stack would be lost). Perhaps the best is to
1523     // re-think part of the editors design.
1524
1525     if (success && !editor->isTemporary())
1526         m_d->m_core->fileManager()->addToRecentFiles(file->fileName());
1527
1528     updateActions();
1529     return success;
1530 }
1531
1532 void EditorManager::gotoNextDocHistory()
1533 {
1534     OpenEditorsWindow *dialog = windowPopup();
1535     if (dialog->isVisible()) {
1536         dialog->selectNextEditor();
1537     } else {
1538         EditorView *view = currentEditorView();
1539         dialog->setEditors(m_d->m_view, view, m_d->m_editorModel);
1540         dialog->selectNextEditor();
1541         showPopupOrSelectDocument();
1542     }
1543 }
1544
1545 void EditorManager::gotoPreviousDocHistory()
1546 {
1547     OpenEditorsWindow *dialog = windowPopup();
1548     if (dialog->isVisible()) {
1549         dialog->selectPreviousEditor();
1550     } else {
1551         EditorView *view = currentEditorView();
1552         dialog->setEditors(m_d->m_view, view, m_d->m_editorModel);
1553         dialog->selectPreviousEditor();
1554         showPopupOrSelectDocument();
1555     }
1556 }
1557
1558 void EditorManager::makeCurrentEditorWritable()
1559 {
1560     if (IEditor* curEditor = currentEditor())
1561         makeEditorWritable(curEditor);
1562 }
1563
1564 void EditorManager::updateActions()
1565 {
1566     QString fName;
1567     IEditor *curEditor = currentEditor();
1568     int openedCount = openedEditors().count() + m_d->m_editorModel->restoredEditors().count();
1569
1570     if (curEditor) {
1571
1572         if (!curEditor->file()->fileName().isEmpty()) {
1573             QFileInfo fi(curEditor->file()->fileName());
1574             fName = fi.fileName();
1575         } else {
1576             fName = curEditor->displayName();
1577         }
1578
1579 #ifdef Q_WS_MAC
1580         window()->setWindowModified(curEditor->file()->isModified());
1581 #endif
1582         if (curEditor->file()->isModified() && curEditor->file()->isReadOnly()) {
1583             // we are about to change a read-only file, warn user
1584             showEditorInfoBar(QLatin1String("Core.EditorManager.MakeWritable"),
1585                 tr("<b>Warning:</b> You are changing a read-only file."),
1586                 tr("Make writable"), this, SLOT(makeCurrentEditorWritable()));
1587         } else {
1588             hideEditorInfoBar(QLatin1String("Core.EditorManager.MakeWritable"));
1589         }
1590 #ifdef Q_WS_MAC
1591     } else { // curEditor
1592         window()->setWindowModified(false);
1593 #endif
1594     }
1595
1596     m_d->m_saveAction->setEnabled(curEditor != 0 && curEditor->file()->isModified());
1597     m_d->m_saveAsAction->setEnabled(curEditor != 0 && curEditor->file()->isSaveAsAllowed());
1598     m_d->m_revertToSavedAction->setEnabled(curEditor != 0
1599         && !curEditor->file()->fileName().isEmpty() && curEditor->file()->isModified());
1600
1601     QString quotedName;
1602     if (!fName.isEmpty())
1603         quotedName = '"' + fName + '"';
1604
1605     m_d->m_saveAsAction->setText(tr("Save %1 &As...").arg(quotedName));
1606     m_d->m_saveAction->setText(tr("&Save %1").arg(quotedName));
1607     m_d->m_revertToSavedAction->setText(tr("Revert %1 to Saved").arg(quotedName));
1608
1609     m_d->m_closeCurrentEditorAction->setEnabled(curEditor != 0);
1610     m_d->m_closeCurrentEditorAction->setText(tr("Close %1").arg(quotedName));
1611     m_d->m_closeAllEditorsAction->setEnabled(openedCount > 0);
1612     m_d->m_closeOtherEditorsAction->setEnabled(openedCount > 1);
1613     m_d->m_closeOtherEditorsAction->setText((openedCount > 1 ? tr("Close All Except %1").arg(quotedName) : tr("Close Others")));
1614
1615     m_d->m_gotoNextDocHistoryAction->setEnabled(m_d->m_editorModel->rowCount() != 0);
1616     m_d->m_gotoPreviousDocHistoryAction->setEnabled(m_d->m_editorModel->rowCount() != 0);
1617     EditorView *view  = currentEditorView();
1618     m_d->m_goBackAction->setEnabled(view ? view->canGoBack() : false);
1619     m_d->m_goForwardAction->setEnabled(view ? view->canGoForward() : false);
1620
1621     bool hasSplitter = m_d->m_splitter->isSplitter();
1622     m_d->m_removeCurrentSplitAction->setEnabled(hasSplitter);
1623     m_d->m_removeAllSplitsAction->setEnabled(hasSplitter);
1624     m_d->m_gotoOtherSplitAction->setEnabled(hasSplitter);
1625
1626     m_d->m_openInExternalEditorAction->setEnabled(curEditor != 0);
1627 }
1628
1629 bool EditorManager::hasSplitter() const
1630 {
1631     return m_d->m_splitter->isSplitter();
1632 }
1633
1634 QList<IEditor*> EditorManager::openedEditors() const
1635 {
1636     return m_d->m_editorModel->editors();
1637 }
1638
1639 OpenEditorsModel *EditorManager::openedEditorsModel() const
1640 {
1641     return m_d->m_editorModel;
1642 }
1643
1644 void EditorManager::addCurrentPositionToNavigationHistory(IEditor *editor, const QByteArray &saveState)
1645 {
1646     currentEditorView()->addCurrentPositionToNavigationHistory(editor, saveState);
1647     updateActions();
1648 }
1649
1650 void EditorManager::cutForwardNavigationHistory()
1651 {
1652     currentEditorView()->cutForwardNavigationHistory();
1653     updateActions();
1654 }
1655
1656 void EditorManager::goBackInNavigationHistory()
1657 {
1658     currentEditorView()->goBackInNavigationHistory();
1659     updateActions();
1660     return;
1661 }
1662
1663 void EditorManager::goForwardInNavigationHistory()
1664 {
1665     currentEditorView()->goForwardInNavigationHistory();
1666     updateActions();
1667 }
1668
1669 OpenEditorsWindow *EditorManager::windowPopup() const
1670 {
1671     return m_d->m_windowPopup;
1672 }
1673
1674 void EditorManager::showPopupOrSelectDocument() const
1675 {
1676     if (QApplication::keyboardModifiers() == Qt::NoModifier) {
1677         windowPopup()->selectAndHide();
1678     } else {
1679         // EditorManager is invisible when invoked from Design Mode.
1680         const QPoint p = isVisible() ?
1681                          mapToGlobal(QPoint(0, 0)) :
1682                          m_d->m_core->mainWindow()->mapToGlobal(QPoint(0, 0));
1683         windowPopup()->move((width()-m_d->m_windowPopup->width())/2 + p.x(),
1684                             (height()-m_d->m_windowPopup->height())/2 + p.y());
1685         windowPopup()->setVisible(true);
1686     }
1687 }
1688
1689 // Save state of all non-teporary editors.
1690 QByteArray EditorManager::saveState() const
1691 {
1692     QByteArray bytes;
1693     QDataStream stream(&bytes, QIODevice::WriteOnly);
1694
1695     stream << QByteArray("EditorManagerV4");
1696
1697     QList<IEditor *> editors = openedEditors();
1698     foreach (IEditor *editor, editors) {
1699         if (!editor->file()->fileName().isEmpty()
1700                 && !editor->isTemporary()) {
1701             QByteArray state = editor->saveState();
1702             if (!state.isEmpty())
1703                 m_d->m_editorStates.insert(editor->file()->fileName(), QVariant(state));
1704         }
1705     }
1706
1707     stream << m_d->m_editorStates;
1708
1709     QList<OpenEditorsModel::Entry> entries = m_d->m_editorModel->entries();
1710     int entriesCount = 0;
1711     foreach (const OpenEditorsModel::Entry &entry, entries) {
1712         // The editor may be 0 if it was not loaded yet: In that case it is not temporary
1713         if (!entry.editor || !entry.editor->isTemporary())
1714             ++entriesCount;
1715     }
1716
1717     stream << entriesCount;
1718
1719     foreach (const OpenEditorsModel::Entry &entry, entries) {
1720         if (!entry.editor || !entry.editor->isTemporary())
1721             stream << entry.fileName() << entry.displayName() << entry.id().toUtf8();
1722     }
1723
1724     stream << m_d->m_splitter->saveState();
1725
1726     return bytes;
1727 }
1728
1729 bool EditorManager::restoreState(const QByteArray &state)
1730 {
1731     closeAllEditors(true);
1732     removeAllSplits();
1733     QDataStream stream(state);
1734
1735     QByteArray version;
1736     stream >> version;
1737
1738     if (version != "EditorManagerV4")
1739         return false;
1740
1741     QMap<QString, QVariant> editorstates;
1742
1743     QApplication::setOverrideCursor(Qt::WaitCursor);
1744
1745     stream >> editorstates;
1746
1747     QMapIterator<QString, QVariant> i(editorstates);
1748     while (i.hasNext()) {
1749         i.next();
1750         m_d->m_editorStates.insert(i.key(), i.value());
1751     }
1752
1753     int editorCount = 0;
1754     stream >> editorCount;
1755     while (--editorCount >= 0) {
1756         QString fileName;
1757         stream >> fileName;
1758         QString displayName;
1759         stream >> displayName;
1760         QByteArray id;
1761         stream >> id;
1762
1763         if (!fileName.isEmpty() && !displayName.isEmpty())
1764             m_d->m_editorModel->addRestoredEditor(fileName, displayName, QString::fromUtf8(id));
1765     }
1766
1767     QByteArray splitterstates;
1768     stream >> splitterstates;
1769     m_d->m_splitter->restoreState(splitterstates);
1770
1771     // splitting and stuff results in focus trouble, that's why we set the focus again after restoration
1772     if (m_d->m_currentEditor) {
1773         m_d->m_currentEditor->widget()->setFocus();
1774     } else if (Core::Internal::SplitterOrView *view = currentSplitterOrView()) {
1775         if (IEditor *e = view->editor())
1776             e->widget()->setFocus();
1777         else if (view->view())
1778             view->view()->setFocus();
1779     }
1780
1781     QApplication::restoreOverrideCursor();
1782
1783     return true;
1784 }
1785
1786 static const char * const documentStatesKey = "EditorManager/DocumentStates";
1787 static const char * const externalEditorKey = "EditorManager/ExternalEditorCommand";
1788 static const char * const reloadBehaviorKey = "EditorManager/ReloadBehavior";
1789
1790 void EditorManager::saveSettings()
1791 {
1792     SettingsDatabase *settings = m_d->m_core->settingsDatabase();
1793     settings->setValue(QLatin1String(documentStatesKey), m_d->m_editorStates);
1794     settings->setValue(QLatin1String(externalEditorKey), m_d->m_externalEditor);
1795     settings->setValue(QLatin1String(reloadBehaviorKey), m_d->m_reloadSetting);
1796 }
1797
1798 void EditorManager::readSettings()
1799 {
1800     // Backward compatibility to old locations for these settings
1801     QSettings *qs = m_d->m_core->settings();
1802     if (qs->contains(QLatin1String(documentStatesKey))) {
1803         m_d->m_editorStates = qs->value(QLatin1String(documentStatesKey))
1804             .value<QMap<QString, QVariant> >();
1805         qs->remove(QLatin1String(documentStatesKey));
1806     }
1807     if (qs->contains(QLatin1String(externalEditorKey))) {
1808         m_d->m_externalEditor = qs->value(QLatin1String(externalEditorKey)).toString();
1809         qs->remove(QLatin1String(externalEditorKey));
1810     }
1811
1812     SettingsDatabase *settings = m_d->m_core->settingsDatabase();
1813     if (settings->contains(QLatin1String(documentStatesKey)))
1814         m_d->m_editorStates = settings->value(QLatin1String(documentStatesKey))
1815             .value<QMap<QString, QVariant> >();
1816     if (settings->contains(QLatin1String(externalEditorKey)))
1817         m_d->m_externalEditor = settings->value(QLatin1String(externalEditorKey)).toString();
1818
1819     if (settings->contains(QLatin1String(reloadBehaviorKey)))
1820         m_d->m_reloadSetting = (IFile::ReloadSetting)settings->value(QLatin1String(reloadBehaviorKey)).toInt();
1821 }
1822
1823
1824 void EditorManager::revertToSaved()
1825 {
1826     IEditor *currEditor = currentEditor();
1827     if (!currEditor)
1828         return;
1829     const QString fileName =  currEditor->file()->fileName();
1830     if (fileName.isEmpty())
1831         return;
1832     if (currEditor->file()->isModified()) {
1833         QMessageBox msgBox(QMessageBox::Question, tr("Revert to Saved"),
1834                            tr("You will lose your current changes if you proceed reverting %1.").arg(QDir::toNativeSeparators(fileName)),
1835                            QMessageBox::Yes|QMessageBox::No, m_d->m_core->mainWindow());
1836         msgBox.button(QMessageBox::Yes)->setText(tr("Proceed"));
1837         msgBox.button(QMessageBox::No)->setText(tr("Cancel"));
1838         msgBox.setDefaultButton(QMessageBox::No);
1839         msgBox.setEscapeButton(QMessageBox::No);
1840         if (msgBox.exec() == QMessageBox::No)
1841             return;
1842
1843     }
1844     currEditor->file()->reload(IFile::FlagReload, IFile::TypeContents);
1845 }
1846
1847 void EditorManager::showEditorInfoBar(const QString &id,
1848                                       const QString &infoText,
1849                                       const QString &buttonText,
1850                                       QObject *object, const char *buttonPressMember,
1851                                       const char *cancelButtonPressMember)
1852 {
1853     currentEditorView()->showEditorInfoBar(id, infoText, buttonText, object, buttonPressMember, cancelButtonPressMember);
1854 }
1855
1856
1857 void EditorManager::hideEditorInfoBar(const QString &id)
1858 {
1859     Core::Internal::EditorView *cev = currentEditorView();
1860     if (cev)
1861         cev->hideEditorInfoBar(id);
1862 }
1863
1864 void EditorManager::showEditorStatusBar(const QString &id,
1865                                       const QString &infoText,
1866                                       const QString &buttonText,
1867                                       QObject *object, const char *member)
1868 {
1869
1870     currentEditorView()->showEditorStatusBar(id, infoText, buttonText, object, member);
1871 }
1872
1873 void EditorManager::hideEditorStatusBar(const QString &id)
1874 {
1875     currentEditorView()->hideEditorStatusBar(id);
1876 }
1877
1878 QString EditorManager::externalEditorHelpText() const
1879 {
1880     QString help = tr(
1881             "<table border=1 cellspacing=0 cellpadding=3>"
1882             "<tr><th>Variable</th><th>Expands to</th></tr>"
1883             "<tr><td>%f</td><td>file name</td></tr>"
1884             "<tr><td>%l</td><td>current line number</td></tr>"
1885             "<tr><td>%c</td><td>current column number</td></tr>"
1886             "<tr><td>%x</td><td>editor's x position on screen</td></tr>"
1887             "<tr><td>%y</td><td>editor's y position on screen</td></tr>"
1888             "<tr><td>%w</td><td>editor's width in pixels</td></tr>"
1889             "<tr><td>%h</td><td>editor's height in pixels</td></tr>"
1890             "<tr><td>%W</td><td>editor's width in characters</td></tr>"
1891             "<tr><td>%H</td><td>editor's height in characters</td></tr>"
1892             "<tr><td>%%</td><td>%</td></tr>"
1893             "</table>");
1894     return help;
1895 }
1896
1897 void EditorManager::openInExternalEditor()
1898 {
1899     QString command = m_d->m_externalEditor;
1900     if (command.isEmpty())
1901         command = defaultExternalEditor();
1902
1903     if (command.isEmpty())
1904         return;
1905
1906     IEditor *editor = currentEditor();
1907     if (!editor)
1908         return;
1909     if (editor->file()->isModified()) {
1910         bool cancelled = false;
1911         QList<IFile*> list = m_d->m_core->fileManager()->
1912                              saveModifiedFiles(QList<IFile*>() << editor->file(), &cancelled);
1913         if (cancelled)
1914             return;
1915     }
1916
1917     QRect rect = editor->widget()->rect();
1918     QFont font = editor->widget()->font();
1919     QFontMetrics fm(font);
1920     rect.moveTo(editor->widget()->mapToGlobal(QPoint(0,0)));
1921
1922     QString pre = command;
1923     QString cmd;
1924     for (int i = 0; i < pre.size(); ++i) {
1925         QChar c = pre.at(i);
1926         if (c == QLatin1Char('%') && i < pre.size()-1) {
1927             c = pre.at(++i);
1928             QString s;
1929             if (c == QLatin1Char('f'))
1930                 s = editor->file()->fileName();
1931             else if (c == QLatin1Char('l'))
1932                 s = QString::number(editor->currentLine());
1933             else if (c == QLatin1Char('c'))
1934                 s = QString::number(editor->currentColumn());
1935             else if (c == QLatin1Char('x'))
1936                 s = QString::number(rect.x());
1937             else if (c == QLatin1Char('y'))
1938                 s = QString::number(rect.y());
1939             else if (c == QLatin1Char('w'))
1940                 s = QString::number(rect.width());
1941             else if (c == QLatin1Char('h'))
1942                 s = QString::number(rect.height());
1943             else if (c == QLatin1Char('W'))
1944                 s = QString::number(rect.width() / fm.width(QLatin1Char('x')));
1945             else if (c == QLatin1Char('H'))
1946                 s = QString::number(rect.height() / fm.lineSpacing());
1947             else if (c == QLatin1Char('%'))
1948                 s = c;
1949             else {
1950                 s = QLatin1Char('%');
1951                 s += c;
1952             }
1953             cmd += s;
1954             continue;
1955
1956         }
1957         cmd += c;
1958     }
1959
1960     QProcess::startDetached(cmd);
1961 }
1962
1963 void EditorManager::setExternalEditor(const QString &editor)
1964 {
1965     if (editor.isEmpty() || editor == defaultExternalEditor())
1966         m_d->m_externalEditor = defaultExternalEditor();
1967     else
1968         m_d->m_externalEditor = editor;
1969 }
1970
1971 QString EditorManager::externalEditor() const
1972 {
1973     if (m_d->m_externalEditor.isEmpty())
1974         return defaultExternalEditor();
1975     return m_d->m_externalEditor;
1976 }
1977
1978 void EditorManager::setReloadSetting(IFile::ReloadSetting behavior)
1979 {
1980     m_d->m_reloadSetting = behavior;
1981 }
1982
1983 IFile::ReloadSetting EditorManager::reloadSetting() const
1984 {
1985     return m_d->m_reloadSetting;
1986 }
1987
1988 QTextCodec *EditorManager::defaultTextEncoding() const
1989 {
1990     QSettings *settings = Core::ICore::instance()->settings();
1991     if (QTextCodec *candidate = QTextCodec::codecForName(
1992             settings->value(QLatin1String(Constants::SETTINGS_DEFAULTTEXTENCODING)).toByteArray()))
1993         return candidate;
1994     return QTextCodec::codecForLocale();
1995 }
1996
1997 Core::IEditor *EditorManager::duplicateEditor(Core::IEditor *editor)
1998 {
1999     if (!editor->duplicateSupported())
2000         return 0;
2001
2002     IEditor *duplicate = editor->duplicate(0);
2003     duplicate->restoreState(editor->saveState());
2004     emit editorCreated(duplicate, duplicate->file()->fileName());
2005     addEditor(duplicate, true);
2006     return duplicate;
2007 }
2008
2009 void EditorManager::split(Qt::Orientation orientation)
2010 {
2011     SplitterOrView *view = m_d->m_currentView;
2012     if (!view)
2013             view = m_d->m_currentEditor ? m_d->m_splitter->findView(m_d->m_currentEditor)
2014                        : m_d->m_splitter->findFirstView();
2015     if (view && !view->splitter()) {
2016         view->split(orientation);
2017     }
2018     updateActions();
2019 }
2020
2021 void EditorManager::split()
2022 {
2023     split(Qt::Vertical);
2024 }
2025
2026 void EditorManager::splitSideBySide()
2027 {
2028     split(Qt::Horizontal);
2029 }
2030
2031 void EditorManager::removeCurrentSplit()
2032 {
2033     SplitterOrView *viewToClose = m_d->m_currentView;
2034     if (!viewToClose && m_d->m_currentEditor)
2035         viewToClose = m_d->m_splitter->findView(m_d->m_currentEditor);
2036
2037     if (!viewToClose || viewToClose->isSplitter() || viewToClose == m_d->m_splitter)
2038         return;
2039
2040     closeView(viewToClose->view());
2041     updateActions();
2042 }
2043
2044 void EditorManager::removeAllSplits()
2045 {
2046     if (!m_d->m_splitter->isSplitter())
2047         return;
2048     IEditor *editor = m_d->m_currentEditor;
2049     m_d->m_currentEditor = 0; // trigger update below
2050     if (editor && m_d->m_editorModel->isDuplicate(editor))
2051         m_d->m_editorModel->makeOriginal(editor);
2052     m_d->m_splitter->unsplitAll();
2053     if (!editor)
2054         editor = pickUnusedEditor();
2055     activateEditor(editor);
2056 }
2057
2058 void EditorManager::gotoOtherSplit()
2059 {
2060     if (m_d->m_splitter->isSplitter()) {
2061         SplitterOrView *currentView = m_d->m_currentView;
2062         if (!currentView && m_d->m_currentEditor)
2063             currentView = m_d->m_splitter->findView(m_d->m_currentEditor);
2064         if (!currentView)
2065             currentView = m_d->m_splitter->findFirstView();
2066         SplitterOrView *view = m_d->m_splitter->findNextView(currentView);
2067         if (!view)
2068             view = m_d->m_splitter->findFirstView();
2069         if (view) {
2070             if (IEditor *editor = view->editor()) {
2071                 setCurrentEditor(editor, true);
2072                 editor->widget()->setFocus();
2073             } else {
2074                 setCurrentView(view);
2075             }
2076         }
2077     }
2078 }
2079
2080 qint64 EditorManager::maxTextFileSize()
2081 {
2082     return (qint64(3) << 24);
2083 }
2084 //===================EditorClosingCoreListener======================
2085