Warning, file /office/calligra/gemini/lib/GeminiMainWindow.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /* This file is part of the KDE project
0002  * Copyright (C) 2015 Dan Leinir Turthra Jensen <admin@leinir.dk>
0003  *
0004  * This library is free software; you can redistribute it and/or
0005  * modify it under the terms of the GNU Library General Public
0006  * License as published by the Free Software Foundation; either
0007  * version 2 of the License, or (at your option) any later version.
0008  *
0009  * This library is distributed in the hope that it will be useful,
0010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012  * Library General Public License for more details.
0013  *
0014  * You should have received a copy of the GNU Library General Public License
0015  * along with this library; see the file COPYING.LIB.  If not, write to
0016  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018  */
0019 
0020 #include "GeminiMainWindow.h"
0021 #include "GeminiModeSwitchEvent.h"
0022 
0023 #include <QApplication>
0024 #include <QMap>
0025 #include <QQuickView>
0026 #include <QTimer>
0027 #include <QVBoxLayout>
0028 
0029 #ifdef Q_OS_WIN
0030 // Slate mode/docked detection stuff
0031 #include <Shellapi.h>
0032 #define SM_CONVERTIBLESLATEMODE 0x2003
0033 #define SM_SYSTEMDOCKED         0x2004
0034 #endif
0035 
0036 struct View {
0037     View() : quickView(0), widget(0) {}
0038     QQuickView* quickView;
0039     QWidget* widget;
0040     QWidget* getWidget(QWidget* parent = 0) {
0041         QWidget* view;
0042         if(widget) {
0043             view = widget;
0044         }
0045         else {
0046             QWidget* container = QWidget::createWindowContainer(quickView);
0047             view = new QWidget(parent);
0048             view->setLayout(new QVBoxLayout());
0049             view->layout()->setContentsMargins(0,0,0,0);
0050             view->layout()->setSpacing(0);
0051             view->layout()->addWidget(container);
0052         }
0053         return view;
0054     }
0055 };
0056 
0057 class GeminiMainWindow::Private {
0058 public:
0059     Private(GeminiMainWindow* qq)
0060         : q(qq)
0061         , fullScreenThrottle(new QTimer(qq))
0062         , currentState(UnknownState)
0063         , stateLocked(false)
0064     {
0065         fullScreenThrottle->setInterval(500);
0066         fullScreenThrottle->setSingleShot(true);
0067 
0068         // Initialise the event receiver map to empty
0069         eventReceivers.insert(CreateState, 0);
0070         eventReceivers.insert(EditState, 0);
0071         eventReceivers.insert(ViewState, 0);
0072 
0073         // Initialise the view map to empty
0074         views.insert(CreateState, 0);
0075         views.insert(EditState, 0);
0076         views.insert(ViewState, 0);
0077     }
0078     GeminiMainWindow* q;
0079     QTimer* fullScreenThrottle;
0080 
0081     GeminiState previousState;
0082     GeminiState currentState;
0083     bool stateLocked;
0084 
0085     QMap<GeminiState, View*> views;
0086     QMap<GeminiState, QObject*> eventReceivers;
0087 
0088     GeminiModeSynchronisationObject* syncObject;
0089 };
0090 
0091 GeminiMainWindow::GeminiMainWindow(QWidget* parent, Qt::WindowFlags flags)
0092     : QMainWindow(parent, flags)
0093     , d(new Private(this))
0094 {
0095 }
0096 
0097 GeminiMainWindow::~GeminiMainWindow()
0098 {
0099     delete d;
0100 }
0101 
0102 GeminiMainWindow::GeminiState GeminiMainWindow::currentState() const
0103 {
0104     return d->currentState;
0105 }
0106 
0107 bool GeminiMainWindow::fullScreen() const
0108 {
0109     return (windowState() & Qt::WindowFullScreen) == Qt::WindowFullScreen;
0110 }
0111 
0112 void GeminiMainWindow::setFullScreen(bool newState)
0113 {
0114     if(newState) {
0115         if(d->fullScreenThrottle->isActive()) {
0116             // not a good thing... you need to avoid this happening. This exists to avoid a death-loop,
0117             // such as what might happen if readermode is enabled when the window is not maximised
0118             // as this causes a resize loop which makes readermode switch between enabled and disabled,
0119             // which in turn makes fullScreen be set and reset all the time... very bad, so let's try
0120             // and avoid that.
0121         }
0122         else {
0123             setWindowState(windowState() | Qt::WindowFullScreen);
0124         }
0125     }
0126     else {
0127         // this is really unpleasant... however, fullscreen is very twitchy, and exiting it as below
0128         // will cause an inconsistent state, so we simply assume exiting fullscreen leaves you maximised.
0129         // It isn't optimal, but it is the best state for now, this has taken too long to work out.
0130         // setWindowState(windowState() & ~Qt::WindowFullScreen);
0131         // should really do it, but... it doesn't. So, we end up with what we have next:
0132         showMaximized();
0133     }
0134     d->fullScreenThrottle->start();
0135     emit fullScreenChanged();
0136 }
0137 
0138 
0139 void GeminiMainWindow::changeState(GeminiMainWindow::GeminiState newState, bool lockNewState)
0140 {
0141     d->syncObject = new GeminiModeSynchronisationObject;
0142 
0143     if(centralWidget()) {
0144         //Notify the view we are switching away from that we are about to switch away from it
0145         //giving it the possibility to set up the synchronisation object.
0146         GeminiModeSwitchEvent aboutToSwitchEvent(GeminiModeSwitchEvent::AboutToSwitchViewModeEvent, d->eventReceivers[d->currentState], d->eventReceivers[newState], d->syncObject);
0147         QApplication::sendEvent(d->eventReceivers[d->currentState], &aboutToSwitchEvent);
0148 
0149         centralWidget()->setParent(0);
0150     }
0151 
0152     View* view = d->views[newState];
0153     setCentralWidget(view->getWidget());
0154     qApp->processEvents();
0155     if(view->quickView)
0156         view->quickView->setVisible(true);
0157     resize(size());
0158 
0159     d->previousState = d->currentState;
0160     d->currentState = newState;
0161     emit currentStateChanged();
0162 
0163     QTimer::singleShot(50, this, SLOT(stateChanging()));
0164 }
0165 
0166 void GeminiMainWindow::stateChanging()
0167 {
0168     qApp->processEvents();
0169     //Notify the new view that we just switched to it, passing our synchronisation object
0170     //so it can use those values to sync with the old view.
0171     GeminiModeSwitchEvent switchedEvent(GeminiModeSwitchEvent::SwitchedToThisModeEvent, d->eventReceivers[d->previousState], d->eventReceivers[d->currentState], d->syncObject);
0172     QApplication::sendEvent(d->eventReceivers[d->currentState], &switchedEvent);
0173     d->syncObject = 0;
0174     qApp->processEvents();
0175 }
0176 
0177 bool GeminiMainWindow::stateLocked() const
0178 {
0179     return d->stateLocked;
0180 }
0181 
0182 void GeminiMainWindow::setStateLocked(bool locked)
0183 {
0184     d->stateLocked = locked;
0185     emit stateLockedChanged();
0186 }
0187 
0188 void GeminiMainWindow::setViewForState(QWidget* widget, GeminiMainWindow::GeminiState state)
0189 {
0190     View* view = d->views[state];
0191     view->quickView = 0;
0192     view->widget = widget;
0193 }
0194 
0195 void GeminiMainWindow::setViewForState(QQuickView* quickView, GeminiMainWindow::GeminiState state)
0196 {
0197     View* view = d->views[state];
0198     view->quickView = quickView;
0199     view->widget = 0;
0200 }
0201 
0202 void GeminiMainWindow::setEventReceiverForState(QObject* receiver, GeminiMainWindow::GeminiState state)
0203 {
0204     d->eventReceivers[state] = receiver;
0205 }
0206 
0207 #ifdef Q_OS_WIN
0208 bool GeminiMainWindow::winEvent( MSG * message, long * result )
0209 {
0210     if (message && message->message == WM_SETTINGCHANGE && message->lParam && !d->stateLocked)
0211     {
0212         if (wcscmp(TEXT("ConvertibleSlateMode"), (TCHAR *) message->lParam) == 0 || wcscmp(TEXT("SystemDockMode"), (TCHAR *) message->lParam) == 0) {
0213             bool slateMode = (GetSystemMetrics(SM_CONVERTIBLESLATEMODE) == 0);
0214             bool undocked = !(GetSystemMetrics(SM_SYSTEMDOCKED) != 0);
0215             if(slateMode || undocked) {
0216                 // find out if we are entirely without sensible input devices, or portrait
0217                 // if we are, change to ViewState. EditState will do for now as an autoswitch...
0218                 changeState(EditState);
0219             }
0220             else {
0221                 // If we are neither slate nor undocked, then we're in clamshell or we are docked, which is the same thing.
0222                 changeState(CreateState);
0223             }
0224             *result = 0;
0225             return true;
0226         }
0227     }
0228     return false;
0229 }
0230 #endif