1 /* This file is part of the KDE project
2  * Copyright (C) 1998, 1999 Torben Weis <weis@kde.org>
3  * Copyright (C) 2000-2005 David Faure <faure@kde.org>
4  * Copyright (C) 2007-2008 Thorsten Zachmann <zachmann@kde.org>
5  * Copyright (C) 2010-2012 Boudewijn Rempt <boud@kogmbh.com>
6  * Copyright (C) 2011 Inge Wallin <ingwa@kogmbh.com>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  */
23 
24 #include "KoPart.h"
25 
26 #include "KoApplication.h"
27 #include "KoMainWindow.h"
28 #include "KoDocument.h"
29 #include "KoView.h"
30 #include "KoOpenPane.h"
31 #include "KoFilterManager.h"
32 #include <KoComponentData.h>
33 
34 #include <KoCanvasController.h>
35 #include <KoCanvasControllerWidget.h>
36 #include <KoResourcePaths.h>
37 
38 #include <MainDebug.h>
39 #include <kxmlguifactory.h>
40 #include <kdesktopfile.h>
41 #include <kconfiggroup.h>
42 #include <ksharedconfig.h>
43 
44 #include <QFileInfo>
45 #include <QGraphicsScene>
46 #include <QGraphicsProxyWidget>
47 #include <QMimeDatabase>
48 
49 #ifndef QT_NO_DBUS
50 #include <QDBusConnection>
51 #include "KoPartAdaptor.h"
52 #endif
53 
54 class Q_DECL_HIDDEN KoPart::Private
55 {
56 public:
Private(const KoComponentData & componentData_,KoPart * _parent)57     Private(const KoComponentData &componentData_, KoPart *_parent)
58         : parent(_parent)
59         , document(0)
60         , proxyWidget(0)
61         , startUpWidget(0)
62         , componentData(componentData_)
63     {
64     }
65 
~Private()66     ~Private()
67     {
68         delete proxyWidget;
69     }
70 
71     KoPart *parent;
72 
73     QList<KoView*> views;
74     QList<KoMainWindow*> mainWindows;
75     KoDocument *document;
76     QList<KoDocument*> documents;
77     QPointer<QGraphicsProxyWidget> proxyWidget;
78     QPointer<KoOpenPane> startUpWidget;
79     QString templatesResourcePath;
80 
81     KoComponentData componentData;
82 };
83 
84 
KoPart(const KoComponentData & componentData,QObject * parent)85 KoPart::KoPart(const KoComponentData &componentData, QObject *parent)
86         : QObject(parent)
87         , d(new Private(componentData, this))
88 {
89 #ifndef QT_NO_DBUS
90     new KoPartAdaptor(this);
91     QDBusConnection::sessionBus().registerObject('/' + objectName(), this);
92 #endif
93 }
94 
~KoPart()95 KoPart::~KoPart()
96 {
97     // Tell our views that the document is already destroyed and
98     // that they shouldn't try to access it.
99     foreach(KoView *view, views()) {
100         view->setDocumentDeleted();
101     }
102 
103     while (!d->mainWindows.isEmpty()) {
104         delete d->mainWindows.takeFirst();
105     }
106 
107     delete d->startUpWidget;
108     d->startUpWidget = 0;
109 
110     delete d;
111 }
112 
componentData() const113 KoComponentData KoPart::componentData() const
114 {
115     return d->componentData;
116 }
117 
setDocument(KoDocument * document)118 void KoPart::setDocument(KoDocument *document)
119 {
120     Q_ASSERT(document);
121     d->document = document;
122 }
123 
document() const124 KoDocument *KoPart::document() const
125 {
126     return d->document;
127 }
128 
createView(KoDocument * document,QWidget * parent)129 KoView *KoPart::createView(KoDocument *document, QWidget *parent)
130 {
131     KoView *view = createViewInstance(document, parent);
132     addView(view, document);
133     if (!d->documents.contains(document)) {
134         d->documents.append(document);
135     }
136     return view;
137 }
138 
addView(KoView * view,KoDocument * document)139 void KoPart::addView(KoView *view, KoDocument *document)
140 {
141     if (!view)
142         return;
143 
144     if (!d->views.contains(view)) {
145         d->views.append(view);
146     }
147     if (!d->documents.contains(document)) {
148         d->documents.append(document);
149     }
150 
151     view->updateReadWrite(document->isReadWrite());
152 
153     if (d->views.size() == 1) {
154         KoApplication *app = qobject_cast<KoApplication*>(qApp);
155         if (0 != app) {
156             emit app->documentOpened('/'+objectName());
157         }
158     }
159 }
160 
removeView(KoView * view)161 void KoPart::removeView(KoView *view)
162 {
163     d->views.removeAll(view);
164 
165     if (d->views.isEmpty()) {
166         KoApplication *app = qobject_cast<KoApplication*>(qApp);
167         if (0 != app) {
168             emit app->documentClosed('/'+objectName());
169         }
170     }
171 }
172 
views() const173 QList<KoView*> KoPart::views() const
174 {
175     return d->views;
176 }
177 
viewCount() const178 int KoPart::viewCount() const
179 {
180     return d->views.count();
181 }
182 
canvasItem(KoDocument * document,bool create)183 QGraphicsItem *KoPart::canvasItem(KoDocument *document, bool create)
184 {
185     if (create && !d->proxyWidget) {
186         return createCanvasItem(document);
187     }
188     return d->proxyWidget;
189 }
190 
createCanvasItem(KoDocument * document)191 QGraphicsItem *KoPart::createCanvasItem(KoDocument *document)
192 {
193     KoView *view = createView(document);
194     d->proxyWidget = new QGraphicsProxyWidget();
195     QWidget *canvasController = view->findChild<KoCanvasControllerWidget*>();
196     d->proxyWidget->setWidget(canvasController);
197     return d->proxyWidget;
198 }
199 
addMainWindow(KoMainWindow * mainWindow)200 void KoPart::addMainWindow(KoMainWindow *mainWindow)
201 {
202     if (d->mainWindows.indexOf(mainWindow) == -1) {
203         debugMain <<"mainWindow" << (void*)mainWindow <<"added to doc" << this;
204         d->mainWindows.append(mainWindow);
205     }
206 }
207 
removeMainWindow(KoMainWindow * mainWindow)208 void KoPart::removeMainWindow(KoMainWindow *mainWindow)
209 {
210     debugMain <<"mainWindow" << (void*)mainWindow <<"removed from doc" << this;
211     if (mainWindow) {
212         d->mainWindows.removeAll(mainWindow);
213     }
214 }
215 
mainWindows() const216 const QList<KoMainWindow*>& KoPart::mainWindows() const
217 {
218     return d->mainWindows;
219 }
220 
mainwindowCount() const221 int KoPart::mainwindowCount() const
222 {
223     return d->mainWindows.count();
224 }
225 
226 
currentMainwindow() const227 KoMainWindow *KoPart::currentMainwindow() const
228 {
229     QWidget *widget = qApp->activeWindow();
230     KoMainWindow *mainWindow = qobject_cast<KoMainWindow*>(widget);
231     while (!mainWindow && widget) {
232         widget = widget->parentWidget();
233         mainWindow = qobject_cast<KoMainWindow*>(widget);
234     }
235 
236     if (!mainWindow && mainWindows().size() > 0) {
237         mainWindow = mainWindows().first();
238     }
239     return mainWindow;
240 
241 }
242 
openExistingFile(const QUrl & url)243 void KoPart::openExistingFile(const QUrl &url)
244 {
245     QApplication::setOverrideCursor(Qt::BusyCursor);
246     d->document->openUrl(url);
247     d->document->setModified(false);
248     QApplication::restoreOverrideCursor();
249 }
250 
openTemplate(const QUrl & url)251 void KoPart::openTemplate(const QUrl &url)
252 {
253     QApplication::setOverrideCursor(Qt::BusyCursor);
254     bool ok = d->document->loadNativeFormat(url.toLocalFile());
255     d->document->setModified(false);
256     d->document->undoStack()->clear();
257 
258     if (ok) {
259         QString mimeType = QMimeDatabase().mimeTypeForUrl(url).name();
260         // in case this is a open document template remove the -template from the end
261         mimeType.remove( QRegExp( "-template$" ) );
262         d->document->setMimeTypeAfterLoading(mimeType);
263         deleteOpenPane();
264         d->document->resetURL();
265         d->document->setEmpty();
266     } else {
267         d->document->showLoadingErrorDialog();
268         d->document->initEmpty();
269     }
270     QApplication::restoreOverrideCursor();
271 }
272 
addRecentURLToAllMainWindows(const QUrl & url)273 void KoPart::addRecentURLToAllMainWindows(const QUrl &url)
274 {
275     // Add to recent actions list in our mainWindows
276     foreach(KoMainWindow *mainWindow, d->mainWindows) {
277         mainWindow->addRecentURL(url);
278     }
279 
280 }
281 
showStartUpWidget(KoMainWindow * mainWindow,bool alwaysShow)282 void KoPart::showStartUpWidget(KoMainWindow *mainWindow, bool alwaysShow)
283 {
284 #ifndef NDEBUG
285     if (d->templatesResourcePath.isEmpty())
286         debugMain << "showStartUpWidget called, but setTemplatesResourcePath() never called. This will not show a lot";
287 #endif
288     if (!alwaysShow) {
289         KConfigGroup cfgGrp(componentData().config(), "TemplateChooserDialog");
290         QString fullTemplateName = cfgGrp.readPathEntry("AlwaysUseTemplate", QString());
291         if (!fullTemplateName.isEmpty()) {
292             QFileInfo fi(fullTemplateName);
293             if (!fi.exists()) {
294                 const QString templatesResourcePath = this->templatesResourcePath();
295                 QString desktopfile = KoResourcePaths::findResource("data", templatesResourcePath + "*/" + fullTemplateName);
296                 if (desktopfile.isEmpty()) {
297                     desktopfile = KoResourcePaths::findResource("data", templatesResourcePath + fullTemplateName);
298                 }
299                 if (desktopfile.isEmpty()) {
300                     fullTemplateName.clear();
301                 } else {
302                     QUrl templateURL;
303                     KDesktopFile f(desktopfile);
304                     templateURL.setPath(QFileInfo(desktopfile).absolutePath() + '/' + f.readUrl());
305                     fullTemplateName = templateURL.toLocalFile();
306                 }
307             }
308             if (!fullTemplateName.isEmpty()) {
309                 openTemplate(QUrl::fromUserInput(fullTemplateName));
310                 mainWindows().first()->setRootDocument(d->document, this);
311                 return;
312             }
313         }
314     }
315 
316     mainWindow->factory()->container("mainToolBar", mainWindow)->hide();
317 
318     if (d->startUpWidget) {
319         d->startUpWidget->show();
320     } else {
321         d->startUpWidget = createOpenPane(mainWindow, d->templatesResourcePath);
322         mainWindow->setCentralWidget(d->startUpWidget);
323     }
324 
325     mainWindow->setPartToOpen(this);
326 }
327 
deleteOpenPane(bool closing)328 void KoPart::deleteOpenPane(bool closing)
329 {
330     if (d->startUpWidget) {
331         d->startUpWidget->hide();
332         d->startUpWidget->deleteLater();
333 
334         if(!closing) {
335             mainWindows().first()->setRootDocument(d->document, this);
336             KoPart::mainWindows().first()->factory()->container("mainToolBar",
337                                                                   mainWindows().first())->show();
338         }
339     }
340 }
341 
createCustomDocumentWidgets(QWidget *)342 QList<KoPart::CustomDocumentWidgetItem> KoPart::createCustomDocumentWidgets(QWidget * /*parent*/)
343 {
344     return QList<CustomDocumentWidgetItem>();
345 }
346 
setTemplatesResourcePath(const QString & templatesResourcePath)347 void KoPart::setTemplatesResourcePath(const QString &templatesResourcePath)
348 {
349     Q_ASSERT(!templatesResourcePath.isEmpty());
350     Q_ASSERT(templatesResourcePath.endsWith(QLatin1Char('/')));
351 
352     d->templatesResourcePath = templatesResourcePath;
353 }
354 
templatesResourcePath() const355 QString KoPart::templatesResourcePath() const
356 {
357     return d->templatesResourcePath;
358 }
359 
360 
startCustomDocument()361 void KoPart::startCustomDocument()
362 {
363     deleteOpenPane();
364 }
365 
createOpenPane(QWidget * parent,const QString & templatesResourcePath)366 KoOpenPane *KoPart::createOpenPane(QWidget *parent, const QString& templatesResourcePath)
367 {
368     const QStringList mimeFilter = koApp->mimeFilter(KoFilterManager::Import);
369 
370     KoOpenPane *openPane = new KoOpenPane(parent, mimeFilter, templatesResourcePath);
371     QList<CustomDocumentWidgetItem> widgetList = createCustomDocumentWidgets(openPane);
372     foreach(const CustomDocumentWidgetItem & item, widgetList) {
373         openPane->addCustomDocumentWidget(item.widget, item.title, item.icon);
374         connect(item.widget, SIGNAL(documentSelected()), this, SLOT(startCustomDocument()));
375     }
376     openPane->show();
377 
378     connect(openPane, SIGNAL(openExistingFile(QUrl)), this, SLOT(openExistingFile(QUrl)));
379     connect(openPane, SIGNAL(openTemplate(QUrl)), this, SLOT(openTemplate(QUrl)));
380 
381     return openPane;
382 }
383