kplato

kptpertcanvas.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2003 - 2004 Dag Andersen <danders@get2net.dk>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation;
7 version 2 of the License.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this library; see the file COPYING.LIB. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "kptpertcanvas.h"
21#include "kptnode.h"
22#include "kptrelation.h"
23#include "kptrelationdialog.h"
24#include "kptcanvasitem.h"
25
26#include <tqbuffer.h>
27#include <tqtimer.h>
28#include <tqclipboard.h>
29#include <tqprogressdialog.h>
30#include <tqobjectlist.h>
31#include <tqpainter.h>
32#include <tqheader.h>
33#include <tqcursor.h>
34#include <tqrect.h>
35#include <tqsize.h>
36#include <tqptrlist.h>
37
38#include <KoStore.h>
39#include <tdetempfile.h>
40#include <tdelocale.h>
41#include <kdebug.h>
42#include <tdeapplication.h>
43#include <tdemessagebox.h>
44#include <assert.h>
45#include <tdemultipledrag.h>
46#include <tdelistview.h>
47
48namespace KPlato
49{
50
51PertCanvas::PertCanvas( TQWidget *parent )
52 : TQCanvasView( parent, "Pert canvas" /*WNorthWestGravity WStaticContents| WResizeNoErase | WRepaintNoErase */),
53 m_verticalGap(20),
54 m_horizontalGap(10),
55 m_itemSize(100,30)
56
57{
58 //setHScrollBarMode(TQScrollView::AlwaysOn);
59 m_canvas = new TQCanvas( this );
60 setCanvas( m_canvas );
61}
62
63PertCanvas::~PertCanvas()
64{
65}
66
67void PertCanvas::draw(Project& project)
68{
69 //kdDebug()<<k_funcinfo<<endl;
70 clear();
71 updateContents();
72
73 // First make node items
74 TQPtrListIterator<Node> nit(project.childNodeIterator());
75 for ( ; nit.current(); ++nit ) {
76 createChildItems(createNodeItem(nit.current()));
77 }
78
79 // First all items with relations
80 TQPtrDictIterator<PertNodeItem> it(m_nodes);
81 for(; it.current(); ++it)
82 {
83 if (!(it.current()->hasParent()) && it.current()->hasChild())
84 {
85 m_rows.append(new TQMemArray<bool>(1)); // New node always goes into new row, first column
86 it.current()->move(this, m_rows.count()-1, 0); // item also moves it's children
87 }
88 }
89 // now items without relations
90 for(it.toFirst(); it.current(); ++it)
91 {
92 if (!(it.current()->hasParent() || it.current()->hasChild()))
93 {
94 m_rows.append(new TQMemArray<bool>(1)); // New node always goes into new row, first column
95 it.current()->move(this, m_rows.count()-1, 0);
96 }
97 }
98 drawRelations(); // done _after_ all nodes are drawn
99 TQSize s = canvasSize();
100 m_canvas->resize(s.width(), s.height());
101 update();
102}
103
104PertNodeItem *PertCanvas::createNodeItem(Node *node)
105{
106 PertNodeItem *item = m_nodes.find(node);
107 if (!item)
108 {
109 if ( node->type() == Node::Type_Project)
110 kdDebug()<<k_funcinfo<<"Project nodes should not have relations"<<endl;
111 else if (node->type() == Node::Type_Subproject)
112 item = new PertProjectItem(this, *node);
113 else if (node->type()== Node::Type_Summarytask)
114 item = new PertTaskItem(this, *node);
115 else if (node->type()== Node::Type_Task)
116 item = new PertTaskItem(this, *node);
117 else if (node->type() == Node::Type_Milestone)
118 item = new PertMilestoneItem(this, *node);
119 else
120 kdDebug()<<k_funcinfo<<"Not implemented yet"<<endl;
121
122 if (item)
123 m_nodes.insert(node, item);
124 }
125 return item;
126}
127
128void PertCanvas::createChildItems(PertNodeItem *parentItem)
129{
130 //kdDebug()<<k_funcinfo<<"parentItem="<<(parentItem ? parentItem->node().name() : "nil")<<endl;
131 if (!parentItem)
132 return;
133
134 TQPtrListIterator<Relation> it(parentItem->node().dependChildNodes());
135 for (; it.current(); ++it)
136 {
137 PertNodeItem *childItem = createNodeItem(it.current()->child());
138 if (childItem)
139 parentItem->addChildRelation(it.current(), childItem);
140 m_relations.append(it.current());
141 }
142
143 // Now my children
144 TQPtrListIterator<Node> nit(parentItem->node().childNodeIterator());
145 for ( ; nit.current(); ++nit ) {
146 createChildItems(createNodeItem(nit.current()));
147 }
148}
149
150void PertCanvas::drawRelations()
151{
152 //kdDebug()<<k_funcinfo<<endl;
153 TQPtrListIterator<Relation> it(m_relations);
154 for (; it.current(); ++it)
155 {
156 PertNodeItem *parentItem = m_nodes.find(it.current()->parent());
157 PertNodeItem *childItem = m_nodes.find(it.current()->child());
158 if (parentItem && childItem)
159 {
160 PertRelationItem *item = new PertRelationItem(this, parentItem, childItem, it.current());
161 item->show();
162 }
163 }
164}
165
166void PertCanvas::mapNode(PertNodeItem *item)
167{
168 //kdDebug()<<k_funcinfo<<endl;
169 if (! m_rows.at(item->row()) || (item->column() >= 0 && m_rows.at(item->row())->count() <= uint(item->column())))
170 {
171 kdError()<<k_funcinfo<<item->node().name()<<": non existing map for: ("<<item->row()<<","<<item->column()<<")"<<endl;
172 return;
173 }
174 m_rows.at(item->row())->at(item->column()) = true;
175}
176
177void PertCanvas::mapChildNode(PertNodeItem *parentItem, PertNodeItem *childItem, Relation::Type type)
178{
179 //kdDebug()<<k_funcinfo<<"Parent: "<<parentItem->node().name()<<" to child: "<<(childItem ? childItem->node().name() : "None")<<endl;
180 if (!childItem)
181 { // shouldn't happen...
182 kdError()<<k_funcinfo<<"No childItem"<<endl;
183 return;
184 }
185 int row = parentItem->row();
186 int col = parentItem->column();
187 int chRow = childItem->row();
188 int chCol = childItem->column();
189 bool chMapped = (chRow > -1 && chCol > -1);
190 //kdDebug()<<k_funcinfo<<"Parent: "<<parentItem->node().name()<<" at ("<<row<<","<<col<<"): Moving "<<childItem->node().name()<<" from: "<<chRow<<","<<chCol<<endl;
191
192 if (type == Relation::StartStart ||
193 type == Relation::FinishFinish)
194 {
195 // node goes into row below parent, at least same col
196 if (chMapped)
197 {
198 m_rows.at(chRow)->at(chCol) = false;
199 //kdDebug()<<k_funcinfo<<" Moving "<<childItem->node().name()<<" from: "<<chRow<<","<<chCol<<endl;
200 if (chRow <= row)
201 {
202 chRow = row+1;
203 if (chRow >= 0 && m_rows.count() <= uint(chRow)) {
204 m_rows.append(new TQMemArray<bool>(1)); // make a new row
205 chRow = m_rows.count()-1; // to be safe
206 }
207 //kdDebug()<<k_funcinfo<<" Moving "<<childItem->node().name()<<" to row: "<<chRow<<endl;
208 }
209 if (chCol < col)
210 {
211 chCol = col;
212 if (chCol >= 0 && m_rows.at(chRow)->count() <= uint(chCol)) // col does not exist
213 m_rows.at(chRow)->resize(chCol+1);
214
215 //kdDebug()<<k_funcinfo<<" Moved "<<childItem->node().name()<<" to col: "<<chCol<<endl;
216 }
217
218 }
219 else
220 {
221 if (!(m_rows.at(row+1)) || // next row does not exists
222 m_rows.at(row+1)->at(col) == true) // col is not free
223 {
224 m_rows.append(new TQMemArray<bool>(col+1)); // make a new row
225 }
226 else if (col >= 0 && m_rows.at(row+1)->count() <= uint(col)) // col does not exist
227 m_rows.at(row)->resize(col+1);
228
229 chRow = m_rows.count() -1;
230 chCol = col;
231 }
232 }
233 else if (type == Relation::FinishStart)
234 {
235 // node goes into same row, next col if col free
236 if (chMapped)
237 {
238 m_rows.at(chRow)->at(chCol) = false;
239 if (chRow < row)
240 chRow = row;
241 if (chCol <= col)
242 {
243 chCol = col+1;
244 }
245 if (chCol >= 0 && m_rows.at(chRow)->count() <= uint(chCol)) // col does not exist
246 m_rows.at(chRow)->resize(chCol+1);
247 }
248 else
249 {
250 ++col;
251 if (col >= 0 && m_rows.at(row)->count() <= uint(col))
252 m_rows.at(row)->resize(col+1); // make new column
253 else if (m_rows.at(row)->at(col) = true)
254 m_rows.append(new TQMemArray<bool>(col+1)); // col not free, so make a new row
255
256 chRow = m_rows.count() -1;
257 chCol = col;
258 }
259 }
260 else
261 {
262 kdError()<<k_funcinfo<<"Unknow relation type"<<endl;
263 return;
264 }
265 childItem->move(this, chRow, chCol);
266}
267
268TQSize PertCanvas::canvasSize()
269{
270 //kdDebug()<<k_funcinfo<<endl;
271 TQSize s(0,0);
272 TQCanvasItemList list = canvas()->allItems();
273 TQCanvasItemList::Iterator it = list.begin();
274 for (; it != list.end(); ++it)
275 {
276 TQRect r = (*it)->boundingRect();
277 s.setWidth(TQMAX(s.width(), r.right()));
278 s.setHeight(TQMAX(s.height(), r.bottom()));
279 }
280 s.setWidth(s.width()+20);
281 s.setHeight(s.height()+20);
282 return s;
283}
284
285void PertCanvas::clear()
286{
287 m_nodes.clear();
288 m_relations.clear();
289 m_rows.clear();
290 TQCanvasItemList list = canvas()->allItems();
291 TQCanvasItemList::Iterator it = list.begin();
292 for (; it != list.end(); ++it)
293 {
294 if ( *it )
295 delete *it;
296 }
297}
298
299void PertCanvas::contentsMousePressEvent ( TQMouseEvent * e )
300{
301 //kdDebug()<<k_funcinfo<<" gl.X,gl.Y="<<e->globalX()<<","<<e->globalY()<<" x,y="<<e->x()<<","<<e->y()<<endl;
302 switch (e->button())
303 {
304 case TQt::LeftButton:
305 {
306 break;
307 }
308 case TQt::RightButton:
309 {
310 PertNodeItem *item = selectedItem();
311 if (item)
312 item->setSelected(false);
313 canvas()->update();
314
315 TQCanvasItemList l = canvas()->collisions(e->pos());
316 for (TQCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it)
317 {
318 if ( (*it)->rtti() == PertProjectItem::RTTI ||
319 (*it)->rtti() == PertTaskItem::RTTI ||
320 (*it)->rtti() == PertMilestoneItem::RTTI )
321 {
322 PertNodeItem *item = (PertNodeItem *)(*it);
323 {
324 item->setSelected(true);
325 canvas()->update();
326 emit rightButtonPressed(&(item->node()), e->globalPos());
327 if (item == selectedItem()) {
328 // item maybe deleted
329 item->setSelected(false);
330 }
331 canvas()->update();
332 break;
333 }
334 }
335 }
336 break;
337 }
338 case TQt::MidButton:
339 break;
340 default:
341 break;
342 }
343}
344
345void PertCanvas::contentsMouseReleaseEvent ( TQMouseEvent * e )
346{
347 //kdDebug()<<k_funcinfo<<" gl.X,gl.Y="<<e->globalX()<<","<<e->globalY()<<" x,y="<<e->x()<<","<<e->y()<<endl;
348 switch (e->button())
349 {
350 case TQt::LeftButton:
351 {
352 bool hit = false;
353 TQCanvasItemList l = canvas()->collisions(e->pos());
354 for (TQCanvasItemList::Iterator it=l.begin(); it!=l.end(); ++it)
355 {
356 if ( (*it)->rtti() == PertProjectItem::RTTI ||
357 (*it)->rtti() == PertTaskItem::RTTI ||
358 (*it)->rtti() == PertMilestoneItem::RTTI )
359 {
360 hit = true;
361 PertNodeItem *item = (PertNodeItem *)(*it);
362 PertNodeItem *par = selectedItem();
363 if ( !par)
364 {
365 //kdDebug()<<k_funcinfo<<" First node="<<item->node().name()<<endl;
366 item->setSelected(true);
367 canvas()->update();
368 return;
369 }
370 par->setSelected(false);
371 if (&(item->node()) == &(par->node()))
372 {
373 break;
374 }
375 //kdDebug()<<k_funcinfo<<" Second node="<<item->node().name()<<endl;
376 // open relation dialog
377 if (!par->node().legalToLink(&(item->node()))) {
378 KMessageBox::sorry(this, i18n("Cannot link these nodes"));
379 } else {
380 Relation *rel = item->node().findRelation(&(par->node()));
381 if (rel)
382 emit modifyRelation(rel);
383 else
384 emit addRelation(&(par->node()), &(item->node()));
385 }
386 break;
387 }
388 }
389 if (!hit) {
390 PertNodeItem *i = selectedItem();
391 if (i) i->setSelected(false);
392 }
393 canvas()->update();
394 break;
395 }
396 case TQt::RightButton:
397 {
398 break;
399 }
400 case TQt::MidButton:
401 break;
402 default:
403 break;
404 }
405}
406
407PertNodeItem *PertCanvas::selectedItem()
408{
409 TQCanvasItemList list = canvas()->allItems();
410 TQCanvasItemList::Iterator it = list.begin();
411 for (; it != list.end(); ++it)
412 {
413 if ( (*it)->isSelected() )
414 {
415 if ( (*it)->rtti() == PertProjectItem::RTTI ||
416 (*it)->rtti() == PertTaskItem::RTTI ||
417 (*it)->rtti() == PertMilestoneItem::RTTI )
418 return (PertNodeItem *)(*it);
419 }
420 }
421 return 0;
422}
423
424Node *PertCanvas::selectedNode() {
425 return selectedItem() ? &(selectedItem()->node()) : 0;
426}
427
428#ifndef NDEBUG
429void PertCanvas::printDebug( int /*info*/ )
430{
431}
432#endif
433
434} //KPlato namespace
435
436#include "kptpertcanvas.moc"