File: part.cpp

package info (click to toggle)
ktikz 0.13.1%2Bds1-1
  • links: PTS, VCS
  • area: main
  • in suites: bullseye
  • size: 5,136 kB
  • sloc: cpp: 10,491; xml: 701; sh: 131; makefile: 19
file content (355 lines) | stat: -rw-r--r-- 12,110 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
/***************************************************************************
 *   Copyright (C) 2008, 2009, 2010, 2011, 2012 by Glad Deschrijver        *
 *     <glad.deschrijver@gmail.com>                                        *
 *                                                                         *
 *   Document watcher and reloader code copied from Okular KPart code      *
 *     which is copyrighted as follows:                                    *
 *     Copyright (C) 2002 by Wilco Greven <greven@kde.org>                 *
 *     Copyright (C) 2002 by Chris Cheney <ccheney@cheney.cx>              *
 *     Copyright (C) 2002 by Malcolm Hunter <malcolm.hunter@gmx.co.uk>     *
 *     Copyright (C) 2003-2004 by Christophe Devriese                      *
 *                           <Christophe.Devriese@student.kuleuven.ac.be>  *
 *     Copyright (C) 2003 by Daniel Molkentin <molkentin@kde.org>          *
 *     Copyright (C) 2003 by Andy Goossens <andygoossens@telenet.be>       *
 *     Copyright (C) 2003 by Dirk Mueller <mueller@kde.org>                *
 *     Copyright (C) 2003 by Laurent Montel <montel@kde.org>               *
 *     Copyright (C) 2004 by Dominique Devriese <devriese@kde.org>         *
 *     Copyright (C) 2004 by Christoph Cullmann <crossfire@babylon2k.de>   *
 *     Copyright (C) 2004 by Henrique Pinto <stampede@coltec.ufmg.br>      *
 *     Copyright (C) 2004 by Waldo Bastian <bastian@kde.org>               *
 *     Copyright (C) 2004-2008 by Albert Astals Cid <aacid@kde.org>        *
 *     Copyright (C) 2004 by Antti Markus <antti.markus@starman.ee>        *
 *     licensed under GPL v2 or later                                      *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, see <http://www.gnu.org/licenses/>.  *
 ***************************************************************************/

#include "part.h"

#include <KPluginFactory>
#include <KAboutApplicationDialog>
#include <KAboutData>
#include <QAction>
#include <KActionCollection>
#include <KDirWatch>
#include <KMessageBox>
#include <KIO/Job>
#include <KIO/JobUiDelegate>
#include <QtCore/QSettings>
#include <QtCore/QTimer>
#include <QtCore/QTranslator>
#include <QMimeDatabase>
#include <QMimeType>
#include <QDir>
#include <QFileDialog>

#include "configdialog.h"
#include "settings.h"
#include "../common/templatewidget.h"
#include "../common/tikzpreview.h"
#include "../common/tikzpreviewcontroller.h"
#include "../common/utils/action.h"
#include "browserextension.h"

namespace KtikZ
{

Part::Part(QWidget *parentWidget, QObject *parent, const QVariantList &args)
	: KParts::ReadOnlyPart(parent)
{
	Q_UNUSED(args);

	// dirty hack: make sure that the "Export" menu and the "Template" widget are translated
	QTranslator *translator = createTranslator("qtikz");
	qApp->installTranslator(translator);

  setComponentData(KAboutData("ktikzpart", "KtikZ", APPVERSION));
// 	setComponentData(ktikzPartFactory::componentData()); // make sure that the actions of this kpart go in a separate section labeled "KtikZ Viewer" (as defined in K_EXPORT_PLUGIN above) in the "Configure Shortcuts" dialog

	m_configDialog = 0;

	Action::setActionCollection(actionCollection());
	m_tikzPreviewController = new TikzPreviewController(this);

	QWidget *mainWidget = new QWidget(parentWidget);
	QVBoxLayout *mainLayout = new QVBoxLayout;
	mainLayout->setSpacing(0);
	mainLayout->setMargin(0);
	mainLayout->addWidget(m_tikzPreviewController->templateWidget());
	mainLayout->addWidget(m_tikzPreviewController->tikzPreview());
	mainWidget->setLayout(mainLayout);
	setWidget(mainWidget);

	createActions();

	// document watcher and reloader
	m_watcher = new KDirWatch(this);
	connect(m_watcher, SIGNAL(dirty(QString)), this, SLOT(slotFileDirty(QString)));
	m_dirtyHandler = new QTimer(this);
	m_dirtyHandler->setSingleShot(true);
	connect(m_dirtyHandler, SIGNAL(timeout()), this, SLOT(slotDoFileDirty()));

	new BrowserExtension(this, m_tikzPreviewController); // needed to be able to use Konqueror's "Print" action

	setXMLFile("ktikzpart/ktikzpart.rc");

	applySettings();
}

Part::~Part()
{
	delete m_tikzPreviewController;
}

QWidget *Part::widget()
{
	return KParts::ReadOnlyPart::widget();
}

KAboutData *Part::createAboutData()
{
	KAboutData *aboutData = new KAboutData(QStringLiteral("ktikz"),i18n("KtikZ"), APPVERSION);
	aboutData->setShortDescription(i18n("A TikZ Viewer"));
	aboutData->setLicense(KAboutLicense::GPL_V2);
	aboutData->setCopyrightStatement(i18n("Copyright 2007-2014 Florian Hackenberger, Glad Deschrijver"));
	aboutData->setOtherText(i18n("This is a plugin for viewing TikZ (from the LaTeX pgf package) diagrams."));
	aboutData->setBugAddress("florian@hackenberger.at");
	aboutData->addAuthor(i18n("Florian Hackenberger"), i18n("Maintainer"), "florian@hackenberger.at");
	aboutData->addAuthor(i18n("Glad Deschrijver"), i18n("Developer"), "glad.deschrijver@gmail.com");
	return aboutData;
}

void Part::showAboutDialog()
{
	KAboutApplicationDialog dlg(*(createAboutData()), widget());
	dlg.exec();
}

void Part::createActions()
{
	// File
	m_saveAsAction = actionCollection()->addAction(KStandardAction::SaveAs, this, SLOT(saveAs()));
	m_saveAsAction->setWhatsThis(i18nc("@info:whatsthis", "<para>Save the document under a new name.</para>"));

	// Reload: we rely on Konqueror's "Reload" action instead of defining our own

	// Configure
	QAction *action = KStandardAction::preferences(this, SLOT(configure()), actionCollection());
	action->setText(i18nc("@action", "Configure KtikZ Viewer..."));

	// Help
	action = actionCollection()->addAction("help_about_ktikz");
	action->setText(i18n("About KtikZ Viewer"));
	action->setIcon(QIcon::fromTheme("ktikz"));
	connect(action, SIGNAL(triggered()), this, SLOT(showAboutDialog()));
}

/***************************************************************************/

bool Part::openFile()
{
	const QString fileName = localFilePath();

	QFile file(fileName);
	if (!file.open(QFile::ReadOnly | QFile::Text))
	{
		KMessageBox::error(widget(), i18nc("@info", "Cannot read file <filename>%1</filename>:<nl/><message>%2</message>", fileName, file.errorString()), i18nc("@title:window", "File Read Error"));
		return false;
	}

	QTextStream in(&file);
	m_tikzCode = in.readAll();
	m_tikzPreviewController->generatePreview();

	// set the file to the fileWatcher
	if (url().isLocalFile())
	{
		if (!m_watcher->contains(localFilePath()))
			m_watcher->addFile(localFilePath());
		QFileInfo fi(localFilePath());
		if (!m_watcher->contains(fi.absolutePath()))
			m_watcher->addDir(fi.absolutePath());
	}
	m_fileWasRemoved = false;

	return true;
}

void Part::saveAs()
{
	const Url srcUrl = url();

	QMimeDatabase db;
	const QMimeType mimeType = db.mimeTypeForName("text/x-pgf");
	const QString tikzFilter = (mimeType.isValid()) ?
	                           mimeType.globPatterns().join(" ") + '|' + mimeType.comment()
	                           : "*.pgf *.tikz *.tex|" + i18nc("@item:inlistbox filter", "TikZ files");
	const QUrl dstUrl = QFileDialog::getSaveFileUrl(widget(), i18nc("@title:window", "Save TikZ Source File As"),
	                    srcUrl, tikzFilter + "\n*|" + i18nc("@item:inlistbox filter", "All files"));

	if (!dstUrl.isValid())
		return;

	KIO::Job *job = KIO::file_copy(srcUrl, dstUrl, -1, KIO::Overwrite | KIO::HideProgressInfo);
	connect(job, SIGNAL(result(KJob*)), this, SLOT(showJobError(KJob*)));
}

bool Part::closeUrl()
{
	if (url().isLocalFile())
	{
		m_watcher->removeFile(localFilePath());
		QFileInfo fi(localFilePath());
		m_watcher->removeDir(fi.absolutePath());
	}

	emit setWindowCaption("");
	m_fileWasRemoved = false;

	return KParts::ReadOnlyPart::closeUrl();
}

void Part::showJobError(KJob *job)
{
	if (job->error() != 0)
	{
		KIO::JobUiDelegate *ui = static_cast<KIO::JobUiDelegate*>(static_cast<KIO::Job*>(job)->uiDelegate());

		if (!ui)
		{
			qCritical() << "Saving failed; job->ui() is null.";
			return;
		}
		ui->setWindow(widget());
		ui->showErrorMessage();
	}
}

QString Part::tikzCode() const
{
	return m_tikzCode;
}

QUrl KtikZ::Part::url() const
{
	return KParts::ReadOnlyPart::url();
}

/***************************************************************************/

void Part::slotFileDirty(const QString &path)
{
	// The beauty of this is that each start cancels the previous one.
	// This means that timeout() is only fired when there have
	// no changes to the file for the last 750 milisecs.
	// This ensures that we don't update on every other byte that gets
	// written to the file.
	if (path == localFilePath())
	{
		m_dirtyHandler->start(750);
	}
	else
	{
		QFileInfo fi(localFilePath());
		if (fi.absolutePath() == path)
		{
			// Our parent has been dirtified
			if (!QFile::exists(localFilePath()))
			{
				m_fileWasRemoved = true;
			}
			else if (m_fileWasRemoved && QFile::exists(localFilePath()))
			{
				// we need to watch the new file
				m_watcher->removeFile(localFilePath());
				m_watcher->addFile(localFilePath());
				m_dirtyHandler->start(750);
			}
		}
	}
}

void Part::slotDoFileDirty()
{
	m_tikzPreviewController->tikzPreview()->showErrorMessage(i18nc("@info:status", "Reloading the document..."));

	// close and (try to) reopen the document
	if (!KParts::ReadOnlyPart::openUrl(url()))
	{
		// start watching the file again (since we dropped it on close)
		m_watcher->addFile(localFilePath());
		m_dirtyHandler->start(750);
	}
}

/***************************************************************************/

void Part::applySettings()
{
	m_tikzPreviewController->applySettings();

	// Watch File
	QSettings settings(ORGNAME, APPNAME);
	bool watchFile = settings.value("WatchFile", true).toBool();
	if (watchFile && m_watcher->isStopped())
		m_watcher->startScan();
	if (!watchFile && !m_watcher->isStopped())
	{
		m_dirtyHandler->stop();
		m_watcher->stopScan();
	}
}

void Part::configure()
{
	if (m_configDialog == 0)
	{
		m_configDialog = new PartConfigDialog(widget());
		connect(m_configDialog, SIGNAL(settingsChanged(QString)), this, SLOT(applySettings()));
	}
	m_configDialog->readSettings();
	m_configDialog->show();
}

/***************************************************************************/
/* The following are only used to translate the "Export" menu and "Template" widget */

bool Part::findTranslator(QTranslator *translator, const QString &transName, const QString &transDir)
{
	const QString qmFile = transName + ".qm";
	if (QFileInfo(QDir(transDir), qmFile).exists())
		return translator->load(qmFile, transDir);
	return false;
}

QTranslator *Part::createTranslator(const QString &transName)
{
	const QString locale = QLocale::languageToString(QLocale().language());
	const QString localeShort = locale.left(2).toLower();

	QTranslator *translator = new QTranslator(0);
#ifdef KTIKZ_TRANSLATIONS_INSTALL_DIR
	const QDir qmPath(KTIKZ_TRANSLATIONS_INSTALL_DIR);
	bool foundTranslator = findTranslator(translator, transName + '_' + locale, qmPath.absolutePath());
	if (!foundTranslator)
		findTranslator(translator, transName + '_' + localeShort, qmPath.absolutePath());
#endif
	return translator;
}

K_PLUGIN_FACTORY(ktikzPartFactory, registerPlugin<KtikZ::Part>();)

#include "part.moc"

} // namespace KtikZ