Warning, file /office/calligra/libs/main/KoView.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) 1998, 1999 Torben Weis <weis@kde.org>
0003    Copyright (C) 2007 Thomas Zander <zander@kde.org>
0004    Copyright (C) 2010 Benjamin Port <port.benjamin@gmail.com>
0005 
0006    This library is free software; you can redistribute it and/or
0007    modify it under the terms of the GNU Library General Public
0008    License as published by the Free Software Foundation; either
0009    version 2 of the License, or (at your option) any later version.
0010 
0011    This library is distributed in the hope that it will be useful,
0012    but WITHOUT ANY WARRANTY; without even the implied warranty of
0013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014    Library General Public License for more details.
0015 
0016    You should have received a copy of the GNU Library General Public License
0017    along with this library; see the file COPYING.LIB.  If not, write to
0018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020 */
0021 
0022 #include "KoView.h"
0023 
0024 // local directory
0025 #include "KoView_p.h"
0026 
0027 #include "KoPart.h"
0028 #include "KoDockRegistry.h"
0029 #include "KoDocument.h"
0030 #include "KoMainWindow.h"
0031 
0032 #ifndef QT_NO_DBUS
0033 #include "KoViewAdaptor.h"
0034 #include <QDBusConnection>
0035 #endif
0036 
0037 #include "KoDockFactoryBase.h"
0038 #include "KoUndoStackAction.h"
0039 #include "KoGlobal.h"
0040 #include "KoPageLayout.h"
0041 #include "KoPrintJob.h"
0042 #include "KoDocumentInfo.h"
0043 
0044 #include <KoIcon.h>
0045 
0046 #include <kactioncollection.h>
0047 #include <klocalizedstring.h>
0048 #include <MainDebug.h>
0049 #include <kmessagebox.h>
0050 #include <KoNetAccess.h>
0051 #include <kselectaction.h>
0052 #include <kconfiggroup.h>
0053 #include <KSharedConfig>
0054 
0055 #include <QStatusBar>
0056 #include <QDockWidget>
0057 #include <QApplication>
0058 #include <QList>
0059 #include <QDropEvent>
0060 #include <QDragEnterEvent>
0061 #include <QImage>
0062 #include <QUrl>
0063 #include <QPrintDialog>
0064 
0065 //static
0066 QString KoView::newObjectName()
0067 {
0068     static int s_viewIFNumber = 0;
0069     QString name; name.setNum(s_viewIFNumber++); name.prepend("view_");
0070     return name;
0071 }
0072 
0073 
0074 class KoViewPrivate
0075 {
0076 public:
0077     KoViewPrivate() {
0078         tempActiveWidget = 0;
0079         documentDeleted = false;
0080         actionAuthor = 0;
0081     }
0082     ~KoViewPrivate() {
0083     }
0084 
0085     QPointer<KoDocument> document; // our KoDocument
0086     QPointer<KoPart> part; // our part
0087     QWidget *tempActiveWidget;
0088     bool documentDeleted; // true when document gets deleted [can't use document==0
0089     // since this only happens in ~QObject, and views
0090     // get deleted by ~KoDocument].
0091 
0092 
0093     // Hmm sorry for polluting the private class with such a big inner class.
0094     // At the beginning it was a little struct :)
0095     class StatusBarItem
0096     {
0097     public:
0098         StatusBarItem() // for QValueList
0099             : m_widget(0),
0100               m_connected(false),
0101               m_hidden(false) {}
0102 
0103         StatusBarItem(QWidget * widget, int stretch, bool permanent)
0104             : m_widget(widget),
0105               m_stretch(stretch),
0106               m_permanent(permanent),
0107               m_connected(false),
0108               m_hidden(false) {}
0109 
0110         bool operator==(const StatusBarItem& rhs) {
0111             return m_widget == rhs.m_widget;
0112         }
0113 
0114         bool operator!=(const StatusBarItem& rhs) {
0115             return m_widget != rhs.m_widget;
0116         }
0117 
0118         QWidget * widget() const {
0119             return m_widget;
0120         }
0121 
0122         void ensureItemShown(QStatusBar * sb) {
0123             Q_ASSERT(m_widget);
0124             if (!m_connected) {
0125                 if (m_permanent)
0126                     sb->addPermanentWidget(m_widget, m_stretch);
0127                 else
0128                     sb->addWidget(m_widget, m_stretch);
0129 
0130                 if(!m_hidden)
0131                     m_widget->show();
0132 
0133                 m_connected = true;
0134             }
0135         }
0136         void ensureItemHidden(QStatusBar * sb) {
0137             if (m_connected) {
0138                 m_hidden = m_widget->isHidden();
0139                 sb->removeWidget(m_widget);
0140                 m_widget->hide();
0141                 m_connected = false;
0142             }
0143         }
0144     private:
0145         QWidget * m_widget;
0146         int m_stretch;
0147         bool m_permanent;
0148         bool m_connected;
0149         bool m_hidden;
0150     };
0151 
0152     QList<StatusBarItem> statusBarItems; // Our statusbar items
0153     bool inOperation; //in the middle of an operation (no screen refreshing)?
0154     KSelectAction *actionAuthor; // Select action for author profile.
0155 };
0156 
0157 KoView::KoView(KoPart *part, KoDocument *document, QWidget *parent)
0158         : QWidget(parent)
0159         , d(new KoViewPrivate)
0160 {
0161     Q_ASSERT(document);
0162     Q_ASSERT(part);
0163 
0164     setObjectName(newObjectName());
0165 
0166 #ifndef QT_NO_DBUS
0167     new KoViewAdaptor(this);
0168     QDBusConnection::sessionBus().registerObject('/' + objectName(), this);
0169 #endif
0170 
0171     d->document = document;
0172     d->part = part;
0173 
0174     setFocusPolicy(Qt::StrongFocus);
0175 
0176     setupGlobalActions();
0177 
0178     QStatusBar * sb = statusBar();
0179     if (sb) { // No statusbar in e.g. konqueror
0180         connect(d->document, SIGNAL(statusBarMessage(QString)),
0181                 this, SLOT(slotActionStatusText(QString)));
0182         connect(d->document, SIGNAL(clearStatusBarMessage()),
0183                 this, SLOT(slotClearStatusText()));
0184     }
0185 
0186     // add all plugins.
0187     foreach(const QString & docker, KoDockRegistry::instance()->keys()) {
0188         KoDockFactoryBase *factory = KoDockRegistry::instance()->value(docker);
0189         if (mainWindow())
0190             mainWindow()->createDockWidget(factory);
0191     }
0192 
0193     actionCollection()->addAssociatedWidget(this);
0194 
0195     /**
0196      * WARNING: This code changes the context of global shortcuts
0197      *          only. All actions added later will have the default
0198      *          context, which is Qt::WindowShortcut!
0199      */
0200     foreach(QAction* action, actionCollection()->actions()) {
0201         action->setShortcutContext(Qt::WidgetWithChildrenShortcut);
0202     }
0203 }
0204 
0205 KoView::~KoView()
0206 {
0207     if (!d->documentDeleted) {
0208         if (d->document) {
0209             d->part->removeView(this);
0210         }
0211     }
0212     delete d;
0213 }
0214 
0215 
0216 void KoView::dragEnterEvent(QDragEnterEvent *event)
0217 {
0218     if (event->mimeData()->hasImage()
0219             || event->mimeData()->hasUrls()) {
0220         event->accept();
0221     } else {
0222         event->ignore();
0223     }
0224 }
0225 
0226 void KoView::dropEvent(QDropEvent *event)
0227 {
0228     // we can drop a list of urls from, for instance dolphin
0229     QVector<QImage> images;
0230 
0231     if (event->mimeData()->hasImage()) {
0232         QImage image = event->mimeData()->imageData().value<QImage>();
0233         if (!image.isNull()) {
0234             // apparently hasImage() && imageData().value<QImage>().isNull()
0235             // can hold sometimes (Qt bug?).
0236             images << image;
0237         }
0238     }
0239     else if (event->mimeData()->hasUrls()) {
0240         QList<QUrl> urls = event->mimeData()->urls();
0241         foreach (const QUrl &url, urls) {
0242             QImage image;
0243             QUrl kurl(url);
0244             // make sure we download the files before inserting them
0245             if (!kurl.isLocalFile()) {
0246                 QString tmpFile;
0247                 if( KIO::NetAccess::download(kurl, tmpFile, this)) {
0248                     image.load(tmpFile);
0249                     KIO::NetAccess::removeTempFile(tmpFile);
0250                 } else {
0251                     KMessageBox::error(this, KIO::NetAccess::lastErrorString());
0252                 }
0253             }
0254             else {
0255                 image.load(kurl.toLocalFile());
0256             }
0257             if (!image.isNull()) {
0258                 images << image;
0259             }
0260         }
0261     }
0262 
0263     if (!images.isEmpty()) {
0264         addImages(images, event->pos());
0265     }
0266 }
0267 
0268 
0269 void KoView::addImages(const QVector<QImage> &, const QPoint &)
0270 {
0271     // override in your application
0272 }
0273 
0274 KoDocument *KoView::koDocument() const
0275 {
0276     return d->document;
0277 }
0278 
0279 void KoView::setDocumentDeleted()
0280 {
0281     d->documentDeleted = true;
0282 }
0283 
0284 void KoView::addStatusBarItem(QWidget * widget, int stretch, bool permanent)
0285 {
0286     KoViewPrivate::StatusBarItem item(widget, stretch, permanent);
0287     QStatusBar * sb = statusBar();
0288     if (sb) {
0289         item.ensureItemShown(sb);
0290     }
0291     d->statusBarItems.append(item);
0292 }
0293 
0294 void KoView::removeStatusBarItem(QWidget *widget)
0295 {
0296     QStatusBar *sb = statusBar();
0297 
0298     int itemCount = d->statusBarItems.count();
0299     for (int i = itemCount-1; i >= 0; --i) {
0300         KoViewPrivate::StatusBarItem &sbItem = d->statusBarItems[i];
0301         if (sbItem.widget() == widget) {
0302             if (sb) {
0303                 sbItem.ensureItemHidden(sb);
0304             }
0305             d->statusBarItems.removeOne(sbItem);
0306             break;
0307         }
0308     }
0309 }
0310 
0311 KoPrintJob * KoView::createPrintJob()
0312 {
0313     warnMain << "Printing not implemented in this application";
0314     return 0;
0315 }
0316 
0317 KoPrintJob * KoView::createPdfPrintJob()
0318 {
0319     return createPrintJob();
0320 }
0321 
0322 KoPageLayout KoView::pageLayout() const
0323 {
0324     return koDocument()->pageLayout();
0325 }
0326 
0327 QPrintDialog *KoView::createPrintDialog(KoPrintJob *printJob, QWidget *parent)
0328 {
0329     QPrintDialog *printDialog = new QPrintDialog(&printJob->printer(), parent);
0330     printDialog->setOptionTabs(printJob->createOptionWidgets());
0331     printDialog->setMinMax(printJob->printer().fromPage(), printJob->printer().toPage());
0332     printDialog->setEnabledOptions(printJob->printDialogOptions());
0333     return printDialog;
0334 }
0335 
0336 void KoView::setupGlobalActions()
0337 {
0338     QAction *undo = actionCollection()->addAction("edit_undo", new KoUndoStackAction(d->document->undoStack(), KoUndoStackAction::UNDO));
0339     QAction *redo = actionCollection()->addAction("edit_redo", new KoUndoStackAction(d->document->undoStack(), KoUndoStackAction::RED0));
0340 
0341     actionCollection()->setDefaultShortcut(undo, QKeySequence::Undo);
0342     actionCollection()->setDefaultShortcut(redo, QKeySequence::Redo);
0343     d->actionAuthor  = new KSelectAction(koIcon("user-identity"), i18n("Active Author Profile"), this);
0344     connect(d->actionAuthor, SIGNAL(triggered(QString)), this, SLOT(changeAuthorProfile(QString)));
0345     actionCollection()->addAction("settings_active_author", d->actionAuthor);
0346 
0347     slotUpdateAuthorProfileActions();
0348 }
0349 
0350 void KoView::changeAuthorProfile(const QString &profileName)
0351 {
0352     KConfigGroup appAuthorGroup( KSharedConfig::openConfig(), "Author");
0353     if (profileName.isEmpty()) {
0354         appAuthorGroup.writeEntry("active-profile", "");
0355     } else if (profileName == i18nc("choice for author profile", "Anonymous")) {
0356         appAuthorGroup.writeEntry("active-profile", "anonymous");
0357     } else {
0358         appAuthorGroup.writeEntry("active-profile", profileName);
0359     }
0360     appAuthorGroup.sync();
0361     d->document->documentInfo()->updateParameters();
0362 }
0363 
0364 KoMainWindow * KoView::mainWindow() const
0365 {
0366     // It is possible (when embedded inside a Gemini window) that you have a KoMainWindow which
0367     // is not the top level window. The code below ensures you can still get access to it, even
0368     // in that case.
0369     KoMainWindow* mw = dynamic_cast<KoMainWindow *>(window());
0370     QWidget* parent = parentWidget();
0371     while (!mw) {
0372         mw = dynamic_cast<KoMainWindow*>(parent);
0373         parent = parent->parentWidget();
0374         if (!parent) {
0375             break;
0376         }
0377     }
0378     return mw;
0379 }
0380 
0381 QStatusBar * KoView::statusBar() const
0382 {
0383     KoMainWindow *mw = mainWindow();
0384     return mw ? mw->statusBar() : 0;
0385 }
0386 
0387 void KoView::slotActionStatusText(const QString &text)
0388 {
0389     QStatusBar *sb = statusBar();
0390     if (sb)
0391         sb->showMessage(text);
0392 }
0393 
0394 void KoView::slotClearStatusText()
0395 {
0396     QStatusBar *sb = statusBar();
0397     if (sb)
0398         sb->clearMessage();
0399 }
0400 
0401 void KoView::slotUpdateAuthorProfileActions()
0402 {
0403     Q_ASSERT(d->actionAuthor);
0404     if (!d->actionAuthor) {
0405         return;
0406     }
0407     d->actionAuthor->clear();
0408     d->actionAuthor->addAction(i18n("Default Author Profile"));
0409     d->actionAuthor->addAction(i18nc("choice for author profile", "Anonymous"));
0410 
0411     KConfigGroup authorGroup(KoGlobal::calligraConfig(), "Author");
0412     QStringList profiles = authorGroup.readEntry("profile-names", QStringList());
0413     foreach (const QString &profile , profiles) {
0414         d->actionAuthor->addAction(profile);
0415     }
0416 
0417     KConfigGroup appAuthorGroup( KSharedConfig::openConfig(), "Author");
0418     QString profileName = appAuthorGroup.readEntry("active-profile", "");
0419     if (profileName == "anonymous") {
0420         d->actionAuthor->setCurrentItem(1);
0421     } else if (profiles.contains(profileName)) {
0422         d->actionAuthor->setCurrentAction(profileName);
0423     } else {
0424         d->actionAuthor->setCurrentItem(0);
0425     }
0426 }
0427 
0428 QList<QAction*> KoView::createChangeUnitActions(bool addPixelUnit)
0429 {
0430     UnitActionGroup* unitActions = new UnitActionGroup(d->document, addPixelUnit, this);
0431     return unitActions->actions();
0432 }
0433 
0434 void KoView::guiActivateEvent(bool activated)
0435 {
0436     Q_UNUSED(activated);
0437 }