From 5dd5f367dfcecab75077c3cb4ca1f01113fc1561 Mon Sep 17 00:00:00 2001
From: =?utf8?q?Enar=20V=C3=A4ikene?= <enar@vaikene.net>
Date: Thu, 1 Dec 2011 16:08:19 +0200
Subject: [PATCH] In the process of creating a more generic document interface
 manager (or window manager) interface. * Now adds panels instead of windows -
 one becomes part of the main windows; others act as separate windows. * Can
 manage multiple windows   - when the main window is closed, closes all the
 other managed windows;   - when the main window is minimized/restores, does
 the same for all the other managed windows. * XML file attribute
 'mainPanelName' is used to set the main panel; if no attribute is set, uses
 the first panel. * Panels can be deleted externally; a garbage collector
 makes sure that the list of managed windows does not grow   forever if
 somebody decides to add/delete millions of panels.

---
 src/plugins/SdiWindow/isdiwindow.h  |  31 ++++-
 src/plugins/SdiWindow/sdiwindow.cpp | 199 +++++++++++++++++++++++-----
 src/plugins/SdiWindow/sdiwindow.h   |  45 ++++++-
 src/plugins/SdiWindow/version.h     |   4 +-
 4 files changed, 238 insertions(+), 41 deletions(-)

diff --git a/src/plugins/SdiWindow/isdiwindow.h b/src/plugins/SdiWindow/isdiwindow.h
index 13b9903..4e0e43d 100644
--- a/src/plugins/SdiWindow/isdiwindow.h
+++ b/src/plugins/SdiWindow/isdiwindow.h
@@ -31,7 +31,7 @@ class QLayout;
 namespace eVaf {
 
 namespace Gui {
-    class Window;
+    class Panel;
 } // namespace eVaf::Gui
 
 namespace SdiWindow {
@@ -54,12 +54,33 @@ struct SDIWINDOW_EXPORT iSdiWindow
     static iSdiWindow * instance();
 
     /**
-     * Adds the window to the main SDI window
-     * @param window The window
+     * Adds a panel to the SDI window manager
+     * @param name Name of the panel
+     * @param panel The panel
      *
-     * This function adds a window to the main SDI layout.
+     * This function adds a panel to the SDI window manager. The ownership of the panel
+     * is transferred to the window manager and it is the responsibility of the window
+     * manager to delete it.
      */
-    virtual void addWindow(Gui::Window * window) = 0;
+    virtual void addPanel(QString const & name, Gui::Panel * panel) = 0;
+
+    /**
+     * Returns a panel by the name
+     * @param name Name of the panel
+     * @return Pointer to the panel or 0 if failed
+     *
+     * This function returns a panel identified by the name.
+     */
+    virtual Gui::Panel * panel(QString const & name) const = 0;
+
+    /**
+     * Shows a panel
+     * @param name Name of the panel
+     * @return True if succeeded; false if not
+     *
+     * This function shows the panel.
+     */
+    virtual bool showPanel(QString const & name) = 0;
 
 };
 
diff --git a/src/plugins/SdiWindow/sdiwindow.cpp b/src/plugins/SdiWindow/sdiwindow.cpp
index aa264de..c0e3587 100644
--- a/src/plugins/SdiWindow/sdiwindow.cpp
+++ b/src/plugins/SdiWindow/sdiwindow.cpp
@@ -23,8 +23,10 @@
 #include <Common/iLogger>
 #include <Common/iRegistry>
 #include <Common/iApp>
+#include <Common/iProp>
 
 #include <QtGui>
+#include <QXmlStreamReader>
 
 namespace eVaf {
 namespace SdiWindow {
@@ -40,28 +42,25 @@ using namespace eVaf;
 
 //-------------------------------------------------------------------
 
-using namespace eVaf::SdiWindow;
-
-iSdiWindow * iSdiWindow::instance()
+SdiWindow::iSdiWindow * SdiWindow::iSdiWindow::instance()
 {
-    return Internal::mSdiWindow;
+    return SdiWindow::Internal::mSdiWindow;
 }
 
 
 //-------------------------------------------------------------------
 
-using namespace eVaf::SdiWindow::Internal;
-
-MainWindow::MainWindow(QWidget * parent, Qt::WindowFlags flags)
+SdiWindow::Internal::MainWindow::MainWindow(QWidget * parent, Qt::WindowFlags flags)
     : QWidget(parent, flags)
     , mReady(false)
+    , mTimerId(0)
 {
     setObjectName(QString("%1-%2").arg(VER_MODULE_NAME_STR).arg(__FUNCTION__));
 
     // Restore geometry
     restoreSettings();
 
-    // Apply the size specified in a) properties; or b) on the command line
+    // Apply the size specified in a) properties; or b) on the command line (overwrites stored geometry)
     setWindowSize();
 
     // Create the default layout
@@ -73,7 +72,7 @@ MainWindow::MainWindow(QWidget * parent, Qt::WindowFlags flags)
     EVAF_INFO("%s created", qPrintable(objectName()));
 }
 
-MainWindow::~MainWindow()
+SdiWindow::Internal::MainWindow::~MainWindow()
 {
     mSdiWindow = 0;
 
@@ -83,14 +82,30 @@ MainWindow::~MainWindow()
     EVAF_INFO("%s destroyed", qPrintable(objectName()));
 }
 
-bool MainWindow::init(QString const & args)
+QString SdiWindow::Internal::MainWindow::getMainPanelName(QString const & args) const
+{
+    QXmlStreamReader xml(args);
+    while (!xml.atEnd()) {
+        xml.readNext();
+        if (xml.isStartElement() && xml.name() == "attributes") {
+            if (xml.attributes().hasAttribute("mainPanelName"))
+                return xml.attributes().value("mainPanelName").toString();
+        }
+    }
+    return QString();
+}
+
+bool SdiWindow::Internal::MainWindow::init(QString const & args)
 {
-    Q_UNUSED(args);
+    mMainPanelName = getMainPanelName(args);
 
     Common::iRegistry::instance()->registerInterface("iSdiWindow", this);
 
     setWindowTitle(Common::iApp::instance()->name());
 
+    // Start the garbage collector timer
+    mTimerId = startTimer(60 * 1000);
+
     show();
 
     mReady = true;
@@ -100,29 +115,73 @@ bool MainWindow::init(QString const & args)
     return true;
 }
 
-void MainWindow::done()
+void SdiWindow::Internal::MainWindow::done()
 {
     mReady = false;
 
     close();
 
-    // Delete the window
-    if (mWindow)
-        delete mWindow.data();
+    if (mTimerId) {
+        killTimer(mTimerId);
+        mTimerId = 0;
+    }
+
+    // Delete all the panels
+    for (int i = mPanels.size() - 1; i >= 0; --i) {
+        QWeakPointer<Gui::Panel> p = mPanels.at(i);
+        if (p)
+            delete p.data();
+    }
+    mPanels.clear();
+    mMinimizedPanels.clear();
+    mPanelNames.clear();
+    mMainPanel.clear();
+    mMainPanelName.clear();
 
     EVAF_INFO("%s finalized", qPrintable(objectName()));
 }
 
-void MainWindow::addWindow(Gui::Window * window)
+void SdiWindow::Internal::MainWindow::addPanel(QString const & name, Gui::Panel * panel)
+{
+    mPanels.append(panel);
+    mPanelNames.insert(name, panel);
+
+    // If this is the predefined main panel, add it to this window
+    if (!mMainPanelName.isEmpty()) {
+        if (name == mMainPanelName) {
+            mMainPanel = panel;
+            mLayout->addWidget(panel);
+        }
+    }
+
+    // If the predefined main panel name is not set, use the first panel
+    else {
+        if (!mMainPanel) {
+            mMainPanel = panel;
+            mLayout->addWidget(panel);
+        }
+    }
+}
+
+Gui::Panel * SdiWindow::Internal::MainWindow::panel(QString const & name) const
+{
+    QHash<QString, QWeakPointer<Gui::Panel> >::const_iterator it = mPanelNames.constFind(name);
+    if (it != mPanelNames.constEnd())
+        return it.value().data();
+    return 0;
+}
+
+bool SdiWindow::Internal::MainWindow::showPanel(QString const & name)
 {
-    // Delete the existing window
-    if (mWindow)
-        delete mWindow.data();
-    mLayout->addWidget(window);
-    mWindow = window;
+    Gui::Panel * p = panel(name);
+    if (p) {
+        p->show();
+        return true;
+    }
+    return false;
 }
 
-void MainWindow::saveSettings()
+void SdiWindow::Internal::MainWindow::saveSettings()
 {
     static int ver[4] = {VER_FILE_VERSION};
     QSettings settings(VER_COMPANY_NAME_STR, Common::iApp::instance()->name());
@@ -131,7 +190,7 @@ void MainWindow::saveSettings()
     settings.setValue(QString("%1/geometry").arg(objectName()), saveGeometry());
 }
 
-void MainWindow::restoreSettings()
+void SdiWindow::Internal::MainWindow::restoreSettings()
 {
     static int ver[4] = {VER_FILE_VERSION};
     QSettings settings(VER_COMPANY_NAME_STR, Common::iApp::instance()->name());
@@ -149,11 +208,11 @@ void MainWindow::restoreSettings()
     restoreGeometry(settings.value(QString("%1/geometry").arg(objectName())).toByteArray());
 }
 
-void MainWindow::setWindowSize()
+void SdiWindow::Internal::MainWindow::setWindowSize()
 {
     // a) Get window size from properties
-    int w = 0;
-    int h = 0;
+    int w = Common::iProp::instance()->getValue("windowWidth", 0).toInt();
+    int h = Common::iProp::instance()->getValue("windowHeight", 0).toInt();
 
     // b) Use command line arguments
     QStringList args = QApplication::arguments();
@@ -184,10 +243,90 @@ void MainWindow::setWindowSize()
     }
 }
 
+void SdiWindow::Internal::MainWindow::closeEvent(QCloseEvent * e)
+{
+    // Try to close all the managed panels; ignore the event if one of the managed panels refuses to close
+    foreach (QWeakPointer<Gui::Panel> p, mPanels) {
+        if (p) {
+            if (!p.data()->close()) {
+                e->ignore();
+                return;
+            }
+        }
+    }
+
+    QWidget::closeEvent(e);
+}
+
+void SdiWindow::Internal::MainWindow::changeEvent(QEvent * e)
+{
+    if (e->type() == QEvent::WindowStateChange) {
+        QWindowStateChangeEvent * wse = static_cast<QWindowStateChangeEvent *>(e);
+
+        if (windowState() == Qt::WindowNoState && wse->oldState() == Qt::WindowMinimized) {
+
+            // Restore all the managed panels that were previously minimized
+            foreach (QWeakPointer<Gui::Panel> p, mMinimizedPanels) {
+                if (p && p.data()->isVisible())
+                    p.data()->showNormal();
+            }
+            mMinimizedPanels.clear();
+        }
+
+        else if (windowState() == Qt::WindowMinimized && wse->oldState() != Qt::WindowMinimized) {
+
+            // Minimize all the managed panels that are not minimized yet
+            mMinimizedPanels.clear();
+            foreach (QWeakPointer<Gui::Panel> p, mPanels) {
+                if (!p)
+                    continue;
+
+                if (p.data()->windowState() != Qt::WindowMinimized && p.data()->isVisible()) {
+                    mMinimizedPanels.append(p);
+                    p.data()->showMinimized();
+                }
+            }
+        }
+    }
+    QWidget::changeEvent(e);
+}
+
+void SdiWindow::Internal::MainWindow::timerEvent(QTimerEvent * e)
+{
+    if (e->timerId() == mTimerId) {
+
+        // Remove panels that are deleted
+        {
+            QList<QWeakPointer<Gui::Panel> >::iterator it = mPanels.begin();
+            while (it != mPanels.end()) {
+                QWeakPointer<Gui::Panel> p = *it;
+                if (!p)
+                    it = mPanels.erase(it);
+                else
+                    ++it;
+            }
+        }
+
+        // Do the same with panel names
+        {
+            QHash<QString, QWeakPointer<Gui::Panel> >::iterator it = mPanelNames.begin();
+            while (it != mPanelNames.end()) {
+                QWeakPointer<Gui::Panel> p = it.value();
+                if (!p)
+                    it = mPanelNames.erase(it);
+                else
+                    ++it;
+            }
+        }
+    }
+    else
+        QWidget::timerEvent(e);
+}
+
 
 //-------------------------------------------------------------------
 
-SdiWindowPlugin::SdiWindowPlugin()
+SdiWindow::Internal::SdiWindowPlugin::SdiWindowPlugin()
     : Plugins::iPlugin()
 {
     setObjectName(VER_MODULE_NAME_STR);
@@ -197,14 +336,14 @@ SdiWindowPlugin::SdiWindowPlugin()
     EVAF_INFO("%s created", qPrintable(objectName()));
 }
 
-SdiWindowPlugin::~SdiWindowPlugin()
+SdiWindow::Internal::SdiWindowPlugin::~SdiWindowPlugin()
 {
     delete mWindow;
 
     EVAF_INFO("%s destroyed", qPrintable(objectName()));
 }
 
-bool SdiWindowPlugin::init(const QString & args)
+bool SdiWindow::Internal::SdiWindowPlugin::init(const QString & args)
 {
     if (!mWindow->init(args))
         return false;
@@ -214,7 +353,7 @@ bool SdiWindowPlugin::init(const QString & args)
     return true;
 }
 
-void SdiWindowPlugin::done()
+void SdiWindow::Internal::SdiWindowPlugin::done()
 {
     mWindow->done();
 
diff --git a/src/plugins/SdiWindow/sdiwindow.h b/src/plugins/SdiWindow/sdiwindow.h
index f884255..757ed28 100644
--- a/src/plugins/SdiWindow/sdiwindow.h
+++ b/src/plugins/SdiWindow/sdiwindow.h
@@ -23,12 +23,14 @@
 #include "isdiwindow.h"
 
 #include <Plugins/iPlugin>
-#include <Gui/Window>
+#include <Gui/Panel>
 
 #include <QObject>
 #include <QString>
 #include <QWidget>
 #include <QList>
+#include <QVector>
+#include <QHash>
 #include <QWeakPointer>
 
 class QVBoxLayout;
@@ -57,7 +59,21 @@ public:
 
     virtual bool isReady() { return mReady; }
 
-    virtual void addWindow(Gui::Window * window);
+    virtual void addPanel(QString const & name, Gui::Panel * panel);
+
+    virtual Gui::Panel * panel(QString const & name) const;
+
+    virtual bool showPanel(QString const & name);
+
+    virtual void changeEvent(QEvent * e);
+
+    virtual void closeEvent(QCloseEvent * e);
+
+
+protected: // Methods
+
+    /// Garbage collector timer
+    virtual void timerEvent(QTimerEvent * e);
 
 
 private: // Methods
@@ -77,8 +93,29 @@ private: // Members
     /// The layout of the main window
     QVBoxLayout * mLayout;
 
-    /// eVaf GUI window implementing the main window
-    QWeakPointer<Gui::Window> mWindow;
+    /// Name of the main panel that becomes part of this window
+    QString mMainPanelName;
+
+    /// List of GUI::Panel objects added to the manager
+    QList<QWeakPointer<Gui::Panel> > mPanels;
+
+    /// List of minimized GUI::Panel objects
+    QVector<QWeakPointer<Gui::Panel> > mMinimizedPanels;
+
+    /// Hash with panel names
+    QHash<QString, QWeakPointer<Gui::Panel> > mPanelNames;
+
+    /// Current main panel added to this window
+    QWeakPointer<Gui::Panel> mMainPanel;
+
+    /// Garbage collector timer ID
+    int mTimerId;
+
+
+private: // Methods
+
+    /// Gets the main panel name from module attributes
+    QString getMainPanelName(QString const & args) const;
 
 };
 
diff --git a/src/plugins/SdiWindow/version.h b/src/plugins/SdiWindow/version.h
index f3fedec..c47549d 100644
--- a/src/plugins/SdiWindow/version.h
+++ b/src/plugins/SdiWindow/version.h
@@ -25,12 +25,12 @@
 /**
  * Module/library version number in the form major,minor,release,build
  */
-#define VER_FILE_VERSION                0,3,1,6
+#define VER_FILE_VERSION                0,4,1,7
 
 /**
  * Module/library version number in the string format (shall end with \0)
  */
-#define VER_FILE_VERSION_STR            "0.3.1.6\0"
+#define VER_FILE_VERSION_STR            "0.4.1.7\0"
 
 /**
  * Module/library name (shall end with \0)
-- 
2.49.0