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