OSDN Git Service

4b42d3ec8f40ad72f59e73a9236e1141f2766857
[qt-creator-jp/qt-creator-jp.git] / src / plugins / coreplugin / editormanager / editorview.cpp
1 /**************************************************************************
2 **
3 ** This file is part of Qt Creator
4 **
5 ** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
6 **
7 ** Contact: Nokia Corporation (qt-info@nokia.com)
8 **
9 ** No Commercial Usage
10 **
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
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 ** In addition, as a special exception, Nokia gives you certain additional
26 ** rights.  These rights are described in the Nokia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** If you have questions regarding the use of this file, please contact
30 ** Nokia at qt-info@nokia.com.
31 **
32 **************************************************************************/
33
34 #include "editorview.h"
35 #include "editormanager.h"
36 #include "coreimpl.h"
37 #include "minisplitter.h"
38 #include "openeditorsmodel.h"
39
40 #include <coreplugin/editortoolbar.h>
41 #include <coreplugin/coreconstants.h>
42 #include <coreplugin/actionmanager/actionmanager.h>
43 #include <coreplugin/editormanager/ieditor.h>
44
45 #include <coreplugin/findplaceholder.h>
46 #include <utils/qtcassert.h>
47
48 #include <QtCore/QDebug>
49 #include <QtCore/QDir>
50 #include <QtCore/QFileInfo>
51 #include <QtCore/QMimeData>
52
53 #include <QtGui/QApplication>
54 #include <QtGui/QComboBox>
55 #include <QtGui/QHBoxLayout>
56 #include <QtGui/QLabel>
57 #include <QtGui/QMouseEvent>
58 #include <QtGui/QPainter>
59 #include <QtGui/QStackedWidget>
60 #include <QtGui/QStyle>
61 #include <QtGui/QStyleOption>
62 #include <QtGui/QToolButton>
63 #include <QtGui/QMenu>
64 #include <QtGui/QClipboard>
65 #include <QtGui/QAction>
66 #include <QtGui/QSplitter>
67 #include <QtGui/QStackedLayout>
68
69 #ifdef Q_WS_MAC
70 #include <qmacstyle_mac.h>
71 #endif
72
73 using namespace Core;
74 using namespace Core::Internal;
75
76
77 // ================EditorView====================
78
79 EditorView::EditorView(QWidget *parent) :
80     QWidget(parent),
81     m_toolBar(EditorManager::createToolBar(this)),
82     m_container(new QStackedWidget(this)),
83     m_infoWidget(new QFrame(this)),
84     m_editorForInfoWidget(0),
85     m_statusHLine(new QFrame(this)),
86     m_statusWidget(new QFrame(this)),
87     m_currentNavigationHistoryPosition(0)
88 {
89     QVBoxLayout *tl = new QVBoxLayout(this);
90     tl->setSpacing(0);
91     tl->setMargin(0);
92     {
93         connect(m_toolBar, SIGNAL(goBackClicked()), this, SLOT(goBackInNavigationHistory()));
94         connect(m_toolBar, SIGNAL(goForwardClicked()), this, SLOT(goForwardInNavigationHistory()));
95         connect(m_toolBar, SIGNAL(closeClicked()), this, SLOT(closeView()));
96         connect(m_toolBar, SIGNAL(listSelectionActivated(int)), this, SLOT(listSelectionActivated(int)));
97         tl->addWidget(m_toolBar);
98     }
99     {
100         QPalette pal = m_infoWidget->palette();
101         pal.setColor(QPalette::Window, QColor(255, 255, 225));
102         pal.setColor(QPalette::WindowText, Qt::black);
103
104         m_infoWidget->setPalette(pal);
105         m_infoWidget->setFrameStyle(QFrame::Panel | QFrame::Raised);
106         m_infoWidget->setLineWidth(1);
107         m_infoWidget->setAutoFillBackground(true);
108
109         QHBoxLayout *hbox = new QHBoxLayout(m_infoWidget);
110         hbox->setMargin(2);
111         m_infoWidgetLabel = new QLabel("Placeholder");
112         m_infoWidgetLabel->setWordWrap(true);
113         hbox->addWidget(m_infoWidgetLabel);
114
115         m_infoWidgetButton = new QToolButton;
116         m_infoWidgetButton->setText(tr("Placeholder"));
117         hbox->addWidget(m_infoWidgetButton);
118
119         m_infoWidgetCloseButton = new QToolButton;
120         m_infoWidgetCloseButton->setAutoRaise(true);
121         m_infoWidgetCloseButton->setIcon(QIcon(QLatin1String(Core::Constants::ICON_CLEAR)));
122         m_infoWidgetCloseButton->setToolTip(tr("Close"));
123
124         hbox->addWidget(m_infoWidgetCloseButton);
125
126         m_infoWidget->setVisible(false);
127         tl->addWidget(m_infoWidget);
128     }
129
130     tl->addWidget(m_container);
131
132     tl->addWidget(new FindToolBarPlaceHolder(this));
133
134     {
135         m_statusHLine->setFrameStyle(QFrame::HLine);
136
137         m_statusWidget->setFrameStyle(QFrame::NoFrame);
138         m_statusWidget->setLineWidth(0);
139         m_statusWidget->setAutoFillBackground(true);
140
141         QHBoxLayout *hbox = new QHBoxLayout(m_statusWidget);
142         hbox->setContentsMargins(1, 0, 1, 1);
143         m_statusWidgetLabel = new QLabel;
144         m_statusWidgetLabel->setContentsMargins(3, 0, 3, 0);
145         hbox->addWidget(m_statusWidgetLabel);
146         hbox->addStretch(1);
147
148         m_statusWidgetButton = new QToolButton;
149         m_statusWidgetButton->setContentsMargins(0, 0, 0, 0);
150         hbox->addWidget(m_statusWidgetButton);
151
152         m_statusHLine->setVisible(false);
153         m_statusWidget->setVisible(false);
154         tl->addWidget(m_statusHLine);
155         tl->addWidget(m_statusWidget);
156     }
157
158     updateNavigatorActions();
159 }
160
161 EditorView::~EditorView()
162 {
163 }
164
165
166 void EditorView::closeView()
167 {
168     EditorManager *em = CoreImpl::instance()->editorManager();
169     IEditor *editor = currentEditor();
170     if (editor)
171        em->closeEditor(editor);
172 }
173 void EditorView::showEditorInfoBar(const QString &id,
174                                    const QString &infoText,
175                                    const QString &buttonText,
176                                    QObject *object, const char *buttonPressMember,
177                                    const char *cancelButtonPressMember)
178 {
179     m_infoWidgetId = id;
180     m_infoWidgetLabel->setText(infoText);
181     m_infoWidgetButton->setText(buttonText);
182
183     if (object && !buttonText.isEmpty()) {
184         m_infoWidgetButton->show();
185     } else {
186         m_infoWidgetButton->hide();
187     }
188
189     m_infoWidgetButton->disconnect();
190     if (object && buttonPressMember)
191         connect(m_infoWidgetButton, SIGNAL(clicked()), object, buttonPressMember);
192
193     m_infoWidgetCloseButton->disconnect();
194     if (object && cancelButtonPressMember)
195         connect(m_infoWidgetCloseButton, SIGNAL(clicked()), object, cancelButtonPressMember);
196     connect(m_infoWidgetCloseButton, SIGNAL(clicked()), m_infoWidget, SLOT(hide()));
197
198     m_infoWidget->setVisible(true);
199     m_editorForInfoWidget = currentEditor();
200 }
201
202 void EditorView::hideEditorInfoBar(const QString &id)
203 {
204     if (id == m_infoWidgetId)
205         m_infoWidget->setVisible(false);
206 }
207
208 void EditorView::showEditorStatusBar(const QString &id,
209                                      const QString &infoText,
210                                      const QString &buttonText,
211                                      QObject *object, const char *member)
212 {
213     m_statusWidgetId = id;
214     m_statusWidgetLabel->setText(infoText);
215     m_statusWidgetButton->setText(buttonText);
216     m_statusWidgetButton->setToolTip(buttonText);
217     m_statusWidgetButton->disconnect();
218     if (object && member)
219         connect(m_statusWidgetButton, SIGNAL(clicked()), object, member);
220     m_statusWidget->setVisible(true);
221     m_statusHLine->setVisible(true);
222     //m_editorForInfoWidget = currentEditor();
223 }
224
225 void EditorView::hideEditorStatusBar(const QString &id)
226 {
227     if (id == m_statusWidgetId) {
228         m_statusWidget->setVisible(false);
229         m_statusHLine->setVisible(false);
230     }
231 }
232
233 void EditorView::addEditor(IEditor *editor)
234 {
235     if (m_editors.contains(editor))
236         return;
237
238     m_editors.append(editor);
239
240     m_container->addWidget(editor->widget());
241     m_widgetEditorMap.insert(editor->widget(), editor);
242     m_toolBar->addEditor(editor);
243
244     if (editor == currentEditor())
245         setCurrentEditor(editor);
246 }
247
248 bool EditorView::hasEditor(IEditor *editor) const
249 {
250     return m_editors.contains(editor);
251 }
252
253 void EditorView::removeEditor(IEditor *editor)
254 {
255     QTC_ASSERT(editor, return);
256     if (!m_editors.contains(editor))
257         return;
258
259     const int index = m_container->indexOf(editor->widget());
260     QTC_ASSERT((index != -1), return);
261     bool wasCurrent = (index == m_container->currentIndex());
262     m_editors.removeAll(editor);
263
264     m_container->removeWidget(editor->widget());
265     m_widgetEditorMap.remove(editor->widget());
266     editor->widget()->setParent(0);
267     m_toolBar->removeToolbarForEditor(editor);
268
269     if (wasCurrent)
270         setCurrentEditor(m_editors.count() ? m_editors.last() : 0);
271 }
272
273 IEditor *EditorView::currentEditor() const
274 {
275     if (m_container->count() > 0)
276         return m_widgetEditorMap.value(m_container->currentWidget());
277     return 0;
278 }
279
280 void EditorView::listSelectionActivated(int index)
281 {
282     QAbstractItemModel *model = EditorManager::instance()->openedEditorsModel();
283     EditorManager::instance()->activateEditorForIndex(this, model->index(index, 0), Core::EditorManager::ModeSwitch);
284 }
285
286 void EditorView::setCurrentEditor(IEditor *editor)
287 {
288     // FIXME: this keeps the editor hidden if switching from A to B and back
289     if (editor != m_editorForInfoWidget) {
290         m_infoWidget->hide();
291         m_editorForInfoWidget = 0;
292     }
293
294     if (!editor || m_container->count() <= 0
295         || m_container->indexOf(editor->widget()) == -1) {
296         m_toolBar->updateEditorStatus(0);
297         // ### TODO the combo box m_editorList should show an empty item
298         return;
299     }
300
301     m_editors.removeAll(editor);
302     m_editors.append(editor);
303
304     const int idx = m_container->indexOf(editor->widget());
305     QTC_ASSERT(idx >= 0, return);
306     m_container->setCurrentIndex(idx);
307     m_toolBar->setCurrentEditor(editor);
308
309     updateEditorHistory(editor);
310 }
311
312 int EditorView::editorCount() const
313 {
314     return m_container->count();
315 }
316
317 QList<IEditor *> EditorView::editors() const
318 {
319     return m_widgetEditorMap.values();
320 }
321
322 void EditorView::updateEditorHistory(IEditor *editor)
323 {
324     if (!editor)
325         return;
326     IFile *file = editor->file();
327
328     if (!file)
329         return;
330
331     QByteArray state = editor->saveState();
332
333     EditLocation location;
334     location.file = file;
335     location.fileName = file->fileName();
336     location.id = editor->id();
337     location.state = QVariant(state);
338
339     for(int i = 0; i < m_editorHistory.size(); ++i) {
340         if (m_editorHistory.at(i).file == 0
341             || m_editorHistory.at(i).file == file
342             ){
343             m_editorHistory.removeAt(i--);
344             continue;
345         }
346     }
347     m_editorHistory.prepend(location);
348 }
349
350 QRect EditorView::editorArea() const
351 {
352     const QRect cRect = m_container->rect();
353     return QRect(m_container->mapToGlobal(cRect.topLeft()), cRect.size());
354 }
355
356 void EditorView::addCurrentPositionToNavigationHistory(IEditor *editor, const QByteArray &saveState)
357 {
358     if (editor && editor != currentEditor()) {
359         return; // we only save editor sate for the current editor, when the user interacts
360     }
361
362     if (!editor)
363         editor = currentEditor();
364     if (!editor)
365         return;
366     IFile *file = editor->file();
367
368     if (!file)
369         return;
370
371     QByteArray state;
372     if (saveState.isNull()) {
373         state = editor->saveState();
374     } else {
375         state = saveState;
376     }
377
378     EditLocation location;
379     location.file = file;
380     location.fileName = file->fileName();
381     location.id = editor->id();
382     location.state = QVariant(state);
383     m_currentNavigationHistoryPosition = qMin(m_currentNavigationHistoryPosition, m_navigationHistory.size()); // paranoia
384     m_navigationHistory.insert(m_currentNavigationHistoryPosition, location);
385     ++m_currentNavigationHistoryPosition;
386
387     while (m_navigationHistory.size() >= 30) {
388         if (m_currentNavigationHistoryPosition > 15) {
389             m_navigationHistory.removeFirst();
390             --m_currentNavigationHistoryPosition;
391         } else {
392             m_navigationHistory.removeLast();
393         }
394     }
395     updateNavigatorActions();
396 }
397
398 void EditorView::cutForwardNavigationHistory()
399 {
400     while (m_currentNavigationHistoryPosition < m_navigationHistory.size() - 1)
401         m_navigationHistory.removeLast();
402 }
403
404 void EditorView::updateNavigatorActions()
405 {
406     m_toolBar->setCanGoBack(canGoBack());
407     m_toolBar->setCanGoForward(canGoForward());
408 }
409
410 void EditorView::copyNavigationHistoryFrom(EditorView* other)
411 {
412     if (!other)
413         return;
414     m_currentNavigationHistoryPosition = other->m_currentNavigationHistoryPosition;
415     m_navigationHistory = other->m_navigationHistory;
416     m_editorHistory = other->m_editorHistory;
417     updateNavigatorActions();
418 }
419
420 void EditorView::updateCurrentPositionInNavigationHistory()
421 {
422     IEditor *editor = currentEditor();
423     if (!editor || !editor->file())
424         return;
425
426     IFile *file = editor->file();
427     EditLocation *location;
428     if (m_currentNavigationHistoryPosition < m_navigationHistory.size()) {
429         location = &m_navigationHistory[m_currentNavigationHistoryPosition];
430     } else {
431         m_navigationHistory.append(EditLocation());
432         location = &m_navigationHistory[m_navigationHistory.size()-1];
433     }
434     location->file = file;
435     location->fileName = file->fileName();
436     location->id = editor->id();
437     location->state = QVariant(editor->saveState());
438 }
439
440 void EditorView::goBackInNavigationHistory()
441 {
442     EditorManager *em = CoreImpl::instance()->editorManager();
443     updateCurrentPositionInNavigationHistory();
444     while (m_currentNavigationHistoryPosition > 0) {
445         --m_currentNavigationHistoryPosition;
446         EditLocation location = m_navigationHistory.at(m_currentNavigationHistoryPosition);
447         IEditor *editor;
448         if (location.file) {
449             editor = em->activateEditorForFile(this, location.file,
450                                         EditorManager::IgnoreNavigationHistory | EditorManager::ModeSwitch);
451         } else {
452             editor = em->openEditor(this, location.fileName, location.id,
453                                     EditorManager::IgnoreNavigationHistory | EditorManager::ModeSwitch);
454             if (!editor) {
455                 m_navigationHistory.removeAt(m_currentNavigationHistoryPosition);
456                 continue;
457             }
458         }
459         editor->restoreState(location.state.toByteArray());
460         break;
461     }
462     updateNavigatorActions();
463 }
464
465 void EditorView::goForwardInNavigationHistory()
466 {
467     EditorManager *em = CoreImpl::instance()->editorManager();
468     updateCurrentPositionInNavigationHistory();
469     if (m_currentNavigationHistoryPosition >= m_navigationHistory.size()-1)
470         return;
471     ++m_currentNavigationHistoryPosition;
472     EditLocation location = m_navigationHistory.at(m_currentNavigationHistoryPosition);
473     IEditor *editor;
474     if (location.file) {
475         editor = em->activateEditorForFile(this, location.file,
476                                     EditorManager::IgnoreNavigationHistory | EditorManager::ModeSwitch);
477     } else {
478         editor = em->openEditor(this, location.fileName, location.id, EditorManager::IgnoreNavigationHistory);
479         if (!editor) {
480             //TODO
481             qDebug() << Q_FUNC_INFO << "can't open file" << location.fileName;
482             return;
483         }
484     }
485     editor->restoreState(location.state.toByteArray());
486     updateNavigatorActions();
487 }
488
489
490 SplitterOrView::SplitterOrView(OpenEditorsModel *model)
491 {
492     Q_ASSERT(model);
493     m_isRoot = true;
494     m_layout = new QStackedLayout(this);
495     m_view = new EditorView();
496     m_splitter = 0;
497     m_layout->addWidget(m_view);
498 }
499
500 SplitterOrView::SplitterOrView(Core::IEditor *editor)
501 {
502     m_isRoot = false;
503     m_layout = new QStackedLayout(this);
504     m_view = new EditorView();
505     if (editor)
506         m_view->addEditor(editor);
507     m_splitter = 0;
508     m_layout->addWidget(m_view);
509 }
510
511 SplitterOrView::~SplitterOrView()
512 {
513     delete m_layout;
514     m_layout = 0;
515     delete m_view;
516     m_view = 0;
517     delete m_splitter;
518     m_splitter = 0;
519 }
520
521 void SplitterOrView::mousePressEvent(QMouseEvent *e)
522 {
523     if (e->button() != Qt::LeftButton)
524         return;
525     setFocus(Qt::MouseFocusReason);
526     CoreImpl::instance()->editorManager()->setCurrentView(this);
527 }
528
529 void SplitterOrView::paintEvent(QPaintEvent *)
530 {
531     if (CoreImpl::instance()->editorManager()->currentSplitterOrView() != this)
532         return;
533
534     if (!m_view || hasEditors())
535         return;
536
537     // Discreet indication where an editor would be if there is none
538     QPainter painter(this);
539     painter.setRenderHint(QPainter::Antialiasing, true);
540     painter.setPen(Qt::NoPen);
541     painter.setBrush(palette().color(QPalette::Background).darker(107));
542     const int r = 3;
543     const QRect areaGlobal(view()->editorArea());
544     const QRect areaLocal(mapFromGlobal(areaGlobal.topLeft()), areaGlobal.size());
545     painter.drawRoundedRect(areaLocal.adjusted(r , r, -r, -r), r * 2, r * 2);
546 }
547
548 SplitterOrView *SplitterOrView::findFirstView()
549 {
550     if (m_splitter) {
551         for (int i = 0; i < m_splitter->count(); ++i) {
552             if (SplitterOrView *splitterOrView = qobject_cast<SplitterOrView*>(m_splitter->widget(i)))
553                 if (SplitterOrView *result = splitterOrView->findFirstView())
554                     return result;
555         }
556         return 0;
557     }
558     return this;
559 }
560
561 SplitterOrView *SplitterOrView::findEmptyView()
562 {
563     if (m_splitter) {
564         for (int i = 0; i < m_splitter->count(); ++i) {
565             if (SplitterOrView *splitterOrView = qobject_cast<SplitterOrView*>(m_splitter->widget(i)))
566                 if (SplitterOrView *result = splitterOrView->findEmptyView())
567                     return result;
568         }
569         return 0;
570     }
571     if (!hasEditors())
572         return this;
573     return 0;
574 }
575
576 SplitterOrView *SplitterOrView::findView(Core::IEditor *editor)
577 {
578     if (!editor || hasEditor(editor))
579         return this;
580     if (m_splitter) {
581         for (int i = 0; i < m_splitter->count(); ++i) {
582             if (SplitterOrView *splitterOrView = qobject_cast<SplitterOrView*>(m_splitter->widget(i)))
583                 if (SplitterOrView *result = splitterOrView->findView(editor))
584                     return result;
585         }
586     }
587     return 0;
588 }
589
590 SplitterOrView *SplitterOrView::findView(EditorView *view)
591 {
592     if (view == m_view)
593         return this;
594     if (m_splitter) {
595         for (int i = 0; i < m_splitter->count(); ++i) {
596             if (SplitterOrView *splitterOrView = qobject_cast<SplitterOrView*>(m_splitter->widget(i)))
597                 if (SplitterOrView *result = splitterOrView->findView(view))
598                     return result;
599         }
600     }
601     return 0;
602 }
603
604 SplitterOrView *SplitterOrView::findSplitter(Core::IEditor *editor)
605 {
606     if (m_splitter) {
607         for (int i = 0; i < m_splitter->count(); ++i) {
608             if (SplitterOrView *splitterOrView = qobject_cast<SplitterOrView*>(m_splitter->widget(i))) {
609                 if (splitterOrView->hasEditor(editor))
610                     return this;
611                 if (SplitterOrView *result = splitterOrView->findSplitter(editor))
612                     return result;
613             }
614         }
615     }
616     return 0;
617 }
618
619 SplitterOrView *SplitterOrView::findSplitter(SplitterOrView *child)
620 {
621     if (m_splitter) {
622         for (int i = 0; i < m_splitter->count(); ++i) {
623             if (SplitterOrView *splitterOrView = qobject_cast<SplitterOrView*>(m_splitter->widget(i))) {
624                 if (splitterOrView == child)
625                     return this;
626                 if (SplitterOrView *result = splitterOrView->findSplitter(child))
627                     return result;
628             }
629         }
630     }
631     return 0;
632 }
633
634 SplitterOrView *SplitterOrView::findNextView(SplitterOrView *view)
635 {
636     bool found = false;
637     return findNextView_helper(view, &found);
638 }
639
640 SplitterOrView *SplitterOrView::findNextView_helper(SplitterOrView *view, bool *found)
641 {
642     if (*found && m_view) {
643         return this;
644     }
645
646     if (this == view) {
647         *found = true;
648         return 0;
649     }
650
651     if (m_splitter) {
652         for (int i = 0; i < m_splitter->count(); ++i) {
653             if (SplitterOrView *splitterOrView = qobject_cast<SplitterOrView*>(m_splitter->widget(i))) {
654                 if (SplitterOrView *result = splitterOrView->findNextView_helper(view, found))
655                     return result;
656             }
657         }
658     }
659     return 0;
660 }
661
662 QSize SplitterOrView::minimumSizeHint() const
663 {
664     if (m_splitter)
665         return m_splitter->minimumSizeHint();
666     return QSize(64, 64);
667 }
668
669 QSplitter *SplitterOrView::takeSplitter()
670 {
671     QSplitter *oldSplitter = m_splitter;
672     if (m_splitter)
673         m_layout->removeWidget(m_splitter);
674     m_splitter = 0;
675     return oldSplitter;
676 }
677
678 EditorView *SplitterOrView::takeView()
679 {
680     EditorView *oldView = m_view;
681     if (m_view)
682         m_layout->removeWidget(m_view);
683     m_view = 0;
684     return oldView;
685 }
686
687 void SplitterOrView::split(Qt::Orientation orientation)
688 {
689     Q_ASSERT(m_view && m_splitter == 0);
690     m_splitter = new MiniSplitter(this);
691     m_splitter->setOrientation(orientation);
692     m_layout->addWidget(m_splitter);
693     EditorManager *em = CoreImpl::instance()->editorManager();
694     Core::IEditor *e = m_view->currentEditor();
695
696     SplitterOrView *view = 0;
697     SplitterOrView *otherView = 0;
698     if (e) {
699
700         foreach(IEditor *editor, m_view->editors())
701             m_view->removeEditor(editor);
702
703         m_splitter->addWidget((view = new SplitterOrView(e)));
704         if (e->duplicateSupported()) {
705             Core::IEditor *duplicate = em->duplicateEditor(e);
706             m_splitter->addWidget((otherView = new SplitterOrView(duplicate)));
707         } else {
708             m_splitter->addWidget((otherView = new SplitterOrView()));
709         }
710     } else {
711         m_splitter->addWidget((otherView = new SplitterOrView()));
712         m_splitter->addWidget((view = new SplitterOrView()));
713     }
714
715     m_layout->setCurrentWidget(m_splitter);
716
717     view->view()->copyNavigationHistoryFrom(m_view);
718     view->view()->setCurrentEditor(view->view()->currentEditor());
719     otherView->view()->copyNavigationHistoryFrom(m_view);
720     otherView->view()->setCurrentEditor(otherView->view()->currentEditor());
721
722     if (m_view && !m_isRoot) {
723         em->emptyView(m_view);
724         delete m_view;
725         m_view = 0;
726     }
727
728     if (e)
729         em->activateEditor(view->view(), e);
730     else
731         em->setCurrentView(view);
732 }
733
734 void SplitterOrView::unsplitAll()
735 {
736     m_splitter->hide();
737     m_layout->removeWidget(m_splitter); // workaround Qt bug
738     unsplitAll_helper();
739     delete m_splitter;
740     m_splitter = 0;
741 }
742
743 void SplitterOrView::unsplitAll_helper()
744 {
745     if (!m_isRoot && m_view)
746         CoreImpl::instance()->editorManager()->emptyView(m_view);
747     if (m_splitter) {
748         for (int i = 0; i < m_splitter->count(); ++i) {
749             if (SplitterOrView *splitterOrView = qobject_cast<SplitterOrView*>(m_splitter->widget(i))) {
750                 splitterOrView->unsplitAll_helper();
751             }
752         }
753     }
754 }
755
756 void SplitterOrView::unsplit()
757 {
758     if (!m_splitter)
759         return;
760
761     Q_ASSERT(m_splitter->count() == 1);
762     EditorManager *em = CoreImpl::instance()->editorManager();
763     SplitterOrView *childSplitterOrView = qobject_cast<SplitterOrView*>(m_splitter->widget(0));
764     QSplitter *oldSplitter = m_splitter;
765     m_splitter = 0;
766
767     if (childSplitterOrView->isSplitter()) {
768         Q_ASSERT(childSplitterOrView->view() == 0);
769         m_splitter = childSplitterOrView->takeSplitter();
770         m_layout->addWidget(m_splitter);
771         m_layout->setCurrentWidget(m_splitter);
772     } else {
773         EditorView *childView = childSplitterOrView->view();
774         Q_ASSERT(childView);
775         if (m_view) {
776             m_view->copyNavigationHistoryFrom(childView);
777             if (IEditor *e = childView->currentEditor()) {
778                 childView->removeEditor(e);
779                 m_view->addEditor(e);
780                 m_view->setCurrentEditor(e);
781             }
782             em->emptyView(childView);
783         } else {
784             m_view = childSplitterOrView->takeView();
785             m_layout->addWidget(m_view);
786         }
787         m_layout->setCurrentWidget(m_view);
788     }
789     delete oldSplitter;
790     em->setCurrentView(findFirstView());
791 }
792
793
794 QByteArray SplitterOrView::saveState() const
795 {
796     QByteArray bytes;
797     QDataStream stream(&bytes, QIODevice::WriteOnly);
798
799     if (m_splitter) {
800         stream << QByteArray("splitter")
801                 << (qint32)m_splitter->orientation()
802                 << m_splitter->saveState()
803                 << static_cast<SplitterOrView*>(m_splitter->widget(0))->saveState()
804                 << static_cast<SplitterOrView*>(m_splitter->widget(1))->saveState();
805     } else {
806         IEditor* e = editor();
807         EditorManager *em = CoreImpl::instance()->editorManager();
808
809         // don't save state of temporary or ad-hoc editors
810         if (e && (e->isTemporary() || e->file()->fileName().isEmpty())) {
811             // look for another editor that is more suited
812             e = 0;
813             foreach (IEditor *otherEditor, editors()) {
814                 if (!otherEditor->isTemporary() && !otherEditor->file()->fileName().isEmpty()) {
815                     e = otherEditor;
816                     break;
817                 }
818             }
819         }
820
821         if (!e) {
822             stream << QByteArray("empty");
823         } else if (e == em->currentEditor()) {
824             stream << QByteArray("currenteditor")
825                     << e->file()->fileName() << e->id() << e->saveState();
826         } else {
827             stream << QByteArray("editor")
828                     << e->file()->fileName() << e->id() << e->saveState();
829         }
830     }
831     return bytes;
832 }
833
834 void SplitterOrView::restoreState(const QByteArray &state)
835 {
836     QDataStream stream(state);
837     QByteArray mode;
838     stream >> mode;
839     if (mode == "splitter") {
840         qint32 orientation;
841         QByteArray splitter, first, second;
842         stream >> orientation >> splitter >> first >> second;
843         split((Qt::Orientation)orientation);
844         m_splitter->restoreState(splitter);
845         static_cast<SplitterOrView*>(m_splitter->widget(0))->restoreState(first);
846         static_cast<SplitterOrView*>(m_splitter->widget(1))->restoreState(second);
847     } else if (mode == "editor" || mode == "currenteditor") {
848         EditorManager *em = CoreImpl::instance()->editorManager();
849         QString fileName;
850         QByteArray id;
851         QByteArray editorState;
852         stream >> fileName >> id >> editorState;
853         IEditor *e = em->openEditor(view(), fileName, id, Core::EditorManager::IgnoreNavigationHistory
854                                     | Core::EditorManager::NoActivate);
855
856         if (!e) {
857             QModelIndex idx = em->openedEditorsModel()->firstRestoredEditor();
858             if (idx.isValid())
859                 em->activateEditorForIndex(view(), idx, Core::EditorManager::IgnoreNavigationHistory
860                                     | Core::EditorManager::NoActivate);
861         }
862
863         if (e) {
864             e->restoreState(editorState);
865             if (mode == "currenteditor")
866                 em->setCurrentEditor(e);
867         }
868     }
869 }