From 1c78e200c261f6a8d6561a00b190d36f4aada74b Mon Sep 17 00:00:00 2001
From: Friedemann Kleint <Friedemann.Kleint@nokia.com>
Date: Tue, 9 Mar 2010 15:48:01 +0100
Subject: [PATCH] Design mode/Qt Designer: clean-up Part II: Fix undo.

Re-introduce FormEditorFile that delegates dirty handling to the form
window. Change DesignerXmlEditable to be an IEditor that embeds
TextEditable so that the PlainTextEditor can work with it, but delegates
relevant functionality to FormEditorFile.
Centralize all form window creation code that was scattered around
in FormEditorW::createEditor() and have that return a struct Editor
data, which is passed to FormEditorStack.
Update the text editor only on open/createNew/switch away from design
mode.
---
 src/plugins/designer/designer.pro          |   3 +-
 src/plugins/designer/designercontext.cpp   |   1 +
 src/plugins/designer/designerxmleditor.cpp | 212 ++++++++++++++++++---
 src/plugins/designer/designerxmleditor.h   |  76 ++++++--
 src/plugins/designer/editordata.h          |  49 +++++
 src/plugins/designer/editorwidget.cpp      |   4 +-
 src/plugins/designer/editorwidget.h        |  10 +-
 src/plugins/designer/formeditorfactory.cpp |  22 ++-
 src/plugins/designer/formeditorfactory.h   |   1 -
 src/plugins/designer/formeditorstack.cpp   |  78 ++------
 src/plugins/designer/formeditorstack.h     |  27 ++-
 src/plugins/designer/formeditorw.cpp       |  32 +++-
 src/plugins/designer/formeditorw.h         |  10 +-
 src/plugins/designer/formwindoweditor.cpp  |  49 +----
 src/plugins/designer/formwindoweditor.h    |   8 -
 src/plugins/designer/formwindowfile.cpp    |  24 ++-
 src/plugins/designer/formwindowfile.h      |  12 +-
 17 files changed, 400 insertions(+), 218 deletions(-)
 create mode 100644 src/plugins/designer/editordata.h

diff --git a/src/plugins/designer/designer.pro b/src/plugins/designer/designer.pro
index d6054141647..9a28eb14b0d 100644
--- a/src/plugins/designer/designer.pro
+++ b/src/plugins/designer/designer.pro
@@ -39,7 +39,8 @@ HEADERS += formeditorplugin.h \
     designerxmleditor.h \
     designercontext.h \
     faketoolbar.h \
-    formeditorstack.h
+    formeditorstack.h \
+    editordata.h
 
 SOURCES += formeditorplugin.cpp \
         formeditorfactory.cpp \
diff --git a/src/plugins/designer/designercontext.cpp b/src/plugins/designer/designercontext.cpp
index 5a5a7b6bee0..7e28f1df689 100644
--- a/src/plugins/designer/designercontext.cpp
+++ b/src/plugins/designer/designercontext.cpp
@@ -36,6 +36,7 @@
 
 #include <QtGui/QWidget>
 #include <QtCore/QDebug>
+#include <QtCore/QSettings>
 
 enum { debug = 0 };
 
diff --git a/src/plugins/designer/designerxmleditor.cpp b/src/plugins/designer/designerxmleditor.cpp
index 96e52f1bcab..e6982bc917d 100644
--- a/src/plugins/designer/designerxmleditor.cpp
+++ b/src/plugins/designer/designerxmleditor.cpp
@@ -29,64 +29,157 @@
 
 #include "designerxmleditor.h"
 #include "designerconstants.h"
+#include "qt_private/formwindowbase_p.h"
+
 #include <coreplugin/editormanager/editormanager.h>
 #include <coreplugin/icore.h>
 #include <coreplugin/modemanager.h>
 #include <coreplugin/imode.h>
 #include <coreplugin/coreconstants.h>
 #include <coreplugin/uniqueidmanager.h>
-#include <QDebug>
+#include <texteditor/basetextdocument.h>
+
+#include <utils/qtcassert.h>
+
+#include <QtDesigner/QDesignerFormWindowInterface>
+
+#include <QtCore/QDebug>
+#include <QtCore/QFileInfo>
+#include <QtCore/QFile>
 
 namespace Designer {
-namespace Internal {
-DesignerXmlEditor::DesignerXmlEditor(QWidget *parent) : TextEditor::PlainTextEditor(parent)
+
+DesignerXmlEditorEditable::DesignerXmlEditorEditable(Internal::DesignerXmlEditor *editor,
+                                                     QDesignerFormWindowInterface *form,
+                                                     QObject *parent) :
+    Core::IEditor(parent),
+    m_textEditable(editor),
+    m_file(form)
 {
-    setReadOnly(true);
-    connect(Core::ICore::instance()->editorManager(), SIGNAL(currentEditorChanged(Core::IEditor*)),
-            SLOT(updateEditorInfoBar(Core::IEditor*)));
+    Core::UniqueIDManager *uidm = Core::UniqueIDManager::instance();
+    m_context << uidm->uniqueIdentifier(QLatin1String(Designer::Constants::K_DESIGNER_XML_EDITOR_ID));
+    m_context << uidm->uniqueIdentifier(QLatin1String(Designer::Constants::C_DESIGNER_XML_EDITOR));
+    connect(form, SIGNAL(changed()), this, SIGNAL(changed()));
+    // Revert to saved/load externally modified files
+    connect(&m_file, SIGNAL(reload(QString)), this, SLOT(slotOpen(QString)));
 }
 
-DesignerXmlEditor::~DesignerXmlEditor()
+bool DesignerXmlEditorEditable::createNew(const QString &contents)
 {
+    if (Designer::Constants::Internal::debug)
+        qDebug() << "DesignerXmlEditorEditable::createNew" << contents.size();
+
+    syncXmlEditor(QString());
+
+    QDesignerFormWindowInterface *form = m_file.formWindow();
+    QTC_ASSERT(form, return false);
+
+    if (contents.isEmpty())
+        return false;
 
+    form->setContents(contents);
+    if (form->mainContainer() == 0)
+        return false;
+
+    syncXmlEditor(contents);
+    m_file.setFileName(QString());
+    return true;
 }
 
-bool DesignerXmlEditor::open(const QString &fileName)
+void DesignerXmlEditorEditable::slotOpen(const QString &fileName)
 {
-    bool res = TextEditor::PlainTextEditor::open(fileName);
-    QPlainTextEdit::setReadOnly(true);
-    return res;
+    open(fileName);
 }
 
-void DesignerXmlEditor::updateEditorInfoBar(Core::IEditor *editor)
+bool DesignerXmlEditorEditable::open(const QString &fileName)
 {
-    if (editor == editableInterface()) {
-        Core::EditorManager::instance()->showEditorInfoBar(Constants::INFO_READ_ONLY,
-            tr("This file can only be edited in Design Mode."),
-            "Open Designer", this, SLOT(designerOpened()));
+    if (Designer::Constants::Internal::debug)
+        qDebug() << "DesignerXmlEditorEditable::open" << fileName;
+
+    QDesignerFormWindowInterface *form = m_file.formWindow();
+    QTC_ASSERT(form, return false);
+
+    if (fileName.isEmpty()) {
+        setDisplayName(tr("untitled"));
+        return true;
     }
-    if (!editor)
-        Core::EditorManager::instance()->hideEditorInfoBar(Constants::INFO_READ_ONLY);
+
+    const QFileInfo fi(fileName);
+    const QString absfileName = fi.absoluteFilePath();
+
+    QFile file(absfileName);
+    if (!file.open(QIODevice::ReadOnly|QIODevice::Text))
+        return false;
+
+    form->setFileName(absfileName);
+
+    const QString contents = QString::fromUtf8(file.readAll());
+    form->setContents(contents);
+    file.close();
+    if (!form->mainContainer())
+        return false;
+    form->setDirty(false);
+    syncXmlEditor(contents);
+
+    setDisplayName(fi.fileName());
+    m_file.setFileName(absfileName);
+
+    emit changed();
+
+    return true;
 }
 
-void DesignerXmlEditor::designerOpened()
+void DesignerXmlEditorEditable::syncXmlEditor()
 {
-    Core::ICore::instance()->modeManager()->activateMode(Core::Constants::MODE_DESIGN);
+    if (Designer::Constants::Internal::debug)
+        qDebug() << "DesignerXmlEditorEditable::syncXmlEditor" << m_file.fileName();
+    syncXmlEditor(contents());
 }
 
-} // namespace Internal
+void DesignerXmlEditorEditable::syncXmlEditor(const QString &contents)
+{
+    m_textEditable.editor()->setPlainText(contents);
+    m_textEditable.editor()->setReadOnly(true);
+}
+
+Core::IFile *DesignerXmlEditorEditable::file()
+{
+    return &m_file;
+}
 
 QString DesignerXmlEditorEditable::id() const
 {
     return QLatin1String(Designer::Constants::K_DESIGNER_XML_EDITOR_ID);
 }
 
-DesignerXmlEditorEditable::DesignerXmlEditorEditable(Internal::DesignerXmlEditor *editor)
-    : TextEditor::PlainTextEditorEditable(editor)
+QString DesignerXmlEditorEditable::displayName() const
 {
-    Core::UniqueIDManager *uidm = Core::UniqueIDManager::instance();
-    m_context << uidm->uniqueIdentifier(Designer::Constants::K_DESIGNER_XML_EDITOR_ID);
-    m_context << uidm->uniqueIdentifier(Designer::Constants::C_DESIGNER_XML_EDITOR);
+    return m_textEditable.displayName();
+}
+
+void DesignerXmlEditorEditable::setDisplayName(const QString &title)
+{
+    m_textEditable.setDisplayName(title);
+}
+
+bool DesignerXmlEditorEditable::duplicateSupported() const
+{
+    return false;
+}
+
+Core::IEditor *DesignerXmlEditorEditable::duplicate(QWidget *)
+{
+    return 0;
+}
+
+QByteArray DesignerXmlEditorEditable::saveState() const
+{
+    return m_textEditable.saveState();
+}
+
+bool DesignerXmlEditorEditable::restoreState(const QByteArray &state)
+{
+    return m_textEditable.restoreState(state);
 }
 
 QList<int> DesignerXmlEditorEditable::context() const
@@ -94,17 +187,78 @@ QList<int> DesignerXmlEditorEditable::context() const
     return m_context;
 }
 
-Core::IEditor *DesignerXmlEditorEditable::duplicate(QWidget *parent)
+QWidget *DesignerXmlEditorEditable::widget()
+{
+    return m_textEditable.widget();
+}
+
+bool DesignerXmlEditorEditable::isTemporary() const
+{
+    return false;
+}
+
+QWidget *DesignerXmlEditorEditable::toolBar()
 {
-    Q_UNUSED(parent);
     return 0;
 }
 
+QString DesignerXmlEditorEditable::contents() const
+{
+    const qdesigner_internal::FormWindowBase *fw = qobject_cast<const qdesigner_internal::FormWindowBase *>(m_file.formWindow());
+    QTC_ASSERT(fw, return QString());
+    return fw->fileContents(); // No warnings about spacers here
+}
+
+TextEditor::BaseTextDocument *DesignerXmlEditorEditable::textDocument()
+{
+    return qobject_cast<TextEditor::BaseTextDocument*>(m_textEditable.file());
+}
+
+TextEditor::PlainTextEditorEditable *DesignerXmlEditorEditable::textEditable()
+{
+    return &m_textEditable;
+}
+
 namespace Internal {
+
+DesignerXmlEditor::DesignerXmlEditor(QDesignerFormWindowInterface *form,
+                                     QWidget *parent) :
+    TextEditor::PlainTextEditor(parent),
+    m_editable(new DesignerXmlEditorEditable(this, form))
+{
+    setReadOnly(true);
+    connect(Core::EditorManager::instance(), SIGNAL(currentEditorChanged(Core::IEditor*)),
+             SLOT(updateEditorInfoBar(Core::IEditor*)));
+}
+
 TextEditor::BaseTextEditorEditable *DesignerXmlEditor::createEditableInterface()
 {
-    return new DesignerXmlEditorEditable(this);
+    if (Designer::Constants::Internal::debug)
+        qDebug() << "DesignerXmlEditor::createEditableInterface()";
+    return m_editable->textEditable();
 }
+
+void DesignerXmlEditor::updateEditorInfoBar(Core::IEditor *editor)
+{
+    if (editor == m_editable) {
+        Core::EditorManager::instance()->showEditorInfoBar(Constants::INFO_READ_ONLY,
+            tr("This file can only be edited in Design Mode."),
+            "Open Designer", this, SLOT(designerModeClicked()));
+    }
+    if (!editor)
+        Core::EditorManager::instance()->hideEditorInfoBar(Constants::INFO_READ_ONLY);
+}
+
+void DesignerXmlEditor::designerModeClicked()
+{
+    Core::ICore::instance()->modeManager()->activateMode(QLatin1String(Core::Constants::MODE_DESIGN));
+}
+
+DesignerXmlEditorEditable *DesignerXmlEditor::designerEditable() const
+{
+    return m_editable;
+}
+
 }
 } // namespace Designer
 
diff --git a/src/plugins/designer/designerxmleditor.h b/src/plugins/designer/designerxmleditor.h
index ce0b2abb897..d5f32ceedc9 100644
--- a/src/plugins/designer/designerxmleditor.h
+++ b/src/plugins/designer/designerxmleditor.h
@@ -31,58 +31,106 @@
 #define DESIGNERXMLEDITOR_H
 
 #include "designer_export.h"
+#include "formwindowfile.h"
+
 #include <texteditor/plaintexteditor.h>
-#include <texteditor/basetexteditor.h>
 
 namespace Core {
-    class IEditor;
     class IMode;
 }
 
+namespace TextEditor {
+    class BaseTextDocument;
+}
+
 namespace Designer {
 
 namespace Internal {
 class DesignerXmlEditor;
 }
 
-class DESIGNER_EXPORT DesignerXmlEditorEditable : public TextEditor::PlainTextEditorEditable
+// The actual Core::IEditor belonging to Qt Designer. It internally embeds
+// a TextEditor::PlainTextEditorEditable which is used to make the
+// Read-only edit mode XML text editor work and delegates some functionality
+// to it. However, the isDirty() handling is delegated to the FormWindowFile,
+// which is the Core::IFile used for it.
+class DESIGNER_EXPORT DesignerXmlEditorEditable : public Core::IEditor
 {
     Q_OBJECT
 public:
-    explicit DesignerXmlEditorEditable(Internal::DesignerXmlEditor *editor);
-    QList<int> context() const;
+    explicit DesignerXmlEditorEditable(Internal::DesignerXmlEditor *editor,
+                                       QDesignerFormWindowInterface *form,
+                                       QObject *parent = 0);
 
-    bool duplicateSupported() const { return false; }
-    Core::IEditor *duplicate(QWidget *parent);
+    // IEditor
+    virtual bool createNew(const QString &contents = QString());
+    virtual bool open(const QString &fileName = QString());
+    virtual Core::IFile *file();
     virtual QString id() const;
+    virtual QString displayName() const;
+    virtual void setDisplayName(const QString &title);
+
+    virtual bool duplicateSupported() const;
+    virtual IEditor *duplicate(QWidget *parent);
+
+    virtual QByteArray saveState() const;
+    virtual bool restoreState(const QByteArray &state);
+
+    virtual bool isTemporary() const;
+
+    virtual QWidget *toolBar();
+
+    // IContext
+    virtual QList<int> context() const;
+    virtual QWidget *widget();
+
+    // For uic code model support
+    QString contents() const;
+
+    TextEditor::BaseTextDocument *textDocument();
+    TextEditor::PlainTextEditorEditable *textEditable();
+
+public slots:
+    void syncXmlEditor();
+
+private slots:
+    void slotOpen(const QString &fileName);
 
 private:
+    void syncXmlEditor(const QString &contents);
+
+    TextEditor::PlainTextEditorEditable m_textEditable;
+    Internal::FormWindowFile m_file;
     QList<int> m_context;
 };
 
-/**
-  * A stub-like, read-only text editor which displays UI files as text. Could be used as a
+/* A stub-like, read-only text editor which displays UI files as text. Could be used as a
   * read/write editor too, but due to lack of XML editor, highlighting and other such
   * functionality, editing is disabled.
-  */
+  * Provides an informational title bar containing a button triggering a
+  * switch to design mode.
+  * Internally manages DesignerXmlEditorEditable and uses the plain text
+  * editable embedded in it.  */
 namespace Internal {
 
 class DesignerXmlEditor : public TextEditor::PlainTextEditor
 {
     Q_OBJECT
 public:
-    explicit DesignerXmlEditor(QWidget *parent = 0);
-    virtual ~DesignerXmlEditor();
-    bool open(const QString &fileName = QString());
+    explicit DesignerXmlEditor(QDesignerFormWindowInterface *form,
+                               QWidget *parent = 0);
+
+    DesignerXmlEditorEditable *designerEditable() const;
 
 private slots:
-    void designerOpened();
+    void designerModeClicked();
     void updateEditorInfoBar(Core::IEditor *editor);
 
 protected:
     virtual TextEditor::BaseTextEditorEditable *createEditableInterface();
 
 private:
+    DesignerXmlEditorEditable *m_editable;
 };
 
 } // Internal
diff --git a/src/plugins/designer/editordata.h b/src/plugins/designer/editordata.h
new file mode 100644
index 00000000000..661c8e20249
--- /dev/null
+++ b/src/plugins/designer/editordata.h
@@ -0,0 +1,49 @@
+/**************************************************************************
+**
+** This file is part of Qt Creator
+**
+** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
+**
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** Commercial Usage
+**
+** Licensees holding valid Qt Commercial licenses may use this file in
+** accordance with the Qt Commercial License Agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Nokia.
+**
+** GNU Lesser General Public License Usage
+**
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** If you are unsure which license is appropriate for your use, please
+** contact the sales department at http://qt.nokia.com/contact.
+**
+**************************************************************************/
+
+#ifndef EDITORDATA_H
+#define EDITORDATA_H
+
+namespace Designer {
+    class FormWindowEditor;
+    class DesignerXmlEditorEditable;
+
+namespace Internal {
+
+// Associates XML and its form editor
+struct EditorData {
+    EditorData() : xmlEditor(0), formEditor(0) {}
+    DesignerXmlEditorEditable *xmlEditor;
+    Designer::FormWindowEditor *formEditor;
+};
+
+} // namespace Internal
+} // namespace Designer
+
+#endif // EDITORDATA_H
diff --git a/src/plugins/designer/editorwidget.cpp b/src/plugins/designer/editorwidget.cpp
index 4459b263078..7e7ea571b57 100644
--- a/src/plugins/designer/editorwidget.cpp
+++ b/src/plugins/designer/editorwidget.cpp
@@ -92,9 +92,9 @@ QDockWidget* const* EditorWidget::designerDockWidgets() const
     return m_designerDockWidgets;
 }
 
-Designer::FormWindowEditor *EditorWidget::createFormWindowEditor(DesignerXmlEditorEditable *xmlEditor)
+void EditorWidget::add(const EditorData &d)
 {
-    return m_stack->createFormWindowEditor(xmlEditor);
+    m_stack->add(d);
 }
 
 bool EditorWidget::removeFormWindowEditor(Core::IEditor *xmlEditor)
diff --git a/src/plugins/designer/editorwidget.h b/src/plugins/designer/editorwidget.h
index 42c8e52a3eb..cf8041d2359 100644
--- a/src/plugins/designer/editorwidget.h
+++ b/src/plugins/designer/editorwidget.h
@@ -34,9 +34,6 @@
 
 #include <utils/fancymainwindow.h>
 
-#include <QtCore/QHash>
-#include <QtCore/QVariant>
-
 QT_BEGIN_NAMESPACE
 class QDesignerFormWindowInterface;
 QT_END_NAMESPACE
@@ -49,10 +46,11 @@ class FormWindowEditor;
 class DesignerXmlEditorEditable;
 
 namespace Internal {
+struct EditorData;
 class FormEditorStack;
 class FormEditorW;
-/* Form editor splitter used as editor window. Contains the shared designer
- * windows. */
+
+// Design mode main view.
 class EditorWidget : public Utils::FancyMainWindow
 {
     Q_OBJECT
@@ -63,7 +61,7 @@ public:
     QDockWidget* const* designerDockWidgets() const;
 
     // Form editor stack API
-    Designer::FormWindowEditor *createFormWindowEditor(DesignerXmlEditorEditable *xmlEditor);
+    void add(const EditorData &d);
     bool removeFormWindowEditor(Core::IEditor *xmlEditor);
     bool setVisibleEditor(Core::IEditor *xmlEditor);
     Designer::FormWindowEditor *formWindowEditorForXmlEditor(const Core::IEditor *xmlEditor) const;
diff --git a/src/plugins/designer/formeditorfactory.cpp b/src/plugins/designer/formeditorfactory.cpp
index 39cd429fb1f..5891741698f 100644
--- a/src/plugins/designer/formeditorfactory.cpp
+++ b/src/plugins/designer/formeditorfactory.cpp
@@ -30,32 +30,34 @@
 #include "formeditorfactory.h"
 #include "formeditorw.h"
 #include "formwindoweditor.h"
+#include "editordata.h"
 #include "designerconstants.h"
 #include "designerxmleditor.h"
 
 #include <coreplugin/icore.h>
 #include <coreplugin/fileiconprovider.h>
 #include <coreplugin/editormanager/editormanager.h>
-#include <texteditor/texteditorsettings.h>
 
 #include <QtCore/QFileInfo>
 #include <QtCore/QDebug>
 
-using namespace Designer::Internal;
 using namespace Designer::Constants;
 
+namespace Designer {
+namespace Internal {
+
 FormEditorFactory::FormEditorFactory()
   : Core::IEditorFactory(Core::ICore::instance()),
     m_mimeTypes(QLatin1String(FORM_MIMETYPE))
 {
     Core::FileIconProvider *iconProvider = Core::FileIconProvider::instance();
-    iconProvider->registerIconOverlayForSuffix(QIcon(":/formeditor/images/qt_ui.png"),
-                                        QLatin1String("ui"));
+    iconProvider->registerIconOverlayForSuffix(QIcon(QLatin1String(":/formeditor/images/qt_ui.png")),
+                                               QLatin1String("ui"));
 }
 
 QString FormEditorFactory::id() const
 {
-    return QLatin1String(DESIGNER_XML_EDITOR_ID); //FORMEDITOR_ID);
+    return QLatin1String(DESIGNER_XML_EDITOR_ID);
 }
 
 QString FormEditorFactory::displayName() const
@@ -71,12 +73,16 @@ Core::IFile *FormEditorFactory::open(const QString &fileName)
 
 Core::IEditor *FormEditorFactory::createEditor(QWidget *parent)
 {
-    DesignerXmlEditor *xmlEditor = new DesignerXmlEditor(parent);
-    TextEditor::TextEditorSettings::instance()->initializeEditor(xmlEditor);
-    return xmlEditor->editableInterface();
+    const EditorData data = FormEditorW::instance()->createEditor(parent);
+    return data.xmlEditor;
 }
 
 QStringList FormEditorFactory::mimeTypes() const
 {
     return m_mimeTypes;
 }
+
+} // namespace Internal
+} // namespace Designer
+
+
diff --git a/src/plugins/designer/formeditorfactory.h b/src/plugins/designer/formeditorfactory.h
index 1d8a8584aac..75c0db8778c 100644
--- a/src/plugins/designer/formeditorfactory.h
+++ b/src/plugins/designer/formeditorfactory.h
@@ -45,7 +45,6 @@ namespace Internal {
 class FormEditorFactory : public Core::IEditorFactory
 {
     Q_OBJECT
-
 public:
     FormEditorFactory();
 
diff --git a/src/plugins/designer/formeditorstack.cpp b/src/plugins/designer/formeditorstack.cpp
index 6d7198445b1..202c5fadaa8 100644
--- a/src/plugins/designer/formeditorstack.cpp
+++ b/src/plugins/designer/formeditorstack.cpp
@@ -33,28 +33,21 @@
 #include "formeditorw.h"
 #include "designerconstants.h"
 
-#include <texteditor/basetextdocument.h>
-
-#include <coreplugin/editormanager/editormanager.h>
-#include <coreplugin/icore.h>
+#include <coreplugin/coreconstants.h>
+#include <coreplugin/modemanager.h>
+#include <coreplugin/imode.h>
 
 #include <utils/qtcassert.h>
 
 #include <QDesignerFormWindowInterface>
 #include <QDesignerFormWindowManagerInterface>
 #include <QDesignerFormEditorInterface>
-#include "qt_private/formwindowbase_p.h"
 
 #include <QtCore/QDebug>
 
 namespace Designer {
 namespace Internal {
 
-FormEditorStack::FormXmlData::FormXmlData() :
-    xmlEditor(0), formEditor(0)
-{
-}
-
 FormEditorStack::FormEditorStack(QWidget *parent) :
     QStackedWidget(parent),
     m_designerCore(0)
@@ -62,28 +55,24 @@ FormEditorStack::FormEditorStack(QWidget *parent) :
     setObjectName(QLatin1String("FormEditorStack"));
 }
 
-Designer::FormWindowEditor *FormEditorStack::createFormWindowEditor(DesignerXmlEditorEditable *xmlEditor)
+void FormEditorStack::add(const EditorData &data)
 {
-    FormEditorW *few = FormEditorW::instance();
     if (m_designerCore == 0) { // Initialize first time here
-        m_designerCore = few->designerEditor();
+        m_designerCore = data.formEditor->formWindow()->core();
         connect(m_designerCore->formWindowManager(), SIGNAL(activeFormWindowChanged(QDesignerFormWindowInterface*)),
                 this, SLOT(updateFormWindowSelectionHandles()));
+        connect(Core::ModeManager::instance(), SIGNAL(currentModeAboutToChange(Core::IMode*)),
+                this, SLOT(modeAboutToChange(Core::IMode*)));
     }
-    FormXmlData data;
-    data.formEditor = few->createFormWindowEditor(this);
-    data.formEditor->setFile(xmlEditor->file());
-    data.xmlEditor = xmlEditor;
-    addWidget(data.formEditor);
-    m_formEditors.append(data);
 
-    setFormEditorData(data.formEditor, xmlEditor->contents());
+    if (Designer::Constants::Internal::debug)
+        qDebug() << "FormEditorStack::add"  << data.xmlEditor << data.formEditor;
+
+    m_formEditors.append(data);
+    addWidget(data.formEditor);
 
-    TextEditor::BaseTextDocument *document = qobject_cast<TextEditor::BaseTextDocument*>(xmlEditor->file());
-    connect(document, SIGNAL(reloaded()), SLOT(reloadDocument()));
     if (Designer::Constants::Internal::debug)
-        qDebug() << "FormEditorStack::createFormWindowEditor" << data.formEditor;
-    return data.formEditor;
+        qDebug() << "FormEditorStack::add" << data.formEditor;
 }
 
 int FormEditorStack::indexOf(const QDesignerFormWindowInterface *fw) const
@@ -125,7 +114,6 @@ bool FormEditorStack::removeFormWindowEditor(Core::IEditor *xmlEditor)
     const int i = indexOf(xmlEditor);
     if (i == -1) // Fail silently as this is invoked for all editors.
         return false;
-    disconnect(m_formEditors[i].formEditor->formWindow(), SIGNAL(changed()), this, SLOT(formChanged()));
     removeWidget(m_formEditors[i].formEditor->widget());
     delete m_formEditors[i].formEditor;
     m_formEditors.removeAt(i);
@@ -150,7 +138,7 @@ void FormEditorStack::updateFormWindowSelectionHandles()
     if (Designer::Constants::Internal::debug)
         qDebug() << "updateFormWindowSelectionHandles";
     QDesignerFormWindowInterface *activeFormWindow = m_designerCore->formWindowManager()->activeFormWindow();
-    foreach(const FormXmlData  &fdm, m_formEditors) {
+    foreach(const EditorData  &fdm, m_formEditors) {
         const bool active = activeFormWindow == fdm.formEditor->formWindow();
         fdm.formEditor->updateFormWindowSelectionHandles(active);
     }
@@ -162,39 +150,15 @@ Designer::FormWindowEditor *FormEditorStack::formWindowEditorForXmlEditor(const
     return i != -1 ? m_formEditors.at(i).formEditor : static_cast<Designer::FormWindowEditor *>(0);
 }
 
-void FormEditorStack::reloadDocument()
+void FormEditorStack::modeAboutToChange(Core::IMode *m)
 {
-    if (Designer::Constants::Internal::debug)
-        qDebug() << "FormEditorStack::reloadDocument()";
-    const int index = currentIndex();
-    if (index >= 0)
-        setFormEditorData(m_formEditors[index].formEditor, m_formEditors[index].xmlEditor->contents());
-}
+    if (Designer::Constants::Internal::debug && m)
+        qDebug() << "FormEditorStack::modeAboutToChange"  << m->id();
 
-void FormEditorStack::setFormEditorData(Designer::FormWindowEditor *formEditor, const QString &contents)
-{
-    if (Designer::Constants::Internal::debug)
-        qDebug() << "FormEditorStack::setFormEditorData()";
-    disconnect(formEditor->formWindow(), SIGNAL(changed()), this, SLOT(formChanged()));
-    formEditor->createNew(contents);
-    connect(formEditor->formWindow(), SIGNAL(changed()), SLOT(formChanged()));
-}
-
-void FormEditorStack::formChanged()
-{
-    const int index = currentIndex();
-    if (index < 0)
-        return;
-    if (Core::IEditor *currentEditor = Core::EditorManager::instance()->currentEditor()) {
-        if (m_formEditors[index].xmlEditor == currentEditor) {
-            FormXmlData &xmlData = m_formEditors[index];
-            TextEditor::BaseTextDocument *doc = qobject_cast<TextEditor::BaseTextDocument*>(xmlData.xmlEditor->file());
-            QTC_ASSERT(doc, return);
-            if (doc)   // Save quietly (without spacer's warning).
-                if (const qdesigner_internal::FormWindowBase *fwb = qobject_cast<const qdesigner_internal::FormWindowBase *>(xmlData.formEditor->formWindow()))
-                   doc->document()->setPlainText(fwb->fileContents());
-        }
-    }
+    // Sync the editor when leaving design mode
+    if (m && m->id() == QLatin1String(Core::Constants::MODE_DESIGN))
+        foreach(const EditorData &data, m_formEditors)
+            data.xmlEditor->syncXmlEditor();
 }
 
 } // Internal
diff --git a/src/plugins/designer/formeditorstack.h b/src/plugins/designer/formeditorstack.h
index 994a892c6c0..94513924e52 100644
--- a/src/plugins/designer/formeditorstack.h
+++ b/src/plugins/designer/formeditorstack.h
@@ -30,6 +30,8 @@
 #ifndef FORMEDITORSTACK_H
 #define FORMEDITORSTACK_H
 
+#include "editordata.h"
+
 #include <QtGui/QStackedWidget>
 #include <QtCore/QList>
 #include <QtCore/QString>
@@ -41,6 +43,7 @@ QT_END_NAMESPACE
 
 namespace Core {
     class IEditor;
+    class IMode;
 }
 
 namespace Designer {
@@ -49,11 +52,11 @@ class DesignerXmlEditorEditable;
 
 namespace Internal {
 
-/**
-  * A wrapper for Qt Designer form editors, so that they can be used in Design mode.
-  * FormEditorW owns an instance of this class, and creates new form editors when
-  * needed.
-  */
+/* FormEditorStack: Maintains a stack of Qt Designer form windows embedded
+ * into a scrollarea and their associated XML editors.
+ * Takes care of updating the XML editor once design mode is left.
+ * Also updates the maincontainer resize handles when the active form
+ * window changes. */
 class FormEditorStack : public QStackedWidget
 {
     Q_OBJECT
@@ -61,29 +64,23 @@ class FormEditorStack : public QStackedWidget
 public:
     explicit FormEditorStack(QWidget *parent = 0);
 
-    Designer::FormWindowEditor *createFormWindowEditor(DesignerXmlEditorEditable *xmlEditor);
+    void add(const EditorData &d);
     bool removeFormWindowEditor(Core::IEditor *xmlEditor);
+
     bool setVisibleEditor(Core::IEditor *xmlEditor);
     Designer::FormWindowEditor *formWindowEditorForXmlEditor(const Core::IEditor *xmlEditor) const;
     Designer::FormWindowEditor *formWindowEditorForFormWindow(const QDesignerFormWindowInterface *fw) const;
     FormWindowEditor *activeFormWindow() const;
 
 private slots:
-    void formChanged();
-    void reloadDocument();
     void updateFormWindowSelectionHandles();
+    void modeAboutToChange(Core::IMode *);
 
 private:
     inline int indexOf(const QDesignerFormWindowInterface *) const;
     inline int indexOf(const Core::IEditor *xmlEditor) const;
 
-    void setFormEditorData(Designer::FormWindowEditor *formEditor, const QString &contents);
-    struct FormXmlData {
-        FormXmlData();
-        DesignerXmlEditorEditable *xmlEditor;
-        Designer::FormWindowEditor *formEditor;
-    };
-    QList<FormXmlData> m_formEditors;
+    QList<EditorData> m_formEditors;
     QDesignerFormEditorInterface *m_designerCore;
 };
 
diff --git a/src/plugins/designer/formeditorw.cpp b/src/plugins/designer/formeditorw.cpp
index 98c2ea295bb..320be347a63 100644
--- a/src/plugins/designer/formeditorw.cpp
+++ b/src/plugins/designer/formeditorw.cpp
@@ -34,12 +34,12 @@
 #include "settingsmanager.h"
 #include "settingspage.h"
 #include "editorwidget.h"
+#include "editordata.h"
 #include "qtcreatorintegration.h"
 #include "designerxmleditor.h"
 #include "designercontext.h"
 #include "editorwidget.h"
 
-#include <texteditor/basetextdocument.h>
 #include <coreplugin/modemanager.h>
 #include <coreplugin/designmode.h>
 #include <coreplugin/coreconstants.h>
@@ -47,6 +47,7 @@
 #include <coreplugin/uniqueidmanager.h>
 #include <coreplugin/actionmanager/actionmanager.h>
 #include <coreplugin/editormanager/editormanager.h>
+#include <texteditor/texteditorsettings.h>
 #include <extensionsystem/pluginmanager.h>
 #include <utils/qtcassert.h>
 
@@ -213,7 +214,7 @@ FormEditorW::~FormEditorW()
     m_self = 0;
 }
 
-// Add an action to toggle the view state of a dock window
+// Add an actioon to toggle the view state of a dock window
 void FormEditorW::addDockViewAction(Core::ActionManager *am,
                                     int index, const QList<int> &context,
                                     const QString &title, const QString &id)
@@ -651,13 +652,27 @@ void FormEditorW::addToolAction(QAction *a,
     c1->addAction(command);
 }
 
-FormWindowEditor *FormEditorW::createFormWindowEditor(QWidget* parentWidget)
+EditorData FormEditorW::createEditor(QWidget *parent)
 {
+    if (Designer::Constants::Internal::debug)
+        qDebug() << "FormEditorW::createEditor";
+    // Create and associate form and text editor.
+    EditorData data;
     m_fwm->closeAllPreviews();
-    QDesignerFormWindowInterface *form = m_fwm->createFormWindow(0);
+    qdesigner_internal::FormWindowBase *form = qobject_cast<qdesigner_internal::FormWindowBase *>(m_fwm->createFormWindow(0));
+    QTC_ASSERT(form, return data);
     connect(form, SIGNAL(toolChanged(int)), this, SLOT(toolChanged(int)));
+    form->setDesignerGrid(qdesigner_internal::FormWindowBase::defaultDesignerGrid());
     qdesigner_internal::FormWindowBase::setupDefaultAction(form);
-    return new FormWindowEditor(form, parentWidget);
+    data.formEditor = new FormWindowEditor(form);
+    DesignerXmlEditor *xmlEditor = new DesignerXmlEditor(form, parent);
+    TextEditor::TextEditorSettings::instance()->initializeEditor(xmlEditor);
+    data.xmlEditor = xmlEditor->designerEditable();
+    data.formEditor->setFile(data.xmlEditor->file());
+    connect(data.formEditor, SIGNAL(formWindowSizeChanged(int,int)),
+            xmlEditor, SIGNAL(changed()));
+    m_editorWidget->add(data);
+    return data;
 }
 
 void FormEditorW::updateShortcut(QObject *command)
@@ -681,11 +696,8 @@ void FormEditorW::currentEditorChanged(Core::IEditor *editor)
         QTC_ASSERT(xmlEditor, return);
         ensureInitStage(FullyInitialized);
         FormWindowEditor *fw = m_editorWidget->formWindowEditorForXmlEditor(xmlEditor);
-        if (fw) {
-            m_editorWidget->setVisibleEditor(xmlEditor);
-        } else {
-            fw = m_editorWidget->createFormWindowEditor(xmlEditor);            
-        }
+        QTC_ASSERT(fw, return)
+        m_editorWidget->setVisibleEditor(xmlEditor);
         m_fwm->setActiveFormWindow(fw->formWindow());
         m_actionGroupEditMode->setVisible(true);
         m_modeActionSeparator->setVisible(true);
diff --git a/src/plugins/designer/formeditorw.h b/src/plugins/designer/formeditorw.h
index 51893429e5b..48617ab62fc 100644
--- a/src/plugins/designer/formeditorw.h
+++ b/src/plugins/designer/formeditorw.h
@@ -31,7 +31,6 @@
 #define FORMEDITORW_H
 
 #include <QtCore/QObject>
-#include <QtCore/QPointer>
 #include <QtCore/QStringList>
 #include <QtCore/QMap>
 
@@ -45,9 +44,6 @@ class QDesignerFormWindowInterface;
 
 class QAction;
 class QActionGroup;
-class QFocusEvent;
-
-class QWidget;
 class QSignalMapper;
 class QSettings;
 class QToolBar;
@@ -64,7 +60,6 @@ class ActionContainer;
 class ICore;
 class IEditor;
 class Command;
-class IMode;
 class DesignMode;
 }
 
@@ -73,6 +68,7 @@ class FormWindowEditor;
 
 namespace Internal {
 
+struct EditorData;
 class EditorWidget;
 class SettingsPage;
 class DesignerContext;
@@ -113,11 +109,11 @@ public:
     // Deletes an existing instance if there is one.
     static void deleteInstance();
 
+    EditorData createEditor(QWidget *parent);
+
     inline QDesignerFormEditorInterface *designerEditor() const { return m_formeditor; }
     inline QWidget * const*designerSubWindows() const { return m_designerSubWindows; }
 
-    FormWindowEditor *createFormWindowEditor(QWidget* parentWidget);
-
     FormWindowEditor *activeFormWindow() const;
 
 private slots:
diff --git a/src/plugins/designer/formwindoweditor.cpp b/src/plugins/designer/formwindoweditor.cpp
index bc43089985b..df6f9a2b219 100644
--- a/src/plugins/designer/formwindoweditor.cpp
+++ b/src/plugins/designer/formwindoweditor.cpp
@@ -96,26 +96,12 @@ FormWindowEditor::FormWindowEditor(QDesignerFormWindowInterface *form,
     m_sessionNode(0),
     m_sessionWatcher(0)
 {
-    connect(formWindow(), SIGNAL(selectionChanged()), this, SIGNAL(changed()));
     connect(this, SIGNAL(formWindowSizeChanged(int,int)), this, SLOT(slotFormSizeChanged(int,int)));
-    connect(formWindow(), SIGNAL(changed()), this, SIGNAL(changed()));
-
 }
 
 void FormWindowEditor::setFile(Core::IFile *file)
 {
-    if (m_file) {
-        disconnect(m_file, SIGNAL(changed()), this, SIGNAL(changed()));
-        disconnect(m_file, SIGNAL(changed()), this, SLOT(updateResources()));
-    }
-
-    m_file = file;
-    formWindow()->setFileName(file->fileName());
-
-    if (m_file) {
-        connect(m_file, SIGNAL(changed()), this, SIGNAL(changed()));
-        connect(m_file, SIGNAL(changed()), this, SLOT(updateResources()));
-    }
+     m_file = file;
 }
 
 FormWindowEditor::~FormWindowEditor()
@@ -127,26 +113,6 @@ FormWindowEditor::~FormWindowEditor()
     }
 }
 
-bool FormWindowEditor::createNew(const QString &contents)
-{
-    if (Designer::Constants::Internal::debug)
-        qDebug() << Q_FUNC_INFO << contents.size() << "chars";
-
-    if (!formWindow())
-        return false;
-
-    formWindow()->setContents(contents);
-    if (!formWindow()->mainContainer())
-        return false;
-
-    if (qdesigner_internal::FormWindowBase *fw = qobject_cast<qdesigner_internal::FormWindowBase *>(formWindow()))
-        fw->setDesignerGrid(qdesigner_internal::FormWindowBase::defaultDesignerGrid());
-
-    initializeResources();
-
-    return true;
-}
-
 void FormWindowEditor::initializeResources(const QString & /* fileName */)
 {
     ProjectExplorer::ProjectExplorerPlugin *pe = ProjectExplorer::ProjectExplorerPlugin::instance();
@@ -167,11 +133,6 @@ void FormWindowEditor::initializeResources(const QString & /* fileName */)
     }
 
     updateResources();
-
-    QDesignerFormWindowManagerInterface *fwm = FormEditorW::instance()->designerEditor()->formWindowManager();
-    fwm->setActiveFormWindow(formWindow());
-
-    emit changed();
 }
 
 void FormWindowEditor::updateResources()
@@ -202,13 +163,6 @@ Core::IFile *FormWindowEditor::file() const
     return m_file;
 }
 
-QString FormWindowEditor::contents() const
-{
-    if (!formWindow())
-        return QString();
-    return formWindow()->contents();
-}
-
 void FormWindowEditor::slotFormSizeChanged(int w, int h)
 {
     if (Designer::Constants::Internal::debug)
@@ -217,5 +171,4 @@ void FormWindowEditor::slotFormSizeChanged(int w, int h)
     formWindow()->setDirty(true);
     static const QString geometry = QLatin1String("geometry");
     FormEditorW::instance()->designerEditor()->propertyEditor()->setPropertyValue(geometry, QRect(0,0,w,h) );
-    emit changed();
 }
diff --git a/src/plugins/designer/formwindoweditor.h b/src/plugins/designer/formwindoweditor.h
index aeb59ef594f..20cccbe09c3 100644
--- a/src/plugins/designer/formwindoweditor.h
+++ b/src/plugins/designer/formwindoweditor.h
@@ -30,7 +30,6 @@
 #ifndef FORMWINDOWEDITOR_H
 #define FORMWINDOWEDITOR_H
 
-#include "designer_export.h"
 #include "widgethost.h"
 
 #include <QtCore/QStringList>
@@ -58,15 +57,10 @@ public:
                               QWidget *parent = 0);
     ~FormWindowEditor();
 
-    // IEditor
-    bool createNew(const QString &contents);
     void setFile(Core::IFile *file);
     QString contents() const;
     Core::IFile *file() const;
 
-signals:
-    void changed();
-
 private slots:
     void updateResources();
     void slotFormSizeChanged(int w, int h);
@@ -74,8 +68,6 @@ private slots:
 private:
     void initializeResources(const QString &fileName = QString());
 
-    QWidget *m_containerWidget;
-    QString m_displayName;
     QPointer<Core::IFile> m_file;
     QStringList m_originalUiQrcPaths;
     ProjectExplorer::SessionNode *m_sessionNode;
diff --git a/src/plugins/designer/formwindowfile.cpp b/src/plugins/designer/formwindowfile.cpp
index 15bac0bbd09..2cd65a1848b 100644
--- a/src/plugins/designer/formwindowfile.cpp
+++ b/src/plugins/designer/formwindowfile.cpp
@@ -31,8 +31,8 @@
 #include "designerconstants.h"
 
 #include <coreplugin/icore.h>
-#include <coreplugin/editormanager/editormanager.h>
 #include <utils/reloadpromptutils.h>
+#include <utils/qtcassert.h>
 
 #include <QtDesigner/QDesignerFormWindowInterface>
 #include <QtDesigner/QDesignerFormEditorInterface>
@@ -42,17 +42,15 @@
 
 #include <QtCore/QFile>
 #include <QtCore/QFileInfo>
-#include <QtCore/QDir>
 #include <QtCore/QByteArray>
 #include <QtCore/QDebug>
 
-using namespace Designer::Internal;
-using namespace Designer::Constants;
-using namespace SharedTools;
+namespace Designer {
+namespace Internal {
 
 FormWindowFile::FormWindowFile(QDesignerFormWindowInterface *form, QObject *parent)
   : Core::IFile(parent),
-    m_mimeType(QLatin1String(FORM_MIMETYPE)),
+    m_mimeType(QLatin1String(Designer::Constants::FORM_MIMETYPE)),
     m_formWindow(form)
 {
 }
@@ -64,6 +62,8 @@ bool FormWindowFile::save(const QString &name /*= QString()*/)
     if (Designer::Constants::Internal::debug)
         qDebug() << Q_FUNC_INFO << name << "->" << actualName;
 
+    QTC_ASSERT(m_formWindow, return false);
+
     if (actualName.isEmpty())
         return false;
 
@@ -94,9 +94,9 @@ QString FormWindowFile::fileName() const
 
 bool FormWindowFile::isModified() const
 {
-    if (Designer::Constants::Internal::debug)
+    if (Designer::Constants::Internal::debug > 1)
         qDebug() << Q_FUNC_INFO << m_formWindow->isDirty();
-    return m_formWindow->isDirty();
+    return m_formWindow && m_formWindow->isDirty();
 }
 
 bool FormWindowFile::isReadOnly() const
@@ -204,3 +204,11 @@ void FormWindowFile::setFileName(const QString &fname)
 {
     m_fileName = fname;
 }
+
+QDesignerFormWindowInterface *FormWindowFile::formWindow() const
+{
+    return m_formWindow;
+}
+
+} // namespace Internal
+} // namespace Designer
diff --git a/src/plugins/designer/formwindowfile.h b/src/plugins/designer/formwindowfile.h
index 873bdb98bcd..e04d74a2a2e 100644
--- a/src/plugins/designer/formwindowfile.h
+++ b/src/plugins/designer/formwindowfile.h
@@ -32,8 +32,7 @@
 
 #include <coreplugin/ifile.h>
 
-#include "widgethost.h"
-#include "designerconstants.h"
+#include <QtCore/QPointer>
 
 QT_BEGIN_NAMESPACE
 class QDesignerFormWindowInterface;
@@ -65,9 +64,12 @@ public:
 
     // Internal
     void setSuggestedFileName(const QString &fileName);
+
     bool writeFile(const QString &fileName, QString &errorString) const;
     bool writeFile(QFile &file, QString &errorString) const;
 
+    QDesignerFormWindowInterface *formWindow() const;
+
 signals:
     // Internal
     void reload(const QString &);
@@ -78,10 +80,12 @@ public slots:
 
 private:
     const QString m_mimeType;
+
     QString m_fileName;
     QString m_suggestedName;
-
-    QDesignerFormWindowInterface *m_formWindow;
+    // Might actually go out of scope before the IEditor due
+    // to deleting the WidgetHost which owns it.
+    QPointer<QDesignerFormWindowInterface> m_formWindow;
 };
 
 } // namespace Internal
-- 
GitLab