kplato

kptpertcanvas.cc

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003 - 2004 Dag Andersen <danders@get2net.dk>
00003 
00004    This library is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation;
00007    version 2 of the License.
00008 
00009    This library is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this library; see the file COPYING.LIB.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "kptpertcanvas.h"
00021 #include "kptnode.h"
00022 #include "kptrelation.h"
00023 #include "kptrelationdialog.h"
00024 #include "kptcanvasitem.h"
00025 
00026 #include <qbuffer.h>
00027 #include <qtimer.h>
00028 #include <qclipboard.h>
00029 #include <qprogressdialog.h>
00030 #include <qobjectlist.h>
00031 #include <qpainter.h>
00032 #include <qheader.h>
00033 #include <qcursor.h>
00034 #include <qrect.h>
00035 #include <qsize.h>
00036 #include <qptrlist.h>
00037 
00038 #include <KoStore.h>
00039 #include <ktempfile.h>
00040 #include <klocale.h>
00041 #include <kdebug.h>
00042 #include <kapplication.h>
00043 #include <kmessagebox.h>
00044 #include <assert.h>
00045 #include <kmultipledrag.h>
00046 #include <klistview.h>
00047 
00048 namespace KPlato
00049 {
00050 
00051 PertCanvas::PertCanvas( QWidget *parent )
00052     : QCanvasView( parent, "Pert canvas" /*WNorthWestGravity WStaticContents| WResizeNoErase | WRepaintNoErase */),
00053     m_verticalGap(20),
00054     m_horizontalGap(10),
00055     m_itemSize(100,30)
00056 
00057 {
00058     //setHScrollBarMode(QScrollView::AlwaysOn);
00059     m_canvas = new QCanvas( this );
00060     setCanvas( m_canvas );
00061 }
00062 
00063 PertCanvas::~PertCanvas()
00064 {
00065 }
00066 
00067 void PertCanvas::draw(Project& project)
00068 {
00069     //kdDebug()<<k_funcinfo<<endl;
00070     clear();
00071     updateContents();
00072 
00073     // First make node items
00074     QPtrListIterator<Node> nit(project.childNodeIterator());
00075     for ( ; nit.current(); ++nit ) {
00076         createChildItems(createNodeItem(nit.current()));
00077     }
00078 
00079     // First all items with relations
00080     QPtrDictIterator<PertNodeItem> it(m_nodes);
00081     for(; it.current(); ++it)
00082     {
00083         if (!(it.current()->hasParent()) && it.current()->hasChild())
00084         {
00085             m_rows.append(new QMemArray<bool>(1)); // New node always goes into new row, first column
00086             it.current()->move(this, m_rows.count()-1, 0); // item also moves it's children
00087         }
00088     }
00089     // now items without relations
00090     for(it.toFirst(); it.current(); ++it)
00091     {
00092         if (!(it.current()->hasParent() || it.current()->hasChild()))
00093         {
00094             m_rows.append(new QMemArray<bool>(1)); // New node always goes into new row, first column
00095             it.current()->move(this, m_rows.count()-1, 0);
00096         }
00097     }
00098     drawRelations(); // done _after_ all nodes are drawn
00099     QSize s = canvasSize();
00100     m_canvas->resize(s.width(), s.height());
00101     update();
00102 }
00103 
00104 PertNodeItem *PertCanvas::createNodeItem(Node *node)
00105 {
00106     PertNodeItem *item = m_nodes.find(node);
00107     if (!item)
00108     {
00109         if ( node->type() == Node::Type_Project)
00110             kdDebug()<<k_funcinfo<<"Project nodes should not have relations"<<endl;
00111         else if (node->type() == Node::Type_Subproject)
00112             item  = new PertProjectItem(this, *node);
00113         else if (node->type()== Node::Type_Summarytask)
00114             item  = new PertTaskItem(this, *node);
00115         else if (node->type()== Node::Type_Task)
00116             item  = new PertTaskItem(this, *node);
00117         else if (node->type() == Node::Type_Milestone)
00118             item  = new PertMilestoneItem(this, *node);
00119         else
00120             kdDebug()<<k_funcinfo<<"Not implemented yet"<<endl;
00121 
00122         if (item)
00123             m_nodes.insert(node, item);
00124     }
00125     return item;
00126 }
00127 
00128 void PertCanvas::createChildItems(PertNodeItem *parentItem)
00129 {
00130     //kdDebug()<<k_funcinfo<<"parentItem="<<(parentItem ? parentItem->node().name() : "nil")<<endl;
00131     if (!parentItem)
00132         return;
00133 
00134     QPtrListIterator<Relation> it(parentItem->node().dependChildNodes());
00135     for (; it.current(); ++it)
00136     {
00137         PertNodeItem *childItem = createNodeItem(it.current()->child());
00138         if (childItem)
00139             parentItem->addChildRelation(it.current(), childItem);
00140             m_relations.append(it.current());
00141     }
00142 
00143     // Now my children
00144     QPtrListIterator<Node> nit(parentItem->node().childNodeIterator());
00145     for ( ; nit.current(); ++nit ) {
00146         createChildItems(createNodeItem(nit.current()));
00147     }
00148 }
00149 
00150 void PertCanvas::drawRelations()
00151 {
00152     //kdDebug()<<k_funcinfo<<endl;
00153     QPtrListIterator<Relation> it(m_relations);
00154     for (; it.current(); ++it)
00155     {
00156         PertNodeItem *parentItem = m_nodes.find(it.current()->parent());
00157         PertNodeItem *childItem = m_nodes.find(it.current()->child());
00158         if (parentItem && childItem)
00159         {
00160             PertRelationItem *item = new PertRelationItem(this, parentItem, childItem, it.current());
00161             item->show();
00162         }
00163     }
00164 }
00165 
00166 void PertCanvas::mapNode(PertNodeItem *item)
00167 {
00168     //kdDebug()<<k_funcinfo<<endl;
00169     if (! m_rows.at(item->row()) || (item->column() >= 0 && m_rows.at(item->row())->count() <= uint(item->column())))
00170     {
00171         kdError()<<k_funcinfo<<item->node().name()<<": non existing map for: ("<<item->row()<<","<<item->column()<<")"<<endl;
00172         return;
00173     }
00174     m_rows.at(item->row())->at(item->column()) = true;
00175 }
00176 
00177 void PertCanvas::mapChildNode(PertNodeItem *parentItem, PertNodeItem *childItem, Relation::Type type)
00178 {
00179     //kdDebug()<<k_funcinfo<<"Parent: "<<parentItem->node().name()<<" to child: "<<(childItem ? childItem->node().name() : "None")<<endl;
00180     if (!childItem)
00181     {   // shouldn't happen...
00182         kdError()<<k_funcinfo<<"No childItem"<<endl;
00183         return;
00184     }
00185     int row = parentItem->row();
00186     int col = parentItem->column();
00187     int chRow = childItem->row();
00188     int chCol = childItem->column();
00189     bool chMapped = (chRow > -1 && chCol > -1);
00190     //kdDebug()<<k_funcinfo<<"Parent: "<<parentItem->node().name()<<" at ("<<row<<","<<col<<"): Moving "<<childItem->node().name()<<" from: "<<chRow<<","<<chCol<<endl;
00191 
00192     if (type == Relation::StartStart ||
00193         type == Relation::FinishFinish)
00194     {
00195         // node goes into row below parent, at least same col
00196         if (chMapped)
00197         {
00198             m_rows.at(chRow)->at(chCol) = false;
00199             //kdDebug()<<k_funcinfo<<" Moving "<<childItem->node().name()<<" from: "<<chRow<<","<<chCol<<endl;
00200             if (chRow <= row)
00201             {
00202                 chRow = row+1;
00203                 if (chRow >= 0 && m_rows.count() <= uint(chRow)) {
00204                     m_rows.append(new QMemArray<bool>(1)); // make a new row
00205                     chRow = m_rows.count()-1;  // to be safe
00206                 }
00207                 //kdDebug()<<k_funcinfo<<" Moving "<<childItem->node().name()<<" to row: "<<chRow<<endl;
00208             }
00209             if (chCol < col)
00210             {
00211                 chCol = col;
00212                 if (chCol >= 0 && m_rows.at(chRow)->count() <= uint(chCol))  // col does not exist
00213                     m_rows.at(chRow)->resize(chCol+1);
00214                 
00215                 //kdDebug()<<k_funcinfo<<" Moved "<<childItem->node().name()<<" to col: "<<chCol<<endl;
00216             }
00217 
00218         }
00219         else
00220         {
00221             if (!(m_rows.at(row+1)) ||                        // next row does not exists
00222                 m_rows.at(row+1)->at(col) == true)  // col is not free
00223             {
00224                 m_rows.append(new QMemArray<bool>(col+1)); // make a new row
00225             }
00226             else if (col >= 0 && m_rows.at(row+1)->count() <= uint(col))  // col does not exist
00227                 m_rows.at(row)->resize(col+1);
00228 
00229             chRow = m_rows.count() -1;
00230             chCol = col;
00231         }
00232     }
00233     else if (type == Relation::FinishStart)
00234     {
00235         // node goes into same row, next col if col free
00236         if (chMapped)
00237         {
00238             m_rows.at(chRow)->at(chCol) = false;
00239             if (chRow < row)
00240                 chRow = row;
00241             if (chCol <= col)
00242             {
00243                 chCol = col+1;
00244             }
00245             if (chCol >= 0 && m_rows.at(chRow)->count() <= uint(chCol))  // col does not exist
00246                 m_rows.at(chRow)->resize(chCol+1);
00247         }
00248         else
00249         {
00250             ++col;
00251             if (col >= 0 && m_rows.at(row)->count() <= uint(col))
00252                 m_rows.at(row)->resize(col+1); // make new column
00253             else if (m_rows.at(row)->at(col) = true)
00254                 m_rows.append(new QMemArray<bool>(col+1)); // col not free, so make a new row
00255 
00256             chRow = m_rows.count() -1;
00257             chCol = col;
00258         }
00259     }
00260     else
00261     {
00262         kdError()<<k_funcinfo<<"Unknow relation type"<<endl;
00263         return;
00264     }
00265     childItem->move(this, chRow, chCol);
00266 }
00267 
00268 QSize PertCanvas::canvasSize()
00269 {
00270     //kdDebug()<<k_funcinfo<<endl;
00271     QSize s(0,0);
00272     QCanvasItemList list = canvas()->allItems();
00273     QCanvasItemList::Iterator it = list.begin();
00274     for (; it != list.end(); ++it)
00275     {
00276         QRect r = (*it)->boundingRect();
00277         s.setWidth(QMAX(s.width(), r.right()));
00278         s.setHeight(QMAX(s.height(), r.bottom()));
00279     }
00280     s.setWidth(s.width()+20);
00281     s.setHeight(s.height()+20);
00282     return s;
00283 }
00284 
00285 void PertCanvas::clear()
00286 {
00287     m_nodes.clear();
00288     m_relations.clear();
00289     m_rows.clear();
00290     QCanvasItemList list = canvas()->allItems();
00291     QCanvasItemList::Iterator it = list.begin();
00292     for (; it != list.end(); ++it)
00293     {
00294         if ( *it )
00295             delete *it;
00296     }
00297 }
00298 
00299 void PertCanvas::contentsMousePressEvent ( QMouseEvent * e )
00300 {
00301     //kdDebug()<<k_funcinfo<<" gl.X,gl.Y="<<e->globalX()<<","<<e->globalY()<<" x,y="<<e->x()<<","<<e->y()<<endl;
00302     switch (e->button())
00303     {
00304         case QEvent::LeftButton:
00305         {
00306             break;
00307         }
00308         case QEvent::RightButton:
00309         {
00310             PertNodeItem *item = selectedItem();
00311             if (item)
00312                 item->setSelected(false);
00313             canvas()->update();
00314             
00315             QCanvasItemList l = canvas()->collisions(e->pos());
00316             for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it)
00317             {
00318                 if ( (*it)->rtti() == PertProjectItem::RTTI ||
00319                      (*it)->rtti() == PertTaskItem::RTTI  ||
00320                      (*it)->rtti() == PertMilestoneItem::RTTI )
00321                 {
00322                     PertNodeItem *item = (PertNodeItem *)(*it);
00323                     {
00324                         item->setSelected(true);
00325                         canvas()->update();
00326                         emit rightButtonPressed(&(item->node()), e->globalPos());
00327                         if (item == selectedItem()) {
00328                             // item maybe deleted
00329                             item->setSelected(false);
00330                         }
00331                         canvas()->update();
00332                         break;
00333                     }
00334                 }
00335             }
00336             break;
00337         }
00338         case QEvent::MidButton:
00339             break;
00340         default:
00341             break;
00342     }
00343 }
00344 
00345 void PertCanvas::contentsMouseReleaseEvent ( QMouseEvent * e )
00346 {
00347     //kdDebug()<<k_funcinfo<<" gl.X,gl.Y="<<e->globalX()<<","<<e->globalY()<<" x,y="<<e->x()<<","<<e->y()<<endl;
00348     switch (e->button())
00349     {
00350         case QEvent::LeftButton:
00351         {
00352             bool hit = false;
00353             QCanvasItemList l = canvas()->collisions(e->pos());
00354             for (QCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it)
00355             {
00356                 if ( (*it)->rtti() == PertProjectItem::RTTI ||
00357                      (*it)->rtti() == PertTaskItem::RTTI  ||
00358                      (*it)->rtti() == PertMilestoneItem::RTTI )
00359                 {
00360                     hit = true;
00361                     PertNodeItem *item = (PertNodeItem *)(*it);
00362                     PertNodeItem *par = selectedItem();
00363                     if ( !par)
00364                     {
00365                         //kdDebug()<<k_funcinfo<<" First node="<<item->node().name()<<endl;
00366                         item->setSelected(true);
00367                         canvas()->update();
00368                         return;
00369                     }
00370                     par->setSelected(false);
00371                     if (&(item->node()) == &(par->node()))
00372                     {
00373                         break;
00374                     }
00375                     //kdDebug()<<k_funcinfo<<" Second node="<<item->node().name()<<endl;
00376                     // open relation dialog
00377                     if (!par->node().legalToLink(&(item->node()))) {
00378                         KMessageBox::sorry(this, i18n("Cannot link these nodes"));
00379                     } else {
00380                         Relation *rel = item->node().findRelation(&(par->node()));
00381                         if (rel)
00382                             emit modifyRelation(rel);
00383                         else
00384                             emit addRelation(&(par->node()), &(item->node()));
00385                     }
00386                     break;
00387                 }
00388             }
00389             if (!hit) {
00390                 PertNodeItem *i = selectedItem();
00391                 if (i) i->setSelected(false);
00392             }
00393             canvas()->update();
00394             break;
00395         }
00396         case QEvent::RightButton:
00397         {
00398             break;
00399         }
00400         case QEvent::MidButton:
00401             break;
00402         default:
00403             break;
00404     }
00405 }
00406 
00407 PertNodeItem *PertCanvas::selectedItem()
00408 {
00409     QCanvasItemList list = canvas()->allItems();
00410     QCanvasItemList::Iterator it = list.begin();
00411     for (; it != list.end(); ++it)
00412     {
00413         if ( (*it)->isSelected() )
00414         {
00415         if ( (*it)->rtti() == PertProjectItem::RTTI ||
00416             (*it)->rtti() == PertTaskItem::RTTI  ||
00417             (*it)->rtti() == PertMilestoneItem::RTTI )
00418                 return (PertNodeItem *)(*it);
00419         }
00420     }
00421     return 0;
00422 }
00423 
00424 Node *PertCanvas::selectedNode() { 
00425     return selectedItem() ? &(selectedItem()->node()) : 0; 
00426 }
00427  
00428 #ifndef NDEBUG
00429 void PertCanvas::printDebug( int /*info*/ )
00430 {
00431 }
00432 #endif
00433 
00434 }  //KPlato namespace
00435 
00436 #include "kptpertcanvas.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys