MDIApplication Example

#include <QApplication>
#include <QScreen>
#include <QSignalMapper>
#include <QTabBar>
#include <QMdiSubWindow>
#include <QFileDialog>
#include <QPainter>
#include <QButtonGroup>
#include <QCheckBox>
#include <QRadioButton>
#include <QSettings>

#include "mainwindow.h"
#include "texteditchild.h"
#include "sketchchild.h"
#include "aboutdialog.h"

/* ManagerRibbon */
MainWindow::MainWindow()
    : DemoRibbonWindow(Q_NULL)
{
    m_typeDocCurrent = ChildInterface::td_None;
    m_childCurrent = Q_NULL;
    m_mdiArea = new QMdiArea(this);
#if (QT_VERSION >= QT_VERSION_CHECK(4, 8, 0))
    m_mdiArea->setTabsClosable(true);
#endif
    m_mdiArea->setLineWidth(3);
    m_mdiArea->setFrameShape(QFrame::Panel);
    m_mdiArea->setFrameShadow(QFrame::Sunken);

    m_mdiArea->setViewMode(QMdiArea::TabbedView);
    qApp->installEventFilter(this);

    m_mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    m_mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    setCentralWidget(m_mdiArea);

    connect(m_mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(updateMenus()));
    connect(m_mdiArea, SIGNAL(subWindowActivated(QMdiSubWindow*)), this, SLOT(subWindowActivated(QMdiSubWindow*)));

    m_windowMapper = new QSignalMapper(this);
    connect(m_windowMapper, SIGNAL(mapped(QWidget*)), this, SLOT(setActiveSubWindow(QWidget*)));

    createActions();
    createMenuFile();
    createRibbon();
    createStatusBar();
    updateMenus();

    setWindowTitle(tr("Ribbon MDI"));
    setUnifiedTitleAndToolBarOnMac(true);
    setFrameThemeEnabled(true);
    m_stateWindow = windowState();
    setDefaultWidgetGeometry(this);

    RibbonCustomizeManager* customizeManager = ribbonBar()->customizeManager();
    customizeManager->setDefaultState(); //Make a default state-point for ribbon-ui elements.

    readSettings();
}

MainWindow::~MainWindow()
{
    writeSettings();
}

bool MainWindow::eventFilter(QObject* obj, QEvent* event)
{
    switch(event->type())
    {
        case QEvent::ChildRemoved :
            if (QChildEvent* pEvent= static_cast<QChildEvent*>(event))
            {
                if (qobject_cast<QMdiSubWindow*>(pEvent->child()) && m_childCurrent && m_mdiArea->subWindowList().size() == 1)
                {
                    if (ChildInterface* ifOldChild = qobject_cast<ChildInterface*>(m_childCurrent))
                        ifOldChild->removeUserInterface(ribbonBar(), statusBar(), Q_NULL);

                    m_childCurrent = Q_NULL;
                    m_typeDocCurrent = ChildInterface::td_None;
                }
            }
            break;
        default:
            break;
    }
    return RibbonMainWindow::eventFilter(obj, event);
}

void MainWindow::closeEvent(QCloseEvent* event)
{
    m_mdiArea->closeAllSubWindows();
    if (m_mdiArea->currentSubWindow())
    {
        event->ignore();
    }
    else
    {
        event->accept();
    }
}

void MainWindow::newTextFile()
{
    TextEditChild* child = createMdiTextChild();
    child->newFile();
    child->show();
}

void MainWindow::newSketchFile()
{
    SketchChild* child = createSketchChild();
    child->newFile();
    child->show();
}

void MainWindow::open()
{
    QString fileName = QFileDialog::getOpenFileName(this);
    if (!fileName.isEmpty())
    {
        QMdiSubWindow* existing = findMdiChild(fileName);
        if (existing)
        {
            m_mdiArea->setActiveSubWindow(existing);
            return;
        }

        TextEditChild* child = createMdiTextChild();
        if (child->loadFile(fileName))
        {
            statusBar()->showMessage(tr("File loaded"), 2000);
            child->show();
        }
        else
        {
            child->close();
        }
    }
}

void MainWindow::save()
{
    ChildInterface* ifChild = qobject_cast<ChildInterface*>(activeMdiChild());
    if (ifChild && ifChild->save())
        statusBar()->showMessage(tr("File saved"), 2000);
}

void MainWindow::saveAs()
{
    ChildInterface* ifChild = qobject_cast<ChildInterface*>(activeMdiChild());
    if (ifChild && ifChild->saveAs())
        statusBar()->showMessage(tr("File saved"), 2000);
}

void MainWindow::cut()
{
    TextEditChild* txtChild = qobject_cast<TextEditChild*>(activeMdiChild());
    if (txtChild)
        txtChild->cut();
}

void MainWindow::copy()
{
    TextEditChild* txtChild = qobject_cast<TextEditChild*>(activeMdiChild());
    if (txtChild)
        txtChild->copy();
}

void MainWindow::paste()
{
    TextEditChild* txtChild = qobject_cast<TextEditChild*>(activeMdiChild());
    if (txtChild)
        txtChild->paste();
}

void MainWindow::updateMenus()
{
    bool hasMdiChild = (activeMdiChild() != Q_NULL);
    m_saveAct->setEnabled(hasMdiChild);
    m_saveAsAct->setEnabled(hasMdiChild);
    m_closeAct->setEnabled(hasMdiChild);
    m_closeAllAct->setEnabled(hasMdiChild);
    m_cascadeAct->setEnabled(hasMdiChild);
    m_nextAct->setEnabled(hasMdiChild);
    m_previousAct->setEnabled(hasMdiChild);
}

void MainWindow::updateWindowMenu()
{
    m_windowMenu->clear();
    QList<QMdiSubWindow*> windows = m_mdiArea->subWindowList();

    for (int i = 0; i < windows.size(); ++i)
    {
        QWidget* child = windows.at(i)->widget();
        if(!child)
            continue;

        ChildInterface* ifChild = qobject_cast<ChildInterface*>(child);
        if(!ifChild)
            continue;

        QString text;
        if (i < 9)
            text = tr("&%1 %2").arg(i + 1).arg(ifChild->userFriendlyCurrentFile());
        else
            text = tr("%1 %2").arg(i + 1).arg(ifChild->userFriendlyCurrentFile());

        QAction* action  = m_windowMenu->addAction(text);
        action->setCheckable(true);
        action ->setChecked(child == activeMdiChild());
        connect(action, SIGNAL(triggered()), m_windowMapper, SLOT(map()));
        m_windowMapper->setMapping(action, windows.at(i));
    }
}

TextEditChild* MainWindow::createMdiTextChild()
{
    TextEditChild* child = new TextEditChild;
    m_mdiArea->addSubWindow(child);
    return child;
}

SketchChild* MainWindow::createSketchChild()
{
    SketchChild* pChild = new SketchChild();
    Q_ASSERT(pChild != Q_NULL);
    QMdiSubWindow* subChild = m_mdiArea->addSubWindow(pChild);
    Q_ASSERT(subChild != Q_NULL);
    Q_UNUSED(subChild);
    return pChild;
}

void MainWindow::createActions()
{
    m_newTextAct = new QAction(QIcon(QStringLiteral(":/res/textedit.png")), tr("&Text Edit"), this);
    m_newTextAct->setStatusTip(tr("Create a new file"));
    connect(m_newTextAct, SIGNAL(triggered()), this, SLOT(newTextFile()));

    m_newSketchAct = new QAction(QIcon(QStringLiteral(":/res/sketch.png")), tr("&Skcetch Edit"), this);
    m_newSketchAct->setStatusTip(tr("Create a new file"));
    connect(m_newSketchAct, SIGNAL(triggered()), this, SLOT(newSketchFile()));

    m_openAct = new QAction(QIcon(QStringLiteral(":/res/open.png")), tr("&Open..."), this);
    m_openAct->setShortcuts(QKeySequence::Open);
    m_openAct->setStatusTip(tr("Open an existing file"));
    connect(m_openAct, SIGNAL(triggered()), this, SLOT(open()));

    m_saveAct = new QAction(QIcon(QStringLiteral(":/res/save.png")), tr("&Save"), this);
    m_saveAct->setShortcuts(QKeySequence::Save);
    m_saveAct->setStatusTip(tr("Save the document to disk"));
    connect(m_saveAct, SIGNAL(triggered()), this, SLOT(save()));

    m_saveAsAct = new QAction(tr("Save &As..."), this);
    m_saveAsAct->setShortcuts(QKeySequence::SaveAs);
    m_saveAsAct->setStatusTip(tr("Save the document under a new name"));
    connect(m_saveAsAct, SIGNAL(triggered()), this, SLOT(saveAs()));

    m_exitAct = new QAction(tr("E&xit"), this);
    m_exitAct->setShortcuts(QKeySequence::Quit);
    m_exitAct->setStatusTip(tr("Exit the application"));
    connect(m_exitAct, SIGNAL(triggered()), qApp, SLOT(closeAllWindows()));

    m_closeAct = new QAction(QIcon(QStringLiteral(":/res/close.png")), tr("Cl&ose"), this);
    m_closeAct->setStatusTip(tr("Close the active window"));
    connect(m_closeAct, SIGNAL(triggered()), m_mdiArea, SLOT(closeActiveSubWindow()));

    m_closeAllAct = new QAction(tr("Close &All"), this);
    m_closeAllAct->setStatusTip(tr("Close all the windows"));
    connect(m_closeAllAct, SIGNAL(triggered()), m_mdiArea, SLOT(closeAllSubWindows()));

    m_tileAct = new QAction(QIcon(QStringLiteral(":/res/arrangeicons.png")), tr("&Arrange Icons"), this);
//    m_tileAct->setStatusTip(tr("Tile the windows"));
    m_tileAct->setEnabled(false);
    m_tileAct->setStatusTip(tr("Arrange icons at the bottom of the window"));
    connect(m_tileAct, SIGNAL(triggered()), m_mdiArea, SLOT(tileSubWindows()));

    m_cascadeAct = new QAction(tr("&Cascade"), this);
    m_cascadeAct->setStatusTip(tr("Cascade the windows"));
    connect(m_cascadeAct, SIGNAL(triggered()), m_mdiArea, SLOT(cascadeSubWindows()));

    m_nextAct = new QAction(tr("Ne&xt"), this);
    m_nextAct->setShortcuts(QKeySequence::NextChild);
    m_nextAct->setStatusTip(tr("Move the focus to the next window"));
    connect(m_nextAct, SIGNAL(triggered()), m_mdiArea, SLOT(activateNextSubWindow()));

    m_previousAct = new QAction(tr("Pre&vious"), this);
    m_previousAct->setShortcuts(QKeySequence::PreviousChild);
    m_previousAct->setStatusTip(tr("Move the focus to the previous "
                                 "window"));
    connect(m_previousAct, SIGNAL(triggered()), m_mdiArea, SLOT(activatePreviousSubWindow()));
}

void MainWindow::createMenuFile()
{
    QIcon iconLogo;
    iconLogo.addPixmap(QPixmap(QStringLiteral(":/res/qtitan.png")));
    iconLogo.addPixmap(QPixmap(QStringLiteral(":/res/qtitanlogo32x32.png")));
    QAction* actionFile = ribbonBar()->addSystemButton(iconLogo, tr("&File"));
    actionFile->setToolTip(tr("Click here to see everything<br />you can do with your<br />document"));

    RibbonSystemMenu* systemMenu = qobject_cast<RibbonSystemMenu *>(actionFile->menu());
    systemMenu->addAction(m_newTextAct);
    systemMenu->addAction(m_newSketchAct);
    systemMenu->addAction(m_openAct);
    systemMenu->addAction(m_saveAct);
    systemMenu->addAction(m_saveAsAct);
    systemMenu->addSeparator();

    systemMenu->addSeparator();
    systemMenu->addAction(m_closeAct);

    m_appCloseAct = systemMenu->addPopupBarAction(tr("Exit Sample"));
    connect(m_appCloseAct, SIGNAL(triggered()), this, SLOT(close()));

    QAction* option = systemMenu->addPopupBarAction(tr("Option"));
    option->setEnabled(false );
}

void MainWindow::createRibbon()
{
    RibbonPage* pageView = ribbonBar()->addPage(tr("&View"));
    RibbonGroup* groupDocument = pageView->addGroup(tr("Document Views"));
    groupDocument->addAction(QIcon(QStringLiteral(":/res/normal.png")), tr("&Normal"), Qt::ToolButtonTextUnderIcon);
    groupDocument->addAction(QIcon(QStringLiteral(":/res/printpreview.png")), tr("&Print Preview"), Qt::ToolButtonTextUnderIcon);
    m_actionFullScreen = groupDocument->addAction(QIcon(QStringLiteral(":/res/fullscreen.png")), tr("&Full Screen"), Qt::ToolButtonTextUnderIcon);
    m_actionFullScreen->setCheckable(true);
    m_actionFullScreen->setChecked(false);
    connect(m_actionFullScreen, SIGNAL(triggered(bool)), this, SLOT(fullScreen(bool)));

    Qt::CheckState stateWorkspace = Qt::Checked;
    RibbonGroup* groupShow_Hide = pageView->addGroup(tr("Show/Hide"));
    QCheckBox* checkStatusBar = new QCheckBox(tr("StatusBar"));
    checkStatusBar->setCheckState(Qt::Checked);
    groupShow_Hide->addWidget(checkStatusBar);
    connect(checkStatusBar, SIGNAL(stateChanged(int)), this, SLOT(hideStatusBar(int)));

    QCheckBox* checkWorkspace = new QCheckBox(tr("Workspace"));
    checkWorkspace->setCheckState(stateWorkspace);
    groupShow_Hide->addWidget(checkWorkspace);
    connect(checkWorkspace, SIGNAL(stateChanged(int)), this, SLOT(switchViewMode(int)));

    QCheckBox* checkFrameTheme = new QCheckBox(tr("FrameTheme"));
    checkFrameTheme->setCheckState(Qt::Checked);
    m_actFrameTheme = groupShow_Hide->addWidget(checkFrameTheme);
    m_actFrameTheme->setCheckable(true);
    m_actFrameTheme->setChecked(true);
    QObject::connect(checkFrameTheme, SIGNAL(toggled(bool)), m_actFrameTheme, SIGNAL(toggled(bool)));
    connect(m_actFrameTheme, SIGNAL(toggled(bool)), this, SLOT(setFrameThemeEnabled(bool)));

    QButtonGroup* groupButton = new QButtonGroup(this);
    m_groupMdiTabs = pageView->addGroup(tr("Option MDI Tabs"));
    m_posTop = new QRadioButton(tr("Position Top"));
    groupButton->addButton(m_posTop);
    connect(m_posTop, SIGNAL(toggled(bool)), this, SLOT(setTabPositionTop(bool)));
    m_posTop->setChecked(true);
    m_groupMdiTabs->addWidget(m_posTop);

    m_posBottom = new QRadioButton(tr("Position Bottom"));
    groupButton->addButton(m_posBottom);
    connect(m_posBottom, SIGNAL(toggled(bool)), this, SLOT(setTabPositionBottom(bool)));
    m_groupMdiTabs->addWidget(m_posBottom);

    m_posLeft = new QRadioButton(tr("Position Left"));
    groupButton->addButton(m_posLeft);
    connect(m_posLeft, SIGNAL(toggled(bool)), this, SLOT(setTabPositionLeft(bool)));
    m_groupMdiTabs->addWidget(m_posLeft);

    m_posRight = new QRadioButton(tr("Position Right"));
    groupButton->addButton(m_posRight);
    connect(m_posRight, SIGNAL(toggled(bool)), this, SLOT(setTabPositionRight(bool)));
    m_groupMdiTabs->addWidget(m_posRight);
    m_groupMdiTabs->setEnabled(stateWorkspace == Qt::Checked);

    RibbonPage* pageWindow = ribbonBar()->addPage(tr("&Window"));
    RibbonGroup* groupWindow = pageWindow->addGroup(tr("Window"));
    QAction* actionnewWindow = groupWindow->addAction(QIcon(QStringLiteral(":/res/newwindow.png")), tr("&New Window"), Qt::ToolButtonTextUnderIcon);
    actionnewWindow->setStatusTip(tr("Open another window for the active document"));
    groupWindow->addAction(m_tileAct, Qt::ToolButtonTextUnderIcon);
    m_windowMenu = groupWindow->addMenu(QIcon(QStringLiteral(":/res/windowswitch.png")), tr("&Switch Windows"));
    updateWindowMenu();
    connect(m_windowMenu, SIGNAL(aboutToShow()), this, SLOT(updateWindowMenu()));
}

void MainWindow::createStatusBar()
{
    statusBar()->showMessage(tr("Ready"));
}

QWidget* MainWindow::activeMdiChild()
{
    if (QMdiSubWindow* activeSubWindow = m_mdiArea->activeSubWindow())
        return activeSubWindow->widget();
    return Q_NULL;
}

QMdiSubWindow* MainWindow::findMdiChild(const QString& fileName)
{
    QString canonicalFilePath = QFileInfo(fileName).canonicalFilePath();
    foreach (QMdiSubWindow* window, m_mdiArea->subWindowList())
    {
        ChildInterface* ifChild = qobject_cast<ChildInterface*>(window->widget());
        if (ifChild && ifChild->currentFile() == canonicalFilePath)
            return window;
    }
    return Q_NULL;
}

void MainWindow::switchLayoutDirection()
{
    if (layoutDirection() == Qt::LeftToRight)
        qApp->setLayoutDirection(Qt::RightToLeft);
    else
        qApp->setLayoutDirection(Qt::LeftToRight);
}

void MainWindow::setActiveSubWindow(QWidget* window)
{
    if (!window)
        return;
    m_mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow*>(window));
}

void MainWindow::hideStatusBar(int state)
{
    statusBar()->setVisible(state == Qt::Checked);
}

void MainWindow::switchViewMode(int state)
{
    m_mdiArea->setLineWidth(state == Qt::Checked ? 3 : 0);
    m_mdiArea->setViewMode(state == Qt::Checked ? QMdiArea::TabbedView : QMdiArea::SubWindowView);
    m_groupMdiTabs->setEnabled(state == Qt::Checked);
    m_tileAct->setEnabled(state != Qt::Checked);
}

void MainWindow::setStyleByName(const QString& styleName)
{
    DemoRibbonWindow::setStyleByName(styleName);
    if (m_actFrameTheme->isChecked() != ribbonBar()->isFrameThemeEnabled())
        setFrameThemeEnabled(m_actFrameTheme->isChecked());
}

void MainWindow::setFrameThemeEnabled(bool checked)
{
    ribbonBar()->setFrameThemeEnabled(checked);
}

void MainWindow::setTabPositionLeft(bool state)
{
    if (state)
        m_mdiArea->setTabPosition(QTabWidget::West);
}

void MainWindow::setTabPositionTop(bool state)
{
    if (state)
        m_mdiArea->setTabPosition(QTabWidget::North);
}

void MainWindow::setTabPositionBottom(bool state)
{
    if (state)
        m_mdiArea->setTabPosition(QTabWidget::South);
}

void MainWindow::setTabPositionRight(bool state)
{
    if (state)
        m_mdiArea->setTabPosition(QTabWidget::East);
}

void MainWindow::subWindowActivated(QMdiSubWindow* subWindow)
{
    if (subWindow)
    {
        QWidget* activatWidget = subWindow->widget();
        if (m_childCurrent == activatWidget)
            return;

        if (ChildInterface* ifChild = qobject_cast<ChildInterface*>(activatWidget))
        {
            ribbonBar()->beginUpdate();

            if (ChildInterface* ifOldChild = qobject_cast<ChildInterface*>(m_childCurrent))
                ifOldChild->removeUserInterface(ribbonBar(), statusBar(), Q_NULL);
            m_childCurrent = activatWidget;
            m_typeDocCurrent = ifChild->typeDocument();
            ifChild->buildUserInterface(ribbonBar(), statusBar(), Q_NULL);

            ribbonBar()->endUpdate();
        }
    }
}

void MainWindow::fullScreen(bool checked)
{
    if (checked)
    {
        m_stateWindow = windowState();
        m_actionFullScreen->setChecked(true);
        ribbonBar()->setVisible(false);
        setWindowState(Qt::WindowFullScreen);
    }
}

void MainWindow::keyPressEvent(QKeyEvent* event)
{
    RibbonMainWindow::keyPressEvent(event);

    if (event->key() == Qt::Key_Escape && m_actionFullScreen->isChecked())
    {
        ribbonBar()->setVisible(true);
        setWindowState(m_stateWindow);
        m_actionFullScreen->setChecked(false);
    }
}