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