kplato

kptganttview.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2002 - 2005 Dag Andersen <danders@get2net.dk>
00003    Copyright (C) 2006 Raphael Langerhorst <raphael.langerhorst@kdemail.net>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation;
00008    version 2 of the License.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "kptganttview.h"
00022 
00023 #include "kptappointment.h"
00024 #include "kptpart.h"
00025 #include "kptview.h"
00026 #include "kptcanvasitem.h"
00027 #include "kptnode.h"
00028 #include "kptpart.h"
00029 #include "kptproject.h"
00030 #include "kpttask.h"
00031 #include "kptresource.h"
00032 #include "kptdatetime.h"
00033 #include "kpttaskappointmentsview.h"
00034 #include "kptrelation.h"
00035 #include "kptcontext.h"
00036 #include "kptschedule.h"
00037 
00038 #include "KDGanttView.h"
00039 #include "KDGanttViewItem.h"
00040 #include "KDGanttViewTaskItem.h"
00041 #include "KDGanttViewSummaryItem.h"
00042 #include "KDGanttViewEventItem.h"
00043 
00044 #include <kdebug.h>
00045 
00046 #include <qsplitter.h>
00047 #include <qvbox.h>
00048 #include <qlayout.h>
00049 #include <qlistview.h>
00050 #include <qheader.h>
00051 #include <qpopupmenu.h>
00052 #include <qtabwidget.h>
00053 #include <qptrlist.h>
00054 #include <qlineedit.h>
00055 #include <qwidget.h>
00056 #include <qlabel.h>
00057 #include <qspinbox.h>
00058 #include <qvaluelist.h>
00059 #include <qpainter.h> 
00060 #include <qpaintdevicemetrics.h> 
00061 
00062 #include <klocale.h>
00063 #include <kglobal.h>
00064 #include <kprinter.h>
00065 #include <kmessagebox.h>
00066 
00067 namespace KPlato
00068 {
00069 
00070 class MyKDGanttView : public KDGanttView {
00071 public:
00072     MyKDGanttView(QWidget *parent, const char *name)
00073     : KDGanttView(parent, name) {
00074     }
00075     virtual QSize sizeHint() const {
00076         return minimumSizeHint(); //HACK: koshell splitter minimumSize problem
00077     }
00078 };
00079 
00080 GanttView::GanttView(QWidget *parent, bool readWrite, const char* name)
00081     : QSplitter(parent, name),
00082     m_readWrite(readWrite),
00083     m_currentItem(0),
00084     m_taskView(0),
00085     m_firstTime(true),
00086     m_project(0)
00087 {
00088     kdDebug() << " ---------------- KPlato: Creating GanttView ----------------" << endl;
00089     setOrientation(QSplitter::Vertical);
00090     
00091     m_gantt = new MyKDGanttView(this, "Gantt view");
00092     
00093     m_showExpected = true;
00094     m_showOptimistic = false;
00095     m_showPessimistic = false;
00096     m_showResources = false; // FIXME
00097     m_showTaskName = false; // FIXME
00098     m_showTaskLinks = false; // FIXME
00099     m_showProgress = false; //FIXME
00100     m_showPositiveFloat = false; //FIXME
00101     m_showCriticalTasks = false; //FIXME
00102     m_showCriticalPath = false; //FIXME
00103     m_showNoInformation = false; //FIXME
00104     m_showAppointments = false;
00105     
00106     m_gantt->setHeaderVisible(true);
00107     m_gantt->addColumn(i18n("Work Breakdown Structure", "WBS"));
00108     // HACK: need changes to kdgantt
00109     KDGanttViewTaskItem *item = new KDGanttViewTaskItem(m_gantt);
00110     QListView *lv = item->listView();
00111     lv->header()->moveSection(1, 0);
00112     
00113     m_gantt->setScale(KDGanttView::Day);
00114     m_gantt->setShowLegendButton(false);
00115     m_gantt->setShowHeaderPopupMenu();
00116     m_taskView = new TaskAppointmentsView(this);
00117     // hide TaskAppointmentsView
00118     QValueList<int> list = sizes();
00119     list[0] += list[1];
00120     list[1] = 0;
00121     setSizes(list);
00122     m_taskView->hide();
00123     
00124     setReadWriteMode(readWrite);
00125     
00126     connect(m_gantt, SIGNAL(lvContextMenuRequested ( KDGanttViewItem *, const QPoint &, int )),
00127                  this, SLOT (popupMenuRequested(KDGanttViewItem *, const QPoint &, int)));
00128 
00129     connect(m_gantt, SIGNAL(lvCurrentChanged(KDGanttViewItem*)), this, SLOT (currentItemChanged(KDGanttViewItem*)));
00130 
00131     // HACK: kdgantt emits 2 signals for each *double* click, so we go direct to listview
00132     connect(lv, SIGNAL(doubleClicked(QListViewItem*, const QPoint&, int)), this, SLOT (slotItemDoubleClicked(QListViewItem*)));
00133 
00134     m_taskLinks.setAutoDelete(true);
00135     
00136     if (m_gantt->firstChild()) {
00137         m_gantt->firstChild()->listView()->setCurrentItem(m_gantt->firstChild());
00138         m_gantt->firstChild()->listView()->setFocus();
00139     }
00140 }
00141 
00142 void GanttView::setZoom(double zoom)
00143 {
00144   kdDebug() << "setting gantt zoom: " << zoom << endl;
00145   m_gantt->setZoomFactor(zoom,true);
00146   m_taskView->zoom( zoom );
00147 }
00148 
00149 void GanttView::clear()
00150 {
00151     m_gantt->clear();
00152     m_taskView->clear();
00153 }
00154 
00155 void GanttView::draw(Project &project)
00156 {
00157     m_project = &project;
00158     //kdDebug()<<k_funcinfo<<endl;
00159     Schedule::Type type = Schedule::Expected;
00160     if (m_showOptimistic) {
00161         type = Schedule::Optimistic;
00162     } else if (m_showPessimistic) {
00163         type = Schedule::Pessimistic;
00164     }
00165     Schedule *sch = project.findSchedule(type);
00166     if (sch) {
00167         project.setCurrentSchedule(sch->id());
00168     }
00169     //kdDebug()<<k_funcinfo<<"Schedule: "<<(sch?sch->typeToString():"None")<<endl;
00170     m_gantt->setUpdateEnabled(false);
00171 
00172     clear();
00173     drawChildren(NULL, project);
00174     drawRelations();
00175     
00176     if (m_firstTime) {
00177         m_gantt->centerTimelineAfterShow(project.startTime().addDays(-1));
00178         m_firstTime = false;
00179     }
00180     m_gantt->setUpdateEnabled(true);
00181     currentItemChanged(m_currentItem);
00182 }
00183 
00184 void GanttView::drawChanges(Project &project)
00185 {
00186     m_project = &project; //FIXME Only draw changes on same project
00187     //kdDebug()<<k_funcinfo<<endl;
00188     Schedule::Type type = Schedule::Expected;
00189     if (m_showOptimistic) {
00190         type = Schedule::Optimistic;
00191     } else if (m_showPessimistic) {
00192         type = Schedule::Pessimistic;
00193     }
00194     Schedule *sch = project.findSchedule(type);
00195     if (sch) {
00196         project.setCurrentSchedule(sch->id());
00197     }
00198     //kdDebug()<<k_funcinfo<<"Schedule: "<<(sch?sch->typeToString():"None")<<endl;
00199     m_gantt->setUpdateEnabled(false);
00200     resetDrawn(m_gantt->firstChild());
00201     updateChildren(&project); // don't draw project
00202     removeNotDrawn(m_gantt->firstChild());
00203     
00204     m_taskLinks.clear();
00205     drawRelations();
00206     
00207     m_gantt->setUpdateEnabled(true);
00208     if (m_currentItem == 0 && m_gantt->firstChild()) {
00209         m_gantt->firstChild()->listView()->setCurrentItem(m_gantt->firstChild());
00210         currentItemChanged(m_gantt->firstChild()); //hmmm
00211     }
00212     currentItemChanged(m_currentItem);
00213 }
00214 
00215 void GanttView::drawOnPainter(QPainter* painter, const QRect rect)
00216 {
00217     // Assume clipping is allready set
00218     
00219     // Fill out the rect by adding ticks to right side of the timeline
00220     QSize s = m_gantt->drawContents(0, false, true);
00221     while (s.width() < rect.width()) {
00222         m_gantt->addTicksRight();
00223         m_gantt->setTimelineToEnd();
00224         s = m_gantt->drawContents(0, false, true);
00225     }
00226     kdDebug()<<k_funcinfo<<rect<<" : "<<s<<endl;
00227     painter->save();
00228     
00229 //    QValueList<int> sizes = m_taskView->sizes();
00230 //    if (sizes.count() >= 2)
00231 //    {
00232 //        int first = sizes[0];
00233 //        int second = sizes[1];
00234 //        sizes.pop_front();
00235 //        sizes.pop_front();
00236 //        sizes.prepend(first+second);
00237 //        sizes.prepend(0);
00238 //        m_taskView->setSizes(sizes);
00239 //    }
00240 //    else
00241 //        kdWarning() << "Apparently the task view splitter contains less than 2 parts!" << endl;
00242 
00243 //    bool showlistview = m_gantt->showListView();
00244 //    int listviewwidth = m_gantt->listViewWidth();
00245 //    m_gantt->setShowListView(false);
00246 //    m_gantt->setListViewWidth(0);
00247   
00248 //    m_gantt->setGanttMaximumWidth(rect.x());
00249     m_gantt->drawContents(painter,false,true);
00250 //    m_gantt->setShowListView(showlistview);
00251 //    m_gantt->setListViewWidth(listviewwidth);
00252 
00253 //   m_taskView->drawContents(painter); //TODO doesn't seem to do very much
00254     painter->restore();
00255 }
00256 
00257 KDGanttViewItem *GanttView::findItem(Node *node)
00258 {
00259     return findItem(node, m_gantt->firstChild());
00260 }
00261 
00262 KDGanttViewItem *GanttView::findItem(Node *node, KDGanttViewItem *item)
00263 {
00264     for (; item; item = item->nextSibling()) {
00265         if (node == getNode(item)) {
00266             return item;
00267         }
00268         KDGanttViewItem *i = findItem(node, item->firstChild());
00269         if (i)
00270             return i;
00271     }
00272     return 0;
00273 }
00274 
00275 Node *GanttView::getNode(KDGanttViewItem *item) const {
00276     if (item) {
00277         if (item->type() == KDGanttViewItem::Event){
00278             return static_cast<GanttViewEventItem *>(item)->getTask();
00279         } else if (item->type() == KDGanttViewItem::Task) {
00280             return static_cast<GanttViewTaskItem *>(item)->getTask();
00281         } else if (item->type() == KDGanttViewItem::Summary) {
00282             return static_cast<GanttViewSummaryItem *>(item)->getNode();
00283         }
00284     }
00285     return 0;
00286 }
00287 
00288 bool GanttView::isDrawn(KDGanttViewItem *item) {
00289     if (item) {
00290         if (item->type() == KDGanttViewItem::Event){
00291             return static_cast<GanttViewEventItem *>(item)->isDrawn();
00292         } else if (item->type() == KDGanttViewItem::Task) {
00293             return static_cast<GanttViewTaskItem *>(item)->isDrawn();
00294         } else if (item->type() == KDGanttViewItem::Summary) {
00295             return static_cast<GanttViewSummaryItem *>(item)->isDrawn();
00296         } else {
00297             kdWarning()<<k_funcinfo<<"Unknown item type: "<<item->type()<<endl;
00298         }
00299     }
00300     return false;
00301 }
00302 
00303 void GanttView::setDrawn(KDGanttViewItem *item, bool state) {
00304     if (item) {
00305         if (item->type() == KDGanttViewItem::Event){
00306             static_cast<GanttViewEventItem *>(item)->setDrawn(state);
00307         } else if (item->type() == KDGanttViewItem::Task) {
00308             static_cast<GanttViewTaskItem *>(item)->setDrawn(state);
00309         } else if (item->type() == KDGanttViewItem::Summary) {
00310             static_cast<GanttViewSummaryItem *>(item)->setDrawn(state);
00311         } else {
00312             kdWarning()<<k_funcinfo<<"Unknown item type: "<<item->type()<<endl;
00313         }
00314     }
00315     return;
00316 }
00317 
00318 void GanttView::resetDrawn(KDGanttViewItem *_item)
00319 {
00320     KDGanttViewItem *nextItem, *item=_item;
00321     for (; item; item = nextItem) {
00322         nextItem = item->nextSibling();
00323         setDrawn(item, false);
00324         resetDrawn(item->firstChild()); // then my children
00325     }
00326 }
00327 
00328 void GanttView::removeNotDrawn(KDGanttViewItem *_item)
00329 {
00330     KDGanttViewItem *nextItem, *item=_item;
00331     for (; item; item = nextItem) {
00332         nextItem = item->nextSibling();
00333         if (!isDrawn(item)) {
00334             if (item == m_currentItem)
00335                 m_currentItem = 0;
00336             deleteItem(item);
00337         } else {
00338             removeNotDrawn(item->firstChild()); // then my children
00339         }
00340     }
00341 }
00342 
00343 void GanttView::deleteItem(KDGanttViewItem *item)
00344 {
00345     //kdDebug()<<k_funcinfo<<item->listViewText()<<endl;
00346     if (item->parent())
00347         item->parent()->takeItem(item);
00348     else
00349         item->listView()->takeItem(item);
00350     delete item;
00351 }
00352 
00353 KDGanttViewItem *GanttView::correctType(KDGanttViewItem *item, Node *node)
00354 {
00355     //kdDebug()<<k_funcinfo<<item->listViewText()<<": "<<item->type()<<" node: "<<node->type()<<endl;
00356     switch (node->type()) {
00357         case Node::Type_Project:
00358             return item;
00359             break;
00360         case Node::Type_Summarytask:
00361         case Node::Type_Subproject:
00362             if (item->type() == KDGanttViewItem::Summary)
00363                 return item;
00364             break;
00365         case Node::Type_Task:
00366             if (item->type() == KDGanttViewItem::Task)
00367                 return item;
00368             break;
00369         case Node::Type_Milestone:
00370             if (item->type() == KDGanttViewItem::Event)
00371                 return item;
00372             break;
00373         default:
00374             return item;
00375             break;
00376     }
00377     KDGanttViewItem *newItem = addNode(item->parent(), node, item);
00378     newItem->setOpen(item->isOpen());
00379     deleteItem(item);
00380     return newItem;
00381 }
00382 
00383 void GanttView::correctPosition(KDGanttViewItem *item, Node *node)
00384 {
00385     KDGanttViewItem *after = findItem(node->siblingBefore());
00386     if (after) {
00387         item->moveItem(after);
00388     }
00389 }
00390 
00391 KDGanttViewItem *GanttView::correctParent(KDGanttViewItem *item, Node *node)
00392 {
00393     KDGanttViewItem *p = findItem(node->getParent());
00394     if (p == item->parent()) {
00395         return item;
00396     }
00397     KDGanttViewItem *newItem = addNode(p, node);
00398     newItem->setOpen(item->isOpen());
00399     deleteItem(item);
00400     return newItem;
00401 }
00402 
00403 void GanttView::updateChildren(Node *parentNode)
00404 {
00405     //kdDebug()<<k_funcinfo<<endl;
00406     QPtrListIterator<Node> nit(parentNode->childNodeIterator());
00407     for (; nit.current(); ++nit )
00408     {
00409         updateNode(nit.current());
00410     }
00411 }
00412 
00413 void GanttView::updateNode(Node *node)
00414 {
00415     //kdDebug()<<k_funcinfo<<node->name()<<endl;
00416     KDGanttViewItem *item = findItem(node);
00417     if (!item) {
00418         item = addNode(findItem(node->getParent()), node, findItem(node->siblingBefore()));
00419         if (item && node->type() == Node::Type_Summarytask)
00420             updateChildren(node);
00421         return;
00422     }
00423     item = correctType(item, node);
00424     item = correctParent(item, node);
00425     correctPosition(item, node);
00426         
00427     modifyNode(node);
00428     
00429     if (node->type() == Node::Type_Summarytask)
00430         updateChildren(node);
00431 }
00432 
00433 void GanttView::modifyChildren(Node *node)
00434 {
00435     //kdDebug()<<k_funcinfo<<endl;
00436     QPtrListIterator<Node> nit(node->childNodeIterator());
00437     for ( nit.toLast(); nit.current(); --nit ) {
00438         modifyNode(nit.current());
00439         modifyChildren(nit.current());
00440     }
00441 }
00442 
00443 void GanttView::modifyNode(Node *node)
00444 {
00445     //kdDebug()<<k_funcinfo<<endl;
00446     KDGanttViewItem *item = findItem(node);
00447     if (!item) {
00448         kdDebug()<<k_funcinfo<<" Item not found"<<endl;
00449         return;
00450     }
00451     if (node->type() == Node::Type_Project) {
00452         return modifyProject(item, node);
00453     }
00454     if (node->type() == Node::Type_Subproject) {
00455         return modifyProject(item, node);
00456     }
00457     if (node->type() == Node::Type_Summarytask) {
00458         return modifySummaryTask(item, static_cast<Task *>(node));
00459     }
00460     if (node->type() == Node::Type_Task) {
00461         return modifyTask(item, static_cast<Task *>(node));
00462     }
00463     if (node->type() == Node::Type_Milestone) {
00464         return modifyMilestone(item, static_cast<Task *>(node));
00465     }
00466     return;
00467 }
00468 
00469 void GanttView::modifyProject(KDGanttViewItem *item, Node *node)
00470 {
00471     //kdDebug()<<k_funcinfo<<endl;
00472     item->setListViewText(node->name());
00473     item->setListViewText(1, node->wbs());
00474     item->setStartTime(node->startTime());
00475     item->setEndTime(node->endTime());
00476     //item->setOpen(true);
00477     setDrawn(item, true);
00478 
00479 }
00480 
00481 void GanttView::modifySummaryTask(KDGanttViewItem *item, Task *task)
00482 {
00483     //kdDebug()<<k_funcinfo<<endl;
00484     KLocale *locale = KGlobal::locale();
00485     //kdDebug()<<k_funcinfo<<task->name()<<": "<<task->currentSchedule()<<", "<<task->notScheduled()<<", "<<(m_project ? m_project->notScheduled() : false)<<endl;
00486     if (task->currentSchedule() == 0) {
00487         item->setShowNoInformation(m_showNoInformation);
00488         item->setStartTime(task->projectNode()->startTime());
00489         item->setEndTime(item->startTime().addDays(1));
00490     } else {
00491         bool noinf = m_showNoInformation && (task->notScheduled() || (m_project ? m_project->notScheduled() : false /*hmmm, no project?*/));
00492         item->setShowNoInformation(noinf);
00493         item->setStartTime(task->startTime());
00494         item->setEndTime(task->endTime());
00495     }
00496     item->setListViewText(task->name());
00497     item->setListViewText(1, task->wbs());
00498     //item->setOpen(true);
00499     if (m_showTaskName) {
00500         item->setText(task->name());
00501     } else {
00502         item->setText(QString());
00503     }    
00504     QString w = i18n("Name: %1").arg(task->name());
00505     if (!task->notScheduled()) {
00506         w += "\n" + i18n("Start: %1").arg(locale->formatDateTime(task->startTime()));
00507         w += "\n" + i18n("End: %1").arg(locale->formatDateTime(task->endTime()));
00508     }
00509     bool ok = true;
00510     if (task->notScheduled()) {
00511         w += "\n" + i18n("Not scheduled");
00512         ok = false;
00513     } else {
00514         if (!m_showNoInformation && m_project && m_project->notScheduled()) {
00515             ok = false;
00516         }
00517     }
00518     if (ok) {
00519         QColor c(cyan);
00520         item->setColors(c,c,c);
00521     } else {
00522         QColor c(yellow);
00523         item->setColors(c,c,c);
00524     }
00525     item->setTooltipText(w);
00526     setDrawn(item, true);
00527 }
00528 
00529 void GanttView::modifyTask(KDGanttViewItem *item, Task *task)
00530 {
00531     //kdDebug()<<k_funcinfo<<endl;
00532     KLocale *locale = KGlobal::locale();
00533     //kdDebug()<<k_funcinfo<<task->name()<<": "<<task->currentSchedule()<<", "<<task->notScheduled()<<", "<<(m_project ? m_project->notScheduled() : false)<<endl;
00534     item->setListViewText(task->name());
00535     item->setListViewText(1, task->wbs());
00536     if (task->currentSchedule() == 0) {
00537         item->setShowNoInformation(m_showNoInformation);
00538         item->setStartTime(task->projectNode()->startTime());
00539         item->setEndTime(item->startTime().addDays(1));
00540     } else {
00541         bool noinf = m_showNoInformation && (task->notScheduled() || (m_project ? m_project->notScheduled() : false /*hmmm, no project?*/));
00542         item->setShowNoInformation(noinf);
00543         item->setStartTime(task->startTime());
00544         item->setEndTime(task->endTime());
00545     }
00546     //item->setOpen(true);
00547     QString text;
00548     if (m_showTaskName) {
00549         text = task->name();
00550     }
00551     if (m_showResources && !task->notScheduled()) {
00552         QPtrList<Appointment> lst = task->appointments();
00553         if (lst.count() > 0) {
00554             if (!text.isEmpty())
00555                 text += ' ';
00556             text += '(';
00557             QPtrListIterator<Appointment> it = lst;
00558             for (bool first=true; it.current(); ++it) {
00559                 if (!first)
00560                     text += ", ";
00561                 text += it.current()->resource()->resource()->name();
00562                 first = false;
00563             }
00564             text += ')';
00565         }
00566     }
00567     item->setText(text);
00568     if (m_showProgress) {
00569         item->setProgress(task->progress().percentFinished);
00570     } else {
00571         item->setProgress(0);
00572     }
00573     if (m_showPositiveFloat) {
00574         QDateTime t = task->endTime() + task->positiveFloat();
00575         if (t.isValid() && t > task->endTime()) {
00576             item->setFloatEndTime(t);
00577         } else {
00578             item->setFloatEndTime(QDateTime());
00579         }
00580     } else {
00581         item->setFloatStartTime(QDateTime());
00582         item->setFloatEndTime(QDateTime());
00583     }
00584     QString w = i18n("Name: %1").arg(task->name());
00585     if (!task->notScheduled()) {
00586         w += "\n"; w += i18n("Start: %1").arg(locale->formatDateTime(task->startTime()));
00587         w += "\n"; w += i18n("End: %1").arg(locale->formatDateTime(task->endTime()));
00588         if (m_showProgress) {
00589             w += "\n"; w += i18n("Completion: %1%").arg(task->progress().percentFinished);
00590         }
00591         if (task->positiveFloat() > Duration::zeroDuration) {
00592             w += "\n" + i18n("Float: %1").arg(task->positiveFloat().toString(Duration::Format_i18nDayTime));
00593         }
00594         if (task->inCriticalPath()) {
00595             w += "\n" + i18n("Critical path");
00596         } else if (task->isCritical()) {
00597             w += "\n" + i18n("Critical");
00598         }
00599     }
00600     QString sts;
00601     bool ok = true;
00602     if (task->notScheduled()) {
00603         sts += "\n" + i18n("Not scheduled");
00604         ok = false;
00605     } else {
00606         if (task->resourceError()) {
00607             sts += "\n" + i18n("No resource assigned");
00608             ok = false;
00609         }
00610         if (task->resourceOverbooked()) {
00611             sts += "\n" + i18n("Resource overbooked");
00612             ok = false;
00613         }
00614         if (task->resourceNotAvailable()) {
00615             sts += "\n" + i18n("Resource not available");
00616             ok = false;
00617         }
00618         if (task->schedulingError()) {
00619             sts += "\n" + i18n("Scheduling conflict");
00620             ok = false;
00621         }
00622         if (!m_showNoInformation && m_project && m_project->notScheduled()) {
00623             ok = false;
00624         }
00625     }
00626     if (ok) {
00627         QColor c(green);
00628         item->setColors(c,c,c);
00629     } else {
00630         w += sts;
00631         QColor c(yellow);
00632         item->setColors(c,c,c);
00633     }
00634     item->setHighlight(false);
00635     if (m_showCriticalTasks) {
00636         item->setHighlight(task->isCritical());
00637     } else if (m_showCriticalPath) {
00638         item->setHighlight(task->inCriticalPath());
00639     }
00640     
00641     item->setTooltipText(w);
00642     setDrawn(item, true);
00643 }
00644 
00645 void GanttView::modifyMilestone(KDGanttViewItem *item, Task *task)
00646 {
00647     //kdDebug()<<k_funcinfo<<endl;
00648     KLocale *locale = KGlobal::locale();
00649     //kdDebug()<<k_funcinfo<<task->name()<<": "<<task->currentSchedule()<<", "<<task->notScheduled()<<", "<<(m_project ? m_project->notScheduled() : false)<<endl;
00650     if (task->currentSchedule() == 0) {
00651         item->setShowNoInformation(m_showNoInformation);
00652         item->setStartTime(task->projectNode()->startTime());
00653     } else {
00654         bool noinf = m_showNoInformation && (task->notScheduled() || (m_project ? m_project->notScheduled() : false /*hmmm, no project?*/));
00655         item->setShowNoInformation(noinf);
00656         item->setStartTime(task->startTime());
00657     }
00658     item->setListViewText(task->name());
00659     item->setListViewText(1, task->wbs());
00660     //item->setOpen(true);
00661     if (m_showTaskName) {
00662         item->setText(task->name());
00663     } else {
00664         item->setText(QString());
00665     }    
00666     if (m_showPositiveFloat) {
00667         DateTime t = task->startTime() + task->positiveFloat();
00668         //kdDebug()<<k_funcinfo<<task->name()<<" float: "<<t.toString()<<endl;
00669         if (t.isValid() && t > task->startTime()) {
00670             item->setFloatEndTime(t);
00671         } else {
00672             item->setFloatEndTime(QDateTime());
00673         }
00674     } else {
00675         item->setFloatStartTime(QDateTime());
00676         item->setFloatEndTime(QDateTime());
00677     }
00678     //TODO: Show progress
00679     
00680     QString w = i18n("Name: %1").arg(task->name());
00681     if (!task->notScheduled()) {
00682         w += "\n" + i18n("Time: %1").arg(locale->formatDateTime(task->startTime()));
00683         
00684         if (task->positiveFloat() > Duration::zeroDuration) {
00685             w += "\n" + i18n("Float: %1").arg(task->positiveFloat().toString(Duration::Format_i18nDayTime));
00686         }
00687         if (task->inCriticalPath()) {
00688             w += "\n" + i18n("Critical path");
00689         } else if (task->isCritical()) {
00690             w += "\n" + i18n("Critical");
00691         }
00692     }
00693     bool ok = true;
00694     if (task->notScheduled()) {
00695         w += "\n" + i18n("Not scheduled");
00696         ok = false;
00697     } else {
00698         if (task->schedulingError()) {
00699             w += "\n" + i18n("Scheduling conflict");
00700             ok = false;
00701         }
00702         if (!m_showNoInformation && m_project && m_project->notScheduled()) {
00703             ok = false;
00704         }
00705     }
00706     if (ok) {
00707         QColor c(blue);
00708         item->setColors(c,c,c);
00709     } else {
00710         QColor c(yellow);
00711         item->setColors(c,c,c);
00712     }
00713     item->setHighlight(false);
00714     if (m_showCriticalTasks) {
00715         item->setHighlight(task->isCritical());
00716     } else if (m_showCriticalPath) {
00717         item->setHighlight(task->inCriticalPath());
00718     }
00719     
00720     item->setTooltipText(w);
00721     setDrawn(item, true);
00722 }
00723 
00724 KDGanttViewItem *GanttView::addNode( KDGanttViewItem *parentItem, Node *node, KDGanttViewItem *after)
00725 {
00726     //kdDebug()<<k_funcinfo<<endl;
00727     if (node->type() == Node::Type_Project) {
00728         return addProject(parentItem, node, after);
00729     }
00730     if (node->type() == Node::Type_Subproject) {
00731         return addSubProject(parentItem, node, after);
00732     }
00733     if (node->type() == Node::Type_Summarytask) {
00734         return addSummaryTask(parentItem, static_cast<Task *>(node), after);
00735     }
00736     if (node->type() == Node::Type_Task) {
00737         return addTask(parentItem, static_cast<Task *>(node), after);
00738     }
00739     if (node->type() == Node::Type_Milestone) {
00740         return addMilestone(parentItem, static_cast<Task *>(node), after);
00741     }
00742     return 0;
00743 }
00744 
00745 KDGanttViewItem *GanttView::addProject(KDGanttViewItem *parentItem, Node *node, KDGanttViewItem *after)
00746 {
00747     //kdDebug()<<k_funcinfo<<endl;
00748     GanttViewSummaryItem *item;
00749     if ( parentItem) {
00750         item = new GanttViewSummaryItem(parentItem, node);
00751     } else {
00752         // we are on the top level
00753         item = new GanttViewSummaryItem(m_gantt, node);
00754     }
00755     if (after)
00756         item->moveItem(after);
00757     modifyProject(item, node);
00758     return item;
00759 }
00760 
00761 KDGanttViewItem *GanttView::addSubProject(KDGanttViewItem *parentItem, Node *node, KDGanttViewItem *after)
00762 {
00763     //kdDebug()<<k_funcinfo<<endl;    
00764     return addProject(parentItem, node, after);
00765 }
00766 
00767 KDGanttViewItem *GanttView::addSummaryTask(KDGanttViewItem *parentItem, Task *task, KDGanttViewItem *after)
00768 {
00769     //kdDebug()<<k_funcinfo<<endl;
00770     // display summary item
00771     GanttViewSummaryItem *item;
00772     if ( parentItem) {
00773         item = new GanttViewSummaryItem(parentItem, task);
00774     } else {
00775         // we are on the top level
00776         item = new GanttViewSummaryItem(m_gantt, task);
00777     }
00778     if (after)
00779         item->moveItem(after);
00780     modifySummaryTask(item, task);
00781     return item;
00782 }
00783 
00784 KDGanttViewItem *GanttView::addTask(KDGanttViewItem *parentItem, Task *task, KDGanttViewItem *after)
00785 {
00786     //kdDebug()<<k_funcinfo<<endl;
00787     // display task item
00788     GanttViewTaskItem *item;
00789     if ( parentItem ) {
00790         item = new GanttViewTaskItem(parentItem, task);
00791     }
00792     else {
00793         // we are on the top level
00794         item = new GanttViewTaskItem(m_gantt, task);
00795     }
00796     if (after)
00797         item->moveItem(after);
00798     modifyTask(item, task);
00799     return item;
00800 }
00801 
00802 KDGanttViewItem *GanttView::addMilestone(KDGanttViewItem *parentItem, Task *task, KDGanttViewItem *after)
00803 {
00804     //kdDebug()<<k_funcinfo<<endl;
00805     GanttViewEventItem *item;
00806     if ( parentItem ) {
00807         item = new GanttViewEventItem(parentItem, task);
00808     } else {
00809         // we are on the top level
00810         item = new GanttViewEventItem(m_gantt, task);
00811     }
00812     if (after)
00813         item->moveItem(after);
00814     modifyMilestone(item, task);
00815     return item;
00816 }
00817 
00818 void GanttView::drawChildren(KDGanttViewItem *parentItem, Node &parentNode)
00819 {
00820     //kdDebug()<<k_funcinfo<<endl;
00821     QPtrListIterator<Node> nit(parentNode.childNodeIterator());
00822     for ( nit.toLast(); nit.current(); --nit )
00823     {
00824         Node *n = nit.current();
00825         if (n->type() == Node::Type_Project)
00826             drawProject(parentItem, n);
00827         else if (n->type() == Node::Type_Subproject)
00828             drawSubProject(parentItem, n);
00829         else if (n->type() == Node::Type_Summarytask) {
00830             Task *t = dynamic_cast<Task *>(n);
00831             drawSummaryTask(parentItem, t);
00832         } else if (n->type() == Node::Type_Task) {
00833             Task *t = dynamic_cast<Task *>(n);
00834             drawTask(parentItem, t);
00835         } else if (n->type() == Node::Type_Milestone) {
00836             Task *t = dynamic_cast<Task *>(n);
00837             drawMilestone(parentItem, t);
00838         }
00839         else
00840             kdDebug()<<k_funcinfo<<"Node type "<<n->type()<<" not implemented yet"<<endl;
00841 
00842     }
00843 }
00844 
00845 
00846 void GanttView::drawProject(KDGanttViewItem *parentItem, Node *node)
00847 {
00848     //kdDebug()<<k_funcinfo<<endl;
00849     GanttViewSummaryItem *item = dynamic_cast<GanttViewSummaryItem*>(addProject(parentItem, node));
00850     drawChildren(item, *node);
00851 }
00852 
00853 void GanttView::drawSubProject(KDGanttViewItem *parentItem, Node *node)
00854 {
00855     //kdDebug()<<k_funcinfo<<endl;
00856     GanttViewSummaryItem *item = dynamic_cast<GanttViewSummaryItem*>(addSubProject(parentItem, node));
00857     drawChildren(item, *node);
00858 }
00859 
00860 void GanttView::drawSummaryTask(KDGanttViewItem *parentItem, Task *task)
00861 {
00862     //kdDebug()<<k_funcinfo<<endl;
00863     GanttViewSummaryItem *item = dynamic_cast<GanttViewSummaryItem*>(addSummaryTask(parentItem, task));
00864     drawChildren(item, *task);
00865 }
00866 
00867 void GanttView::drawTask(KDGanttViewItem *parentItem, Task *task)
00868 {
00869     //kdDebug()<<k_funcinfo<<endl;
00870     addTask(parentItem, task);
00871 }
00872 
00873 void GanttView::drawMilestone(KDGanttViewItem *parentItem, Task *task)
00874 {
00875     //kdDebug()<<k_funcinfo<<endl;
00876     addMilestone(parentItem, task);
00877 }
00878 
00879 void GanttView::addTaskLink(KDGanttViewTaskLink *link) {
00880     //kdDebug()<<k_funcinfo<<endl;
00881     m_taskLinks.append(link);
00882 }
00883 
00884 void GanttView::drawRelations()
00885 {
00886     if (!m_showTaskLinks)
00887         return;
00888     KDGanttViewItem *item = m_gantt->firstChild();
00889     //kdDebug()<<k_funcinfo<<"First: "<<(item ? item->listViewText() : "nil")<<endl;
00890     for (; item; item = item->nextSibling())
00891     {
00892         drawRelations(item);
00893         drawChildRelations(item->firstChild());
00894     }
00895 }
00896 
00897 void GanttView::drawChildRelations(KDGanttViewItem *item)
00898 {
00899     //kdDebug()<<k_funcinfo<<"item: "<<(item ? item->listViewText() : "nil")<<endl;
00900     for (; item; item = item->nextSibling())
00901     {
00902         drawRelations(item);
00903         drawChildRelations(item->firstChild());
00904     }
00905 }
00906 
00907 void GanttView::drawRelations(KDGanttViewItem *item)
00908 {
00909     //kdDebug()<<k_funcinfo<<endl;
00910     if (!item) return;
00911 
00912     GanttViewSummaryItem *summaryItem = dynamic_cast<GanttViewSummaryItem *>(item);
00913     if (summaryItem)
00914     {
00915         //kdDebug()<<k_funcinfo<<"Summary item: "<<summaryItem->listViewText()<<endl;
00916         summaryItem->insertRelations(this);
00917         return;
00918     }
00919     GanttViewTaskItem *taskItem = dynamic_cast<GanttViewTaskItem *>(item);
00920     if (taskItem)
00921     {
00922         //kdDebug()<<k_funcinfo<<"Task item: "<<taskItem->listViewText()<<endl;
00923         taskItem->insertRelations(this);
00924         return;
00925     }
00926     GanttViewEventItem *milestoneItem = dynamic_cast<GanttViewEventItem *>(item);
00927     if (milestoneItem)
00928     {
00929         //kdDebug()<<k_funcinfo<<"Milestone item: "<<milestoneItem->listViewText()<<endl;
00930         milestoneItem->insertRelations(this);
00931         return;
00932     }
00933     kdDebug()<<k_funcinfo<<"Unknown item type: "<<item->listViewText()<<endl;
00934 }
00935 
00936 void GanttView::currentItemChanged(KDGanttViewItem* item)
00937 {
00938     //kdDebug()<<k_funcinfo<<(item ? item->listViewText() : "null")<<endl;
00939     m_taskView->clear();
00940     m_gantt->setSelected(m_currentItem, false);
00941     m_currentItem = item;
00942     if (item) {
00943         m_gantt->setSelected(item, true);
00944         if (m_showAppointments) {
00945             m_taskView->show();
00946             GanttViewTaskItem *taskItem = dynamic_cast<GanttViewTaskItem *>(item);
00947             if (taskItem) {
00948                 m_taskView->draw(taskItem->getTask());
00949             } else {
00950                 GanttViewEventItem *msItem = dynamic_cast<GanttViewEventItem *>(item);
00951                 if (msItem)
00952                     m_taskView->draw(msItem->getTask());
00953             }
00954         } else {
00955             m_taskView->hide();
00956         }
00957     }
00958     emit enableActions(true);
00959 }
00960 
00961 Node *GanttView::currentNode() const
00962 {
00963     return getNode(m_currentItem);
00964 }
00965 
00966 void GanttView::popupMenuRequested(KDGanttViewItem * item, const QPoint & pos, int)
00967 {
00968     //kdDebug()<<k_funcinfo<<(item?item->listViewText(0):"0")<<endl;
00969     if (item == 0) {
00970         kdDebug()<<"No item selected"<<endl;
00971         return;
00972     }
00973     Node *n = getNode(item);
00974     if (n == 0) {
00975         kdDebug()<<"No node selected"<<endl;
00976         return;
00977     }
00978     Task *t =  dynamic_cast<Task*>(n);
00979     if (t && (t->type() == Node::Type_Task || t->type() == Node::Type_Milestone)) {
00980         emit requestPopupMenu("task_popup",pos);
00981 //         QPopupMenu *menu = m_mainview->popupMenu("task_popup");
00982 //         if (menu)
00983 //         {
00984 //             /*int id =*/ menu->exec(pos);
00985             //kdDebug()<<k_funcinfo<<"id="<<id<<endl;
00986 //         }
00987         return;
00988     } 
00989     if (t && t->type() == Node::Type_Summarytask) {
00990         emit requestPopupMenu("summarytask_popup",pos);
00991 //         QPopupMenu *menu = m_mainview->popupMenu("summarytask_popup");
00992 //         if (menu)
00993 //         {
00994 //             /*int id =*/ menu->exec(pos);
00995             //kdDebug()<<k_funcinfo<<"id="<<id<<endl;
00996 //         }
00997         return;
00998     }
00999     //TODO: Other nodetypes
01000 }
01001 
01002 void GanttView::slotItemDoubleClicked(QListViewItem* item) {
01003     //kdDebug()<<k_funcinfo<<endl;
01004     if (item == 0 || item->childCount() > 0) {
01005         // FIXME: How else to avoid interference wirh expanding/collapsing summary items?
01006         return;
01007     }
01008     emit itemDoubleClicked();
01009 }
01010 
01011 //TODO: 1) make it koffice compliant, 
01012 //      2) allow printing on multiple pages
01013 void GanttView::print(KPrinter &prt) {
01014     //kdDebug()<<k_funcinfo<<endl;
01015 
01016     KDGanttViewItem *selItem = m_gantt->selectedItem();
01017     if (selItem)
01018         selItem->setSelected(false);
01019     
01020     //Comment from KWord
01021     //   We don't get valid metrics from the printer - and we want a better resolution
01022     //   anyway (it's the PS driver that takes care of the printer resolution).
01023     //But KSpread uses fixed 300 dpis, so we can use it.
01024 
01025     QPaintDeviceMetrics metrics( &prt );
01026     uint top, left, bottom, right;
01027     prt.margins(&top, &left, &bottom, &right);
01028     //kdDebug()<<m.width()<<"x"<<m.height()<<" : "<<top<<", "<<left<<", "<<bottom<<", "<<right<<" : "<<size()<<endl;
01029 
01030     // get the size of the desired output for scaling.
01031     // here we want to print: ListView and TimeLine (default)
01032     // for this purpose, we call drawContents() with a 0 pointer as painter
01033     QSize size = m_gantt->drawContents(0);
01034     
01035     QPainter p;
01036     p.begin( &prt );
01037     p.setViewport(left, top, metrics.width()-left-right, metrics.height()-top-bottom);
01038     p.setClipRect(left, top, metrics.width()-left-right, metrics.height()-top-bottom);
01039     
01040     // Make a simple header
01041     p.drawRect(0,0,metrics.width(),metrics.height());
01042     QString text;
01043     int hei = 0;
01044     text = KGlobal::locale()->formatDateTime(QDateTime::currentDateTime());
01045     QRect r = p.boundingRect(metrics.width()-1,0,0,0, Qt::AlignRight, text );
01046     p.drawText( r, Qt::AlignRight, text );
01047     hei = r.height();
01048     //kdDebug()<<"Date r="<<r.left()<<","<<r.top()<<" "<<r.width()<<"x"<<r.height()<<endl;
01049     if (m_project)
01050     {
01051       QRect re = p.boundingRect(1,0,0,0, Qt::AlignLeft, text );
01052       re.setWidth(metrics.width()-r.width()-5); // don't print on top of date
01053       p.drawText( re, Qt::AlignLeft, m_project->name() );
01054       hei = r.height();
01055       //kdDebug()<<"Project r="<<re.left()<<","<<re.top()<<" "<<re.width()<<"x"<<re.height()<<": "<<endl;
01056       hei = QMAX(hei, re.height());
01057     }
01058     
01059     hei++;
01060     p.drawLine(0,hei,metrics.width(),hei);
01061     hei += 3;
01062     // compute the scale
01063     float dx = (float) (metrics.width()-2)  / (float)size.width();
01064     float dy  = (float)(metrics.height()-hei) / (float)size.height();
01065     float scale;
01066     // scale to fit the width or height of the paper
01067     if ( dx < dy )
01068         scale = dx;
01069     else
01070         scale = dy;
01071     // set the scale
01072     p.translate(1,hei);
01073     p.scale( scale, scale );
01074     m_gantt->drawContents(&p);
01075     // the drawContents() has the side effect, that the painter translation is
01076     // after drawContents() set to the bottom of the painted stuff
01077     // for instance a
01078     // p.drawText(0, 0, "printend");
01079     // would be painted directly below the paintout of drawContents()
01080     
01081     p.end();
01082     if (selItem)
01083         selItem->setSelected(true);
01084 }
01085 
01086 void GanttView::slotItemRenamed(KDGanttViewItem* item, int col, const QString& str) {
01087     //kdDebug()<<k_funcinfo<<(item ? item->listViewText(col) : "null")<<": "<<str<<endl;
01088     if (col == 0) {
01089         emit itemRenamed(getNode(item), str);
01090     }
01091 }
01092 
01093  void GanttView::slotGvItemClicked(KDGanttViewItem *) {
01094 }
01095 
01096 // testing
01097 bool GanttView::exportGantt(QIODevice* device) {
01098     kdDebug()<<k_funcinfo<<endl;
01099     return m_gantt->saveProject(device);
01100 }
01101 
01102 void GanttView::slotLinkItems(KDGanttViewItem* from, KDGanttViewItem* to, int linkType) {
01103     //kdDebug()<<k_funcinfo<<(from?from->listViewText():"null")<<" to "<<(to?to->listViewText():"null")<<" linkType="<<linkType<<endl;
01104     Node *par = getNode(from);
01105     Node *child = getNode(to);
01106     if (!par || !child || !(par->legalToLink(child))) {
01107         KMessageBox::sorry(this, i18n("Cannot link these nodes"));
01108         return;
01109     }
01110     Relation *rel = child->findRelation(par);
01111     if (rel)
01112         emit modifyRelation(rel, linkTypeToRelation(linkType));
01113     else
01114         emit addRelation(par, child, linkTypeToRelation(linkType));
01115     
01116     return;
01117 }
01118 
01119 int GanttView::linkTypeToRelation(int linkType) {
01120     switch (linkType) {
01121         case KDGanttViewTaskLink::FinishStart: 
01122             return Relation::FinishStart;
01123             break;
01124         case KDGanttViewTaskLink::StartStart: 
01125             return Relation::StartStart;
01126             break;
01127         case KDGanttViewTaskLink::FinishFinish: 
01128             return Relation::FinishFinish;
01129             break;
01130         case KDGanttViewTaskLink::StartFinish:
01131         default: 
01132             return -1;
01133             break;
01134     }
01135 }
01136 
01137 void GanttView::slotModifyLink(KDGanttViewTaskLink* link) {
01138     //kdDebug()<<k_funcinfo<<link<<endl;
01139     // we support only one from/to item in each link
01140     Node *par = getNode(link->from().first());
01141     Relation *rel = par->findRelation(getNode(link->to().first()));
01142     if (rel)
01143         emit modifyRelation(rel);
01144 }
01145 
01146 bool GanttView::setContext(Context::Ganttview &context, Project& /*project*/) {
01147     //kdDebug()<<k_funcinfo<<endl;
01148     
01149     QValueList<int> list = sizes();
01150     list[0] = context.ganttviewsize;
01151     list[1] = context.taskviewsize;
01152     setSizes(list);
01153 
01154     //TODO this does not work yet!
01155 //     currentItemChanged(findItem(project.findNode(context.currentNode)));
01156     
01157     m_showResources = context.showResources ;
01158     m_showTaskName = context.showTaskName;
01159     m_showTaskLinks = context.showTaskLinks;
01160     m_showProgress = context.showProgress;
01161     m_showPositiveFloat = context.showPositiveFloat;
01162     m_showCriticalTasks = context.showCriticalTasks;
01163     m_showCriticalPath = context.showCriticalPath;
01164     m_showNoInformation = context.showNoInformation;
01165     
01166     //TODO this does not work yet!
01167 //     getContextClosedNodes(context, m_gantt->firstChild());
01168 //     for (QStringList::ConstIterator it = context.closedNodes.begin(); it != context.closedNodes.end(); ++it) {
01169 //         KDGanttViewItem *item = findItem(project.findNode(*it));
01170 //         if (item) {
01171 //             item->setOpen(false);
01172 //         }
01173 //     }
01174     return true;
01175 }
01176 
01177 void GanttView::getContext(Context::Ganttview &context) const {
01178     //kdDebug()<<k_funcinfo<<endl;
01179     context.ganttviewsize = sizes()[0];
01180     context.taskviewsize = sizes()[1];
01181     //kdDebug()<<k_funcinfo<<"sizes="<<sizes()[0]<<","<<sizes()[1]<<endl;
01182     if (currentNode()) {
01183         context.currentNode = currentNode()->id();
01184     }
01185     context.showResources = m_showResources;
01186     context.showTaskName = m_showTaskName;
01187     context.showTaskLinks = m_showTaskLinks;
01188     context.showProgress = m_showProgress;
01189     context.showPositiveFloat = m_showPositiveFloat;
01190     context.showCriticalTasks = m_showCriticalTasks;
01191     context.showCriticalPath = m_showCriticalPath;
01192     context.showNoInformation = m_showNoInformation;
01193     getContextClosedNodes(context, m_gantt->firstChild());
01194 }
01195 
01196 void GanttView::getContextClosedNodes(Context::Ganttview &context, KDGanttViewItem *item) const {
01197     if (item == 0)
01198         return;
01199     for (KDGanttViewItem *i = item; i; i = i->nextSibling()) {
01200         if (!i->isOpen()) {
01201             context.closedNodes.append(getNode(i)->id());
01202             //kdDebug()<<k_funcinfo<<"add closed "<<i->listViewText()<<endl;
01203         }
01204         getContextClosedNodes(context, i->firstChild());
01205     }
01206 }
01207 
01208 void GanttView::setReadWriteMode(bool on) {
01209     m_readWrite = on;
01210     disconnect(m_gantt, SIGNAL(linkItems(KDGanttViewItem*, KDGanttViewItem*, int)), this, SLOT(slotLinkItems(KDGanttViewItem*, KDGanttViewItem*, int)));
01211     disconnect(m_gantt, SIGNAL(taskLinkDoubleClicked(KDGanttViewTaskLink*)), this, SLOT(slotModifyLink(KDGanttViewTaskLink*)));
01212     m_gantt->setLinkItemsEnabled(on);
01213 
01214     if (on) {
01215         connect(m_gantt, SIGNAL(linkItems(KDGanttViewItem*, KDGanttViewItem*, int)), SLOT(slotLinkItems(KDGanttViewItem*, KDGanttViewItem*, int)));
01216         
01217         connect(m_gantt, SIGNAL(taskLinkDoubleClicked(KDGanttViewTaskLink*)), SLOT(slotModifyLink(KDGanttViewTaskLink*)));
01218     }
01219     setRenameEnabled(m_gantt->firstChild(), on);
01220 }
01221 
01222 void GanttView::setRenameEnabled(QListViewItem *item, bool on) {
01223     if (item == 0)
01224         return;
01225     for (QListViewItem *i = item; i; i = i->nextSibling()) {
01226         i->setRenameEnabled(0, on);
01227         setRenameEnabled(i->firstChild(), on);
01228     }
01229 }
01230 
01231 }  //KPlato namespace
01232 
01233 #include "kptganttview.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys