kplato

kptpart.cpp
1/* This file is part of the KDE project
2 Copyright (C) 1998, 1999, 2000 Torben Weis <weis@kde.org>
3 Copyright (C) 2004, 2005 Dag Andersen <danders@get2net.dk>
4 Copyright (C) 2006 Raphael Langerhorst <raphael.langerhorst@kdemail.net>
5 Copyright (C) 2006 Dag Andersen <danders@get2net.dk>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 * Boston, MA 02110-1301, USA.
21*/
22
23#include "kptpart.h"
24#include "kptview.h"
25#include "kptfactory.h"
26#include "kptproject.h"
27#include "kptprojectdialog.h"
28#include "kptresource.h"
29#include "kptcontext.h"
30#include "kptganttview.h"
31#include "KDGanttViewTaskLink.h"
32
33#include <tqpainter.h>
34#include <tqfileinfo.h>
35
36#include <kdebug.h>
37#include <tdeconfig.h>
38#include <tdelocale.h>
39#include <tdemessagebox.h>
40#include <kstandarddirs.h>
41#include <kcommand.h>
42#include <KoTemplateChooseDia.h>
43#include <KoCommandHistory.h>
44#include <KoGlobal.h>
45
46#define CURRENT_SYNTAX_VERSION "0.5"
47
48namespace KPlato
49{
50
51Part::Part(TQWidget *parentWidget, const char *widgetName,
52 TQObject *parent, const char *name, bool singleViewMode)
53 : KoDocument(parentWidget, widgetName, parent, name, singleViewMode),
54 m_project(0), m_projectDialog(0), m_parentWidget(parentWidget), m_view(0),
55 m_embeddedGanttView(new GanttView(parentWidget)),
56 m_embeddedContext(new Context()), m_embeddedContextInitialized(false),
57 m_context(0), m_xmlLoader()
58{
59 m_update = m_calculate = false;
60 m_commandHistory = new KoCommandHistory(actionCollection());
61
62 setInstance(Factory::global());
63 setTemplateType("kplato_template");
64 m_config.setReadWrite(isReadWrite()|| !isEmbedded());
65 m_config.load();
66
67 delete m_project;
68 m_project = new Project(); // after config is loaded
69
70 connect(m_commandHistory, TQ_SIGNAL(commandExecuted()), TQ_SLOT(slotCommandExecuted()));
71 connect(m_commandHistory, TQ_SIGNAL(documentRestored()), TQ_SLOT(slotDocumentRestored()));
72
73 //FIXME the following is really dirty, we should make KPlato::Context a real class
74 // with getter and setter and signals when content changes, thus we can keep track
75 TQTimer* timer = new TQTimer(this,"context update timer");
76 connect(timer,TQ_SIGNAL(timeout()),this,TQ_SLOT(slotCopyContextFromView()));
77 timer->start(500);
78}
79
80
81Part::~Part() {
82 m_config.save();
83 delete m_commandHistory; // before project, in case of dependencies...
84 delete m_project;
85 delete m_projectDialog;
86 if (m_embeddedGanttView) {
87 delete m_embeddedGanttView;
88 m_embeddedGanttView = 0L;
89 }
90 if (m_embeddedContext) {
91 delete m_embeddedContext;
92 m_embeddedContext = 0L;
93 }
94}
95
96
97bool Part::initDoc(InitDocFlags flags, TQWidget* parentWidget) {
98 bool result = true;
99
100 if (flags==KoDocument::InitDocEmpty)
101 {
102 delete m_project;
103 m_project = new Project();
104 setAutoSave(0); // disable
105 setModified(false);
106 return true;
107 }
108
109 TQString templateDoc;
110 KoTemplateChooseDia::ReturnType ret;
111 KoTemplateChooseDia::DialogType dlgtype;
112 if (flags != KoDocument::InitDocFileNew )
113 dlgtype = KoTemplateChooseDia::Everything;
114 else
115 dlgtype = KoTemplateChooseDia::OnlyTemplates;
116
117 ret = KoTemplateChooseDia::choose(Factory::global(), templateDoc,
118 dlgtype,
119 "kplato_template",
120 parentWidget);
121 if (ret == KoTemplateChooseDia::Template) {
122 resetURL();
123 result = loadNativeFormat(templateDoc);
124 if ( !result )
125 showLoadingErrorDialog();
126 } else if (ret == KoTemplateChooseDia::File) {
127 KURL url(templateDoc);
128 kdDebug() << "Part::initDoc opening URL " << url.prettyURL() <<endl;
129 result = openURL(url);
130 } else if (ret == KoTemplateChooseDia::Empty) {
131 // Make a fresh project and let the user enter some info
132 delete m_project;
133 m_project = new Project();
134 // an emty project should be empty
135 // m_projectDialog = new ProjectDialog(*m_project, m_view);
136 // m_projectDialog->exec();
137
138 result = true;
139 } else {
140 result = false;
141 }
142 setAutoSave(0); // disable
143 setModified(false);
144 return result;
145}
146
147
148KoView *Part::createViewInstance(TQWidget *parent, const char *name) {
149 m_view = new View(this, parent, name);
150 connect(m_view,TQ_SIGNAL(destroyed()),this,TQ_SLOT(slotViewDestroyed()));
151
152 // If there is a project dialog this should be deleted so it will
153 // use the m_view as parent. If the dialog will be needed again,
154 // it will be made at that point
155 if (m_projectDialog != 0) {
156 kdDebug() << "Deleting m_projectDialog because of new ViewInstance\n";
157 delete m_projectDialog;
158 m_projectDialog = 0;
159 }
160 if (m_context)
161 m_view->setContext( *m_context );
162 else if (m_embeddedContext && m_embeddedContextInitialized)
163 m_view->setContext( *m_embeddedContext );
164 else {
165 // Activate menu actions. Assumes ganttview, we don't get any
166 // 'aboutToShow' signal. Need to redo action control.
167 m_view->setTaskActionsEnabled(true);
168 }
169 //m_view->setBaselineMode(getProject().isBaselined()); FIXME: Removed for this release
170 return m_view;
171}
172
173
174void Part::editProject() {
175
176 TQWidget* parent = m_parentWidget;
177 if (m_view)
178 parent = m_view;
179
180 if (m_projectDialog == 0)
181 // Make the dialog
182 m_projectDialog = new ProjectDialog(*m_project, parent);
183
184 m_projectDialog->exec();
185}
186
187
188bool Part::loadXML(TQIODevice *, const TQDomDocument &document) {
189 TQTime dt;
190 dt.start();
191 emit sigProgress( 0 );
192
193 TQString value;
194 TQDomElement plan = document.documentElement();
195
196 // Check if this is the right app
197 value = plan.attribute("mime", TQString());
198 if (value.isEmpty()) {
199 kdError() << "No mime type specified!" << endl;
200 setErrorMessage(i18n("Invalid document. No mimetype specified."));
201 return false;
202 }
203 else if (value != "application/x-vnd.kde.kplato") {
204 kdError() << "Unknown mime type " << value << endl;
205 setErrorMessage(i18n("Invalid document. Expected mimetype application/x-vnd.kde.kplato, got %1").arg(value));
206 return false;
207 }
208 TQString m_syntaxVersion = plan.attribute("version", CURRENT_SYNTAX_VERSION);
209 if (m_syntaxVersion > CURRENT_SYNTAX_VERSION) {
210 int ret = KMessageBox::warningContinueCancel(
211 0, i18n("This document was created with a newer version of KPlato (syntax version: %1)\n"
212 "Opening it in this version of KPlato will lose some information.").arg(m_syntaxVersion),
213 i18n("File-Format Mismatch"), i18n("Continue") );
214 if (ret == KMessageBox::Cancel)
215 {
216 setErrorMessage("USER_CANCELED");
217 return false;
218 }
219 }
220 emit sigProgress(5);
221
222 TQDomNodeList list = plan.childNodes();
223 if (list.count() > 2) {
224 // TODO: Make a proper bitching about this
225 kdDebug() << "*** Error ***\n";
226 kdDebug() << " Children count should be 1 but is " << list.count()
227 << "\n";
228 return false;
229 }
230 m_xmlLoader.startLoad();
231 for (unsigned int i = 0; i < list.count(); ++i) {
232 if (list.item(i).isElement()) {
233 TQDomElement e = list.item(i).toElement();
234
235 if (e.tagName() == "context") {
236 delete m_context;
237 m_context = new Context();
238 m_context->load(e);
239 } else if (e.tagName() == "project") {
240 Project *newProject = new Project();
241 if (newProject->load(e)) {
242 // The load went fine. Throw out the old project
243 delete m_project;
244 m_project = newProject;
245 delete m_projectDialog;
246 m_projectDialog = 0;
247 }
248 else {
249 delete newProject;
250 m_xmlLoader.addMsg(XMLLoaderObject::Errors, "Loading of project failed");
251 //TODO add some ui here
252 }
253 }
254 }
255 }
256 m_xmlLoader.stopLoad();
257 emit sigProgress(100); // the rest is only processing, not loading
258
259 kdDebug() << "Loading took " << (float)(dt.elapsed()) / 1000 << " seconds" << endl;
260
261 // do some sanity checking on document.
262 emit sigProgress(-1);
263
264 m_commandHistory->clear();
265 m_commandHistory->documentSaved();
266 setModified( false );
267 if (m_view)
268 m_view->slotUpdate(false);
269 return true;
270}
271
272TQDomDocument Part::saveXML() {
273 TQDomDocument document("kplato");
274
275 document.appendChild(document.createProcessingInstruction(
276 "xml",
277 "version=\"1.0\" encoding=\"UTF-8\""));
278
279 TQDomElement doc = document.createElement("kplato");
280 doc.setAttribute("editor", "KPlato");
281 doc.setAttribute("mime", "application/x-vnd.kde.kplato");
282 doc.setAttribute("version", CURRENT_SYNTAX_VERSION);
283 document.appendChild(doc);
284
285 delete m_context;
286 m_context = 0;
287 if (m_view) {
288 m_context = new Context();
289 m_view->getContext(*m_context);
290 }
291 if (m_context) {
292 m_context->save(doc);
293 }
294 // Save the project
295 m_project->save(doc);
296
297 m_commandHistory->documentSaved();
298 return document;
299}
300
301
302void Part::slotDocumentRestored() {
303 //kdDebug()<<k_funcinfo<<endl;
304 setModified(false);
305}
306
307
308void Part::paintContent(TQPainter &painter, const TQRect &rect,
309 bool /*transparent*/,
310 double zoomX, double /*zoomY*/)
311{
312 kdDebug() << "----------- KPlato: Part::paintContent ------------" << endl;
313 if (isEmbedded() && m_embeddedGanttView && m_project)
314 {
315 if (m_embeddedContext)
316 {
317 int ganttsize = m_embeddedContext->ganttview.ganttviewsize;
318 int tasksize = m_embeddedContext->ganttview.taskviewsize;
319 bool showtaskname = m_embeddedContext->ganttview.showTaskName;
320
321// m_embeddedContext->ganttview.ganttviewsize += m_embeddedContext->ganttview.taskviewsize;
322// m_embeddedContext->ganttview.taskviewsize = 0; //TODO this doesn't have any effect?! (bug?)
323 m_embeddedContext->ganttview.showTaskName = true; //since task view is not shown(?), show name in the gantt itself
324
325 m_embeddedGanttView->setContext( m_embeddedContext->ganttview, *m_project );
326
327 m_embeddedContext->ganttview.ganttviewsize = ganttsize;
328 m_embeddedContext->ganttview.taskviewsize = tasksize;
329 m_embeddedContext->ganttview.showTaskName = showtaskname;
330 }
331 else
332 {
333 kdWarning() << "Don't have any context to set!" << endl;
334 }
335 painter.setClipRect(rect, TQPainter::CoordPainter);
336 // We don't support zoom yet, so use the painters scaling
337 double d_zoom = 1.0;
338 setZoomAndResolution(100, KoGlobal::dpiX(), KoGlobal::dpiY());
339 if ( m_zoomedResolutionX != zoomX ) {
340 d_zoom *= ( zoomX / m_zoomedResolutionX );
341 painter.scale(d_zoom, d_zoom);
342 }
343
344 m_embeddedGanttView->clear();
345 m_embeddedGanttView->draw(*m_project);
346 m_embeddedGanttView->drawOnPainter(&painter,rect);
347 }
348 // ####### handle transparency
349
350 // Need to draw only the document rectangle described in the parameter rect.
351// int left = rect.left() / 20;
352// int right = rect.right() / 20 + 1;
353// int top = rect.top() / 20;
354// int bottom = rect.bottom() / 20 + 1;
355
356// for( int x = left; x < right; ++x )
357// painter.drawLine( x * 40, top * 20, 40 * 20, bottom * 20 );
358// for( int y = left; y < right; ++y )
359// painter.drawLine( left * 20, y * 20, right * 20, y * 20 );
360}
361
362
363void Part::addCommand(KCommand * cmd, bool execute)
364{
365 m_commandHistory->addCommand(cmd, execute);
366}
367
368void Part::slotCommandExecuted() {
369 //kdDebug()<<k_funcinfo<<endl;
370 setModified(true);
371 kdDebug() << "------- KPlato, is embedded: " << isEmbedded() << endl;
372 if (m_view == NULL)
373 return;
374
375 if (m_calculate)
376 m_view->slotUpdate(false/*config().behavior().calculationMode == Behavior::OnChange*/);
377 else if (m_update)
378 m_view->slotUpdate(false);
379
380 if (m_baseline)
381 m_view->setBaselineMode(getProject().isBaselined());
382
383 m_update = m_calculate = m_baseline = false;
384}
385
386void Part::slotCopyContextFromView()
387{
388 if (m_view)
389 {
390// kdDebug() << "Updating embedded context from view context." << endl;
391 this->m_view->getContext( *m_embeddedContext );
392 this->m_embeddedContextInitialized = true;
393 }
394// else
395// {
396// kdDebug() << "Not updating the context." << endl;
397// if (m_context)
398// kdDebug() << "Current View: " << m_context->currentView << endl;
399// }
400}
401
402void Part::slotViewDestroyed()
403{
404 m_view = NULL;
405}
406
407void Part::setCommandType(int type) {
408 //kdDebug()<<k_funcinfo<<"type="<<type<<endl;
409 if (type == 0)
410 m_update = true;
411 else if (type == 1)
412 m_calculate = true;
413 else if (type == 2)
414 m_baseline = true;
415}
416
417void Part::generateWBS() {
418 m_project->generateWBS(1, m_wbsDefinition);
419}
420
421} //KPlato namespace
422
423#include "kptpart.moc"