kplato

kptpart.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 1998, 1999, 2000 Torben Weis <weis@kde.org>
00003    Copyright (C) 2004, 2005 Dag Andersen <danders@get2net.dk>
00004    Copyright (C) 2006 Raphael Langerhorst <raphael.langerhorst@kdemail.net>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "kptpart.h"
00023 #include "kptview.h"
00024 #include "kptfactory.h"
00025 #include "kptproject.h"
00026 #include "kptprojectdialog.h"
00027 #include "kptresource.h"
00028 #include "kptcontext.h"
00029 #include "kptganttview.h"
00030 #include "KDGanttViewTaskLink.h"
00031 
00032 #include <qpainter.h>
00033 #include <qfileinfo.h>
00034 
00035 #include <kdebug.h>
00036 #include <kconfig.h>
00037 #include <klocale.h>
00038 #include <kmessagebox.h>
00039 #include <kstandarddirs.h>
00040 #include <kcommand.h>
00041 #include <KoTemplateChooseDia.h>
00042 #include <KoCommandHistory.h>
00043 #include <KoGlobal.h>
00044 
00045 #define CURRENT_SYNTAX_VERSION "0.3"
00046 
00047 namespace KPlato
00048 {
00049 
00050 Part::Part(QWidget *parentWidget, const char *widgetName,
00051          QObject *parent, const char *name, bool singleViewMode)
00052     : KoDocument(parentWidget, widgetName, parent, name, singleViewMode),
00053       m_project(0), m_projectDialog(0), m_parentWidget(parentWidget), m_view(0),
00054       m_embeddedGanttView(new GanttView(parentWidget)),
00055       m_embeddedContext(new Context()), m_embeddedContextInitialized(false),
00056       m_context(0), m_xmlLoader()
00057 {
00058     m_update = m_calculate = false;
00059     m_commandHistory = new KoCommandHistory(actionCollection());
00060 
00061     setInstance(Factory::global());
00062     setTemplateType("kplato_template");
00063     m_config.setReadWrite(isReadWrite()|| !isEmbedded());
00064     m_config.load();
00065 
00066     delete m_project;
00067     m_project = new Project(); // after config is loaded
00068 
00069     connect(m_commandHistory, SIGNAL(commandExecuted()), SLOT(slotCommandExecuted()));
00070     connect(m_commandHistory, SIGNAL(documentRestored()), SLOT(slotDocumentRestored()));
00071 
00072     //FIXME the following is really dirty, we should make KPlato::Context a real class
00073     //      with getter and setter and signals when content changes, thus we can keep track
00074     QTimer* timer = new QTimer(this,"context update timer");
00075     connect(timer,SIGNAL(timeout()),this,SLOT(slotCopyContextFromView()));
00076     timer->start(500);
00077 }
00078 
00079 
00080 Part::~Part() {
00081     m_config.save();
00082     delete m_project;
00083     delete m_projectDialog;
00084     delete m_commandHistory;
00085     if (m_embeddedGanttView)
00086       delete m_embeddedGanttView;
00087     if (m_embeddedContext)
00088       delete m_embeddedContext;
00089 }
00090 
00091 
00092 bool Part::initDoc(InitDocFlags flags, QWidget* parentWidget) {
00093     bool result = true;
00094 
00095     if (flags==KoDocument::InitDocEmpty)
00096     {
00097         delete m_project;
00098         m_project = new Project();
00099         setAutoSave(0); // disable
00100         setModified(false);
00101         return true;
00102     }
00103 
00104     QString templateDoc;
00105     KoTemplateChooseDia::ReturnType ret;
00106     KoTemplateChooseDia::DialogType dlgtype;
00107     if (flags != KoDocument::InitDocFileNew )
00108         dlgtype = KoTemplateChooseDia::Everything;
00109     else
00110         dlgtype = KoTemplateChooseDia::OnlyTemplates;
00111 
00112     ret = KoTemplateChooseDia::choose(Factory::global(), templateDoc,
00113                                       dlgtype,
00114                                       "kplato_template",
00115                                       parentWidget);
00116     if (ret == KoTemplateChooseDia::Template) {
00117         resetURL();
00118         result = loadNativeFormat(templateDoc);
00119         if ( !result )
00120             showLoadingErrorDialog();
00121     } else if (ret == KoTemplateChooseDia::File) {
00122         KURL url(templateDoc);
00123         kdDebug() << "Part::initDoc opening URL " << url.prettyURL() <<endl;
00124         result = openURL(url);
00125     } else if (ret == KoTemplateChooseDia::Empty) {
00126         // Make a fresh project and let the user enter some info
00127         delete m_project;
00128         m_project = new Project();
00129        // an emty project should be empty
00130         // m_projectDialog = new ProjectDialog(*m_project, m_view);
00131         // m_projectDialog->exec();
00132 
00133         result = true;
00134     } else {
00135         result = false;
00136     }
00137     setAutoSave(0); // disable
00138     setModified(false);
00139     return result;
00140 }
00141 
00142 
00143 KoView *Part::createViewInstance(QWidget *parent, const char *name) {
00144     m_view = new View(this, parent, name);
00145     connect(m_view,SIGNAL(destroyed()),this,SLOT(slotViewDestroyed()));
00146 
00147     // If there is a project dialog this should be deleted so it will
00148     // use the m_view as parent. If the dialog will be needed again,
00149     // it will be made at that point
00150     if (m_projectDialog != 0) {
00151     kdDebug() << "Deleting m_projectDialog because of new ViewInstance\n";
00152     delete m_projectDialog;
00153     m_projectDialog = 0;
00154     }
00155     if (m_context)
00156         m_view->setContext( *m_context );
00157     else if (m_embeddedContext && m_embeddedContextInitialized)
00158         m_view->setContext( *m_embeddedContext );
00159     else {
00160         // Activate menu actions. Assumes ganttview, we don't get any 
00161         // 'aboutToShow' signal. Need to redo action control.
00162         m_view->setTaskActionsEnabled(true);
00163     }
00164     //m_view->setBaselineMode(getProject().isBaselined()); FIXME: Removed for this release  
00165     return m_view;
00166 }
00167 
00168 
00169 void Part::editProject() {
00170 
00171     QWidget* parent = m_parentWidget;
00172     if (m_view)
00173       parent = m_view;
00174       
00175     if (m_projectDialog == 0)
00176     // Make the dialog
00177     m_projectDialog = new ProjectDialog(*m_project, parent);
00178 
00179     m_projectDialog->exec();
00180 }
00181 
00182 
00183 bool Part::loadXML(QIODevice *, const QDomDocument &document) {
00184     QTime dt;
00185     dt.start();
00186     emit sigProgress( 0 );
00187 
00188     QString value;
00189     QDomElement plan = document.documentElement();
00190 
00191     // Check if this is the right app
00192     value = plan.attribute("mime", QString::null);
00193     if (value.isEmpty()) {
00194         kdError() << "No mime type specified!" << endl;
00195         setErrorMessage(i18n("Invalid document. No mimetype specified."));
00196         return false;
00197     }
00198     else if (value != "application/x-vnd.kde.kplato") {
00199         kdError() << "Unknown mime type " << value << endl;
00200         setErrorMessage(i18n("Invalid document. Expected mimetype application/x-vnd.kde.kplato, got %1").arg(value));
00201         return false;
00202     }
00203     QString m_syntaxVersion = plan.attribute("version", CURRENT_SYNTAX_VERSION);
00204     if (m_syntaxVersion > CURRENT_SYNTAX_VERSION) {
00205         int ret = KMessageBox::warningContinueCancel(
00206             0, i18n("This document was created with a newer version of KPlato (syntax version: %1)\n"
00207                     "Opening it in this version of KPlato will lose some information.").arg(m_syntaxVersion),
00208             i18n("File-Format Mismatch"), i18n("Continue") );
00209         if (ret == KMessageBox::Cancel)
00210         {
00211             setErrorMessage("USER_CANCELED");
00212             return false;
00213         }
00214     }
00215     emit sigProgress(5);
00216 
00217     QDomNodeList list = plan.childNodes();
00218     if (list.count() > 2) {
00219         // TODO: Make a proper bitching about this
00220         kdDebug() << "*** Error ***\n";
00221         kdDebug() << "  Children count should be 1 but is " << list.count()
00222                 << "\n";
00223         return false;
00224     }
00225     m_xmlLoader.startLoad();
00226     for (unsigned int i = 0; i < list.count(); ++i) {
00227         if (list.item(i).isElement()) {
00228             QDomElement e = list.item(i).toElement();
00229 
00230             if (e.tagName() == "context") {
00231                 delete m_context;
00232                 m_context = new Context();
00233                 m_context->load(e);
00234             } else if (e.tagName() == "project") {
00235                 Project *newProject = new Project();
00236                 if (newProject->load(e)) {
00237                     // The load went fine. Throw out the old project
00238                     delete m_project;
00239                     m_project = newProject;
00240                     delete m_projectDialog;
00241                     m_projectDialog = 0;
00242                 }
00243                 else {
00244                     delete newProject;
00245                     m_xmlLoader.addMsg(XMLLoaderObject::Errors, "Loading of project failed");
00246                     //TODO add some ui here
00247                 }
00248             }
00249         }
00250     }
00251     m_xmlLoader.stopLoad();
00252     emit sigProgress(100); // the rest is only processing, not loading
00253 
00254     kdDebug() << "Loading took " << (float)(dt.elapsed()) / 1000 << " seconds" << endl;
00255 
00256     // do some sanity checking on document.
00257     emit sigProgress(-1);
00258 
00259     m_commandHistory->clear();
00260     m_commandHistory->documentSaved();
00261     setModified( false );
00262     if (m_view)
00263         m_view->slotUpdate(false);
00264     return true;
00265 }
00266 
00267 QDomDocument Part::saveXML() {
00268     QDomDocument document("kplato");
00269 
00270     document.appendChild(document.createProcessingInstruction(
00271             "xml",
00272             "version=\"1.0\" encoding=\"UTF-8\""));
00273 
00274     QDomElement doc = document.createElement("kplato");
00275     doc.setAttribute("editor", "KPlato");
00276     doc.setAttribute("mime", "application/x-vnd.kde.kplato");
00277     doc.setAttribute("version", CURRENT_SYNTAX_VERSION);
00278     document.appendChild(doc);
00279 
00280     delete m_context;
00281     m_context = 0;
00282     if (m_view) {
00283         m_context = new Context();
00284         m_view->getContext(*m_context);
00285     }
00286     if (m_context) {
00287         m_context->save(doc);
00288     }
00289     // Save the project
00290     m_project->save(doc);
00291 
00292     m_commandHistory->documentSaved();
00293     return document;
00294 }
00295 
00296 
00297 void Part::slotDocumentRestored() {
00298     //kdDebug()<<k_funcinfo<<endl;
00299     setModified(false);
00300 }
00301 
00302 
00303 void Part::paintContent(QPainter &painter, const QRect &rect,
00304                bool /*transparent*/,
00305                double zoomX, double /*zoomY*/)
00306 {
00307     kdDebug() << "----------- KPlato: Part::paintContent ------------" << endl;
00308     if (isEmbedded() && m_embeddedGanttView && m_project)
00309     {
00310         if (m_embeddedContext)
00311         {
00312             int ganttsize = m_embeddedContext->ganttview.ganttviewsize;
00313             int tasksize = m_embeddedContext->ganttview.taskviewsize;
00314             bool showtaskname = m_embeddedContext->ganttview.showTaskName;
00315             
00316 //            m_embeddedContext->ganttview.ganttviewsize += m_embeddedContext->ganttview.taskviewsize;
00317 //            m_embeddedContext->ganttview.taskviewsize = 0;  //TODO this doesn't have any effect?! (bug?)
00318             m_embeddedContext->ganttview.showTaskName = true;  //since task view is not shown(?), show name in the gantt itself
00319             
00320             m_embeddedGanttView->setContext( m_embeddedContext->ganttview, *m_project );
00321             
00322             m_embeddedContext->ganttview.ganttviewsize = ganttsize;
00323             m_embeddedContext->ganttview.taskviewsize = tasksize;
00324             m_embeddedContext->ganttview.showTaskName = showtaskname;
00325         }
00326         else
00327         {
00328             kdWarning() << "Don't have any context to set!" << endl;
00329         }
00330         painter.setClipRect(rect, QPainter::CoordPainter);
00331         // We don't support zoom yet, so use the painters scaling
00332         double d_zoom = 1.0;
00333         setZoomAndResolution(100, KoGlobal::dpiX(), KoGlobal::dpiY());
00334         if ( m_zoomedResolutionX != zoomX ) {
00335             d_zoom *= ( zoomX / m_zoomedResolutionX );
00336             painter.scale(d_zoom, d_zoom);
00337         }
00338         
00339         m_embeddedGanttView->clear();
00340         m_embeddedGanttView->draw(*m_project);
00341         m_embeddedGanttView->drawOnPainter(&painter,rect);
00342     }
00343     // ####### handle transparency
00344 
00345     // Need to draw only the document rectangle described in the parameter rect.
00346 //     int left = rect.left() / 20;
00347 //     int right = rect.right() / 20 + 1;
00348 //     int top = rect.top() / 20;
00349 //     int bottom = rect.bottom() / 20 + 1;
00350 
00351 //     for( int x = left; x < right; ++x )
00352 //         painter.drawLine( x * 40, top * 20, 40 * 20, bottom * 20 );
00353 //     for( int y = left; y < right; ++y )
00354 //         painter.drawLine( left * 20, y * 20, right * 20, y * 20 );
00355 }
00356 
00357 
00358 void Part::addCommand(KCommand * cmd, bool execute)
00359 {
00360     m_commandHistory->addCommand(cmd, execute);
00361 }
00362 
00363 void Part::slotCommandExecuted() {
00364     //kdDebug()<<k_funcinfo<<endl;
00365     setModified(true);
00366     kdDebug() << "------- KPlato, is embedded: " << isEmbedded() << endl;
00367     if (m_view == NULL)
00368       return;
00369       
00370     if (m_calculate)
00371         m_view->slotUpdate(false/*config().behavior().calculationMode == Behavior::OnChange*/);
00372     else if (m_update)
00373         m_view->slotUpdate(false);
00374 
00375     if (m_baseline)
00376         m_view->setBaselineMode(getProject().isBaselined());
00377 
00378     m_update = m_calculate = m_baseline = false;
00379 }
00380 
00381 void Part::slotCopyContextFromView()
00382 {
00383     if (m_view)
00384     {
00385 //         kdDebug() << "Updating embedded context from view context." << endl;
00386         this->m_view->getContext( *m_embeddedContext );
00387         this->m_embeddedContextInitialized = true;
00388     }
00389 //     else
00390 //     {
00391 //         kdDebug() << "Not updating the context." << endl;
00392 //         if (m_context)
00393 //           kdDebug() << "Current View: " << m_context->currentView << endl;
00394 //     }
00395 }
00396 
00397 void Part::slotViewDestroyed()
00398 {
00399     m_view = NULL;
00400 }
00401 
00402 void Part::setCommandType(int type) {
00403     //kdDebug()<<k_funcinfo<<"type="<<type<<endl;
00404     if (type == 0)
00405         m_update = true;
00406     else if (type == 1)
00407         m_calculate = true;
00408     else if (type == 2)
00409         m_baseline = true;
00410 }
00411 
00412 void Part::generateWBS() {
00413     m_project->generateWBS(1, m_wbsDefinition);
00414 }
00415 
00416 }  //KPlato namespace
00417 
00418 #include "kptpart.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys