/* This file is part of the KDE project Copyright (C) 1998, 1999, 2000 Torben Weis <weis@kde.org> Copyright (C) 2004, 2005 Dag Andersen <danders@get2net.dk> Copyright (C) 2006 Raphael Langerhorst <raphael.langerhorst@kdemail.net> Copyright (C) 2006 Dag Andersen <danders@get2net.dk> This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include "kptpart.h" #include "kptview.h" #include "kptfactory.h" #include "kptproject.h" #include "kptprojectdialog.h" #include "kptresource.h" #include "kptcontext.h" #include "kptganttview.h" #include "KDGanttViewTaskLink.h" #include <tqpainter.h> #include <tqfileinfo.h> #include <kdebug.h> #include <tdeconfig.h> #include <tdelocale.h> #include <tdemessagebox.h> #include <kstandarddirs.h> #include <kcommand.h> #include <KoTemplateChooseDia.h> #include <KoCommandHistory.h> #include <KoGlobal.h> #define CURRENT_SYNTAX_VERSION "0.5" namespace KPlato { Part::Part(TQWidget *parentWidget, const char *widgetName, TQObject *parent, const char *name, bool singleViewMode) : KoDocument(parentWidget, widgetName, parent, name, singleViewMode), m_project(0), m_projectDialog(0), m_parentWidget(parentWidget), m_view(0), m_embeddedGanttView(new GanttView(parentWidget)), m_embeddedContext(new Context()), m_embeddedContextInitialized(false), m_context(0), m_xmlLoader() { m_update = m_calculate = false; m_commandHistory = new KoCommandHistory(actionCollection()); setInstance(Factory::global()); setTemplateType("kplato_template"); m_config.setReadWrite(isReadWrite()|| !isEmbedded()); m_config.load(); delete m_project; m_project = new Project(); // after config is loaded connect(m_commandHistory, TQT_SIGNAL(commandExecuted()), TQT_SLOT(slotCommandExecuted())); connect(m_commandHistory, TQT_SIGNAL(documentRestored()), TQT_SLOT(slotDocumentRestored())); //FIXME the following is really dirty, we should make KPlato::Context a real class // with getter and setter and signals when content changes, thus we can keep track TQTimer* timer = new TQTimer(this,"context update timer"); connect(timer,TQT_SIGNAL(timeout()),this,TQT_SLOT(slotCopyContextFromView())); timer->start(500); } Part::~Part() { m_config.save(); delete m_commandHistory; // before project, in case of dependencies... delete m_project; delete m_projectDialog; if (m_embeddedGanttView) { delete m_embeddedGanttView; m_embeddedGanttView = 0L; } if (m_embeddedContext) { delete m_embeddedContext; m_embeddedContext = 0L; } } bool Part::initDoc(InitDocFlags flags, TQWidget* parentWidget) { bool result = true; if (flags==KoDocument::InitDocEmpty) { delete m_project; m_project = new Project(); setAutoSave(0); // disable setModified(false); return true; } TQString templateDoc; KoTemplateChooseDia::ReturnType ret; KoTemplateChooseDia::DialogType dlgtype; if (flags != KoDocument::InitDocFileNew ) dlgtype = KoTemplateChooseDia::Everything; else dlgtype = KoTemplateChooseDia::OnlyTemplates; ret = KoTemplateChooseDia::choose(Factory::global(), templateDoc, dlgtype, "kplato_template", parentWidget); if (ret == KoTemplateChooseDia::Template) { resetURL(); result = loadNativeFormat(templateDoc); if ( !result ) showLoadingErrorDialog(); } else if (ret == KoTemplateChooseDia::File) { KURL url(templateDoc); kdDebug() << "Part::initDoc opening URL " << url.prettyURL() <<endl; result = openURL(url); } else if (ret == KoTemplateChooseDia::Empty) { // Make a fresh project and let the user enter some info delete m_project; m_project = new Project(); // an emty project should be empty // m_projectDialog = new ProjectDialog(*m_project, m_view); // m_projectDialog->exec(); result = true; } else { result = false; } setAutoSave(0); // disable setModified(false); return result; } KoView *Part::createViewInstance(TQWidget *parent, const char *name) { m_view = new View(this, parent, name); connect(m_view,TQT_SIGNAL(destroyed()),this,TQT_SLOT(slotViewDestroyed())); // If there is a project dialog this should be deleted so it will // use the m_view as parent. If the dialog will be needed again, // it will be made at that point if (m_projectDialog != 0) { kdDebug() << "Deleting m_projectDialog because of new ViewInstance\n"; delete m_projectDialog; m_projectDialog = 0; } if (m_context) m_view->setContext( *m_context ); else if (m_embeddedContext && m_embeddedContextInitialized) m_view->setContext( *m_embeddedContext ); else { // Activate menu actions. Assumes ganttview, we don't get any // 'aboutToShow' signal. Need to redo action control. m_view->setTaskActionsEnabled(true); } //m_view->setBaselineMode(getProject().isBaselined()); FIXME: Removed for this release return m_view; } void Part::editProject() { TQWidget* parent = m_parentWidget; if (m_view) parent = m_view; if (m_projectDialog == 0) // Make the dialog m_projectDialog = new ProjectDialog(*m_project, parent); m_projectDialog->exec(); } bool Part::loadXML(TQIODevice *, const TQDomDocument &document) { TQTime dt; dt.start(); emit sigProgress( 0 ); TQString value; TQDomElement plan = document.documentElement(); // Check if this is the right app value = plan.attribute("mime", TQString()); if (value.isEmpty()) { kdError() << "No mime type specified!" << endl; setErrorMessage(i18n("Invalid document. No mimetype specified.")); return false; } else if (value != "application/x-vnd.kde.kplato") { kdError() << "Unknown mime type " << value << endl; setErrorMessage(i18n("Invalid document. Expected mimetype application/x-vnd.kde.kplato, got %1").arg(value)); return false; } TQString m_syntaxVersion = plan.attribute("version", CURRENT_SYNTAX_VERSION); if (m_syntaxVersion > CURRENT_SYNTAX_VERSION) { int ret = KMessageBox::warningContinueCancel( 0, i18n("This document was created with a newer version of KPlato (syntax version: %1)\n" "Opening it in this version of KPlato will lose some information.").arg(m_syntaxVersion), i18n("File-Format Mismatch"), i18n("Continue") ); if (ret == KMessageBox::Cancel) { setErrorMessage("USER_CANCELED"); return false; } } emit sigProgress(5); TQDomNodeList list = plan.childNodes(); if (list.count() > 2) { // TODO: Make a proper bitching about this kdDebug() << "*** Error ***\n"; kdDebug() << " Children count should be 1 but is " << list.count() << "\n"; return false; } m_xmlLoader.startLoad(); for (unsigned int i = 0; i < list.count(); ++i) { if (list.item(i).isElement()) { TQDomElement e = list.item(i).toElement(); if (e.tagName() == "context") { delete m_context; m_context = new Context(); m_context->load(e); } else if (e.tagName() == "project") { Project *newProject = new Project(); if (newProject->load(e)) { // The load went fine. Throw out the old project delete m_project; m_project = newProject; delete m_projectDialog; m_projectDialog = 0; } else { delete newProject; m_xmlLoader.addMsg(XMLLoaderObject::Errors, "Loading of project failed"); //TODO add some ui here } } } } m_xmlLoader.stopLoad(); emit sigProgress(100); // the rest is only processing, not loading kdDebug() << "Loading took " << (float)(dt.elapsed()) / 1000 << " seconds" << endl; // do some sanity checking on document. emit sigProgress(-1); m_commandHistory->clear(); m_commandHistory->documentSaved(); setModified( false ); if (m_view) m_view->slotUpdate(false); return true; } TQDomDocument Part::saveXML() { TQDomDocument document("kplato"); document.appendChild(document.createProcessingInstruction( "xml", "version=\"1.0\" encoding=\"UTF-8\"")); TQDomElement doc = document.createElement("kplato"); doc.setAttribute("editor", "KPlato"); doc.setAttribute("mime", "application/x-vnd.kde.kplato"); doc.setAttribute("version", CURRENT_SYNTAX_VERSION); document.appendChild(doc); delete m_context; m_context = 0; if (m_view) { m_context = new Context(); m_view->getContext(*m_context); } if (m_context) { m_context->save(doc); } // Save the project m_project->save(doc); m_commandHistory->documentSaved(); return document; } void Part::slotDocumentRestored() { //kdDebug()<<k_funcinfo<<endl; setModified(false); } void Part::paintContent(TQPainter &painter, const TQRect &rect, bool /*transparent*/, double zoomX, double /*zoomY*/) { kdDebug() << "----------- KPlato: Part::paintContent ------------" << endl; if (isEmbedded() && m_embeddedGanttView && m_project) { if (m_embeddedContext) { int ganttsize = m_embeddedContext->ganttview.ganttviewsize; int tasksize = m_embeddedContext->ganttview.taskviewsize; bool showtaskname = m_embeddedContext->ganttview.showTaskName; // m_embeddedContext->ganttview.ganttviewsize += m_embeddedContext->ganttview.taskviewsize; // m_embeddedContext->ganttview.taskviewsize = 0; //TODO this doesn't have any effect?! (bug?) m_embeddedContext->ganttview.showTaskName = true; //since task view is not shown(?), show name in the gantt itself m_embeddedGanttView->setContext( m_embeddedContext->ganttview, *m_project ); m_embeddedContext->ganttview.ganttviewsize = ganttsize; m_embeddedContext->ganttview.taskviewsize = tasksize; m_embeddedContext->ganttview.showTaskName = showtaskname; } else { kdWarning() << "Don't have any context to set!" << endl; } painter.setClipRect(rect, TQPainter::CoordPainter); // We don't support zoom yet, so use the painters scaling double d_zoom = 1.0; setZoomAndResolution(100, KoGlobal::dpiX(), KoGlobal::dpiY()); if ( m_zoomedResolutionX != zoomX ) { d_zoom *= ( zoomX / m_zoomedResolutionX ); painter.scale(d_zoom, d_zoom); } m_embeddedGanttView->clear(); m_embeddedGanttView->draw(*m_project); m_embeddedGanttView->drawOnPainter(&painter,rect); } // ####### handle transparency // Need to draw only the document rectangle described in the parameter rect. // int left = rect.left() / 20; // int right = rect.right() / 20 + 1; // int top = rect.top() / 20; // int bottom = rect.bottom() / 20 + 1; // for( int x = left; x < right; ++x ) // painter.drawLine( x * 40, top * 20, 40 * 20, bottom * 20 ); // for( int y = left; y < right; ++y ) // painter.drawLine( left * 20, y * 20, right * 20, y * 20 ); } void Part::addCommand(KCommand * cmd, bool execute) { m_commandHistory->addCommand(cmd, execute); } void Part::slotCommandExecuted() { //kdDebug()<<k_funcinfo<<endl; setModified(true); kdDebug() << "------- KPlato, is embedded: " << isEmbedded() << endl; if (m_view == NULL) return; if (m_calculate) m_view->slotUpdate(false/*config().behavior().calculationMode == Behavior::OnChange*/); else if (m_update) m_view->slotUpdate(false); if (m_baseline) m_view->setBaselineMode(getProject().isBaselined()); m_update = m_calculate = m_baseline = false; } void Part::slotCopyContextFromView() { if (m_view) { // kdDebug() << "Updating embedded context from view context." << endl; this->m_view->getContext( *m_embeddedContext ); this->m_embeddedContextInitialized = true; } // else // { // kdDebug() << "Not updating the context." << endl; // if (m_context) // kdDebug() << "Current View: " << m_context->currentView << endl; // } } void Part::slotViewDestroyed() { m_view = NULL; } void Part::setCommandType(int type) { //kdDebug()<<k_funcinfo<<"type="<<type<<endl; if (type == 0) m_update = true; else if (type == 1) m_calculate = true; else if (type == 2) m_baseline = true; } void Part::generateWBS() { m_project->generateWBS(1, m_wbsDefinition); } } //KPlato namespace #include "kptpart.moc"