00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "kptresourceview.h"
00021
00022 #include "kptcalendar.h"
00023 #include "kptduration.h"
00024 #include "kptresourceappointmentsview.h"
00025 #include "kptview.h"
00026 #include "kptnode.h"
00027 #include "kptproject.h"
00028 #include "kpttask.h"
00029 #include "kptresource.h"
00030 #include "kptdatetime.h"
00031 #include "kptcontext.h"
00032
00033 #include <qheader.h>
00034 #include <qpopupmenu.h>
00035 #include <qpainter.h>
00036 #include <qpaintdevicemetrics.h>
00037 #include <qstyle.h>
00038
00039 #include <klistview.h>
00040 #include <klocale.h>
00041 #include <kglobal.h>
00042 #include <kprinter.h>
00043
00044 #include <kdebug.h>
00045
00046 namespace KPlato
00047 {
00048
00049 class ResListView : public KListView {
00050 public:
00051 ResListView(QWidget * parent = 0, const char* name=0)
00052 : KListView(parent, name)
00053 {}
00054
00055 int headerHeight() const {
00056 return header()->count() > 0 ? header()->sectionRect(0).height() : 0;
00057 }
00058 virtual void paintToPrinter(QPainter *p, int x, int y, int w, int h) {
00059 p->save();
00060 QColor bgc(193, 223, 255);
00061 QBrush bg(bgc);
00062 p->setBackgroundMode(Qt::OpaqueMode);
00063 p->setBackgroundColor(bgc);
00064 QHeader *head = header();
00065 int offset = 0;
00066 QRect sr;
00067
00068 for (int s = 0; s < head->count(); ++s) {
00069 sr = head->sectionRect(s);
00070 if (offset > sr.x())
00071 offset = sr.x();
00072 }
00073 for (int s = 0; s < head->count(); ++s) {
00074 sr = head->sectionRect(s);
00075 if (offset != 0) {
00076 sr = QRect(sr.x()-offset, sr.y(), sr.width(), sr.height());
00077 }
00078
00079 if (sr.x()+sr.width() <= x || sr.x() >= x+w) {
00080
00081 continue;
00082 }
00083 QRect tr = sr;
00084 if (sr.x() < x) {
00085 tr.setX(x);
00086
00087 }
00088 p->eraseRect(tr);
00089 p->drawText(tr, columnAlignment(s)|Qt::AlignVCenter, head->label(s), -1);
00090 }
00091 p->restore();
00092 p->save();
00093 p->translate(0, headerHeight());
00094 drawAllContents(p, x, y, w, h);
00095 p->restore();
00096 }
00097 int calculateY(int ymin, int ymax) const {
00098 QPtrList<ResListView::DrawableItem> drawables;
00099 drawables.setAutoDelete(true);
00100 QListViewItem *child = firstChild();
00101 int level = 0;
00102 int ypos = 0;
00103 for (; child; child = child->nextSibling()) {
00104 ypos = buildDrawables(drawables, level, ypos, child, ymin, ymax);
00105 }
00106 int y = 0;
00107 DrawableItem *item = drawables.getLast();
00108 if (item) {
00109 y = item->y + item->i->height();
00110 }
00111
00112 return y;
00113 }
00114 class DrawableItem {
00115 public:
00116 DrawableItem(int level, int ypos, QListViewItem *item ) { y = ypos; l = level; i = item; };
00117 int y;
00118 int l;
00119 QListViewItem * i;
00120 };
00121 protected:
00122 int buildDrawables(QPtrList<ResListView::DrawableItem> &lst, int level, int ypos, QListViewItem *item, int ymin, int ymax) const {
00123 int y = ypos;
00124 int ih = item->height();
00125 if (y < ymin && y+ih > ymin) {
00126 y = ymin;
00127 }
00128 if (y >= ymin && y+ih < ymax) {
00129 ResListView::DrawableItem *dr = new ResListView::DrawableItem(level, y, item);
00130 lst.append(dr);
00131
00132 }
00133 y += ih;
00134 if (item->isOpen()) {
00135 QListViewItem *child = item->firstChild();
00136 for (; child; child = child->nextSibling()) {
00137 y = buildDrawables(lst, level+1, y, child, ymin, ymax);
00138 }
00139 }
00140 return y;
00141 }
00142
00143
00144
00145
00146 virtual void drawAllContents(QPainter * p, int cx, int cy, int cw, int ch) {
00147 if ( columns() == 0 ) {
00148 paintEmptyArea( p, QRect( cx, cy, cw, ch ) );
00149 return;
00150 }
00151
00152 QPtrList<ResListView::DrawableItem> drawables;
00153 drawables.setAutoDelete(true);
00154 QListViewItem *child = firstChild();
00155 int level = 0;
00156 int ypos = 0;
00157 for (; child; child = child->nextSibling()) {
00158 ypos = buildDrawables(drawables, level, ypos, child, cy, cy+ch);
00159 }
00160
00161 p->setFont( font() );
00162
00163 QPtrListIterator<ResListView::DrawableItem> it(drawables);
00164
00165 QRect r;
00166 int fx = -1, x, fc = 0, lc = 0;
00167 int tx = -1;
00168 ResListView::DrawableItem * current;
00169
00170 while ( (current = it.current()) != 0 ) {
00171 ++it;
00172 int ih = current->i->height();
00173 int ith = current->i->totalHeight();
00174 int c;
00175 int cs;
00176
00177
00178 if ( ih > 0 && current->y < cy+ch && current->y+ih > cy ) {
00179
00180 if ( fx < 0 ) {
00181
00182 x = 0;
00183 c = 0;
00184 cs = header()->cellSize( 0 );
00185 while ( x + cs <= cx && c < header()->count() ) {
00186 x += cs;
00187 c++;
00188 if ( c < header()->count() )
00189 cs = header()->cellSize( c );
00190 }
00191 fx = x;
00192 fc = c;
00193 while( x < cx + cw && c < header()->count() ) {
00194 x += cs;
00195 c++;
00196 if ( c < header()->count() )
00197 cs = header()->cellSize( c );
00198 }
00199 lc = c;
00200 }
00201
00202 x = fx;
00203 c = fc;
00204
00205
00206 const QColorGroup &cg = ( palette().inactive() );
00207
00208 while ( c < lc && !drawables.isEmpty() ) {
00209 int i = header()->mapToLogical( c );
00210 cs = header()->cellSize( c );
00211 r.setRect( x, current->y-cy, cs, ih );
00212 if ( i == 0 )
00213 r.setLeft( r.left() + current->l * treeStepSize() );
00214
00215 p->save();
00216
00217 if ( !( r.width() == 0 || r.height() == 0 ) ) {
00218 p->translate( r.left(), r.top() );
00219 int ac = header()->mapToLogical( c );
00220
00221
00222 int align = columnAlignment( ac );
00223 if ( align == AlignAuto ) align = AlignLeft;
00224 bool sel = current->i->isSelected();
00225 if (sel)
00226 current->i->setSelected(false);
00227 current->i->paintCell( p, cg, ac, r.width(), align );
00228 if (sel)
00229 current->i->setSelected(sel);
00230 }
00231 p->restore();
00232 x += cs;
00233 c++;
00234 }
00235
00236 }
00237
00238 const int cell = header()->mapToActual( 0 );
00239
00240 if ( tx < 0 )
00241 tx = header()->cellPos( cell );
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276 }
00277 }
00278
00279 };
00280
00281 class ResourceItemPrivate : public KListViewItem {
00282 public:
00283 ResourceItemPrivate(Resource *r, QListViewItem *parent)
00284 : KListViewItem(parent, r->name()),
00285 resource(r) {}
00286
00287 Resource *resource;
00288
00289 virtual void paintCell(QPainter *p, const QColorGroup &cg, int column, int width, int align) {
00290 QColorGroup g = cg;
00291 if (m_columns[column] == 1) {
00292 g.setColor(QColorGroup::Text, QColor(red));
00293 g.setColor(QColorGroup::HighlightedText, QColor(red));
00294 }
00295
00296 KListViewItem::paintCell(p, g, column, width, align);
00297 }
00298 void setColumnState(int c, int state=1) {
00299 m_columns[c] = state;
00300 }
00301 private:
00302 QMap<int, int> m_columns;
00303 };
00304
00305 class NodeItemPrivate : public KListViewItem {
00306 public:
00307 NodeItemPrivate(Task *n, QListView *parent)
00308 : KListViewItem(parent, n->name()),
00309 node(n) {
00310 init();
00311 }
00312
00313 NodeItemPrivate(QString name, QListView *parent)
00314 : KListViewItem(parent, name),
00315 node(0) {
00316 init();
00317 }
00318
00319 void setPriority(int col, int prio) {
00320 if (prioColors.contains(prio)) {
00321 columnPrio.insert(col, prio);
00322 } else {
00323 columnPrio.remove(col);
00324 }
00325 }
00326 int priority(int col) {
00327 if (columnPrio.contains(col)) {
00328 return columnPrio[col];
00329 }
00330 return 0;
00331 }
00332
00333 virtual void paintCell ( QPainter * p, const QColorGroup & cg, int column, int width, int align ) {
00334
00335 QColorGroup g = cg;
00336 if (columnPrio.contains(column)) {
00337 g.setColor(QColorGroup::Base, prioColors[columnPrio[column]]);
00338 }
00339 KListViewItem::paintCell(p, g, column, width, align);
00340 }
00341
00342 Task *node;
00343 private:
00344 void init() {
00345 prioColors.insert(1, QColor(gray));
00346 prioColors.insert(2, QColor(green));
00347 prioColors.insert(3, QColor(yellow));
00348 prioColors.insert(4, QColor(red));
00349 }
00350 QMap<int, QColor> prioColors;
00351 QMap<int, int> columnPrio;
00352 };
00353
00354 class AppointmentItem : public KListViewItem {
00355 public:
00356 AppointmentItem(Appointment *a, QDate &d, QListViewItem *parent)
00357 : KListViewItem(parent),
00358 appointment(a),
00359 date(d) {}
00360
00361 Appointment *appointment;
00362 QDate date;
00363 };
00364
00365 QSize ResourceView::sizeHint() const {
00366 return minimumSizeHint();
00367 }
00368
00369 ResourceView::ResourceView(View *view, QWidget *parent)
00370 : QSplitter(parent, "Resource view"),
00371 m_mainview(view),
00372 m_selectedItem(0),
00373 m_currentNode(0)
00374 {
00375 setOrientation(QSplitter::Vertical);
00376
00377 resList = new ResListView(this, "Resource list");
00378 resList->setItemMargin(2);
00379 #if KDE_IS_VERSION(3,3,9)
00380 resList->setShadeSortColumn(false);
00381 #endif
00382 resList->setRootIsDecorated(true);
00383 resList->addColumn(i18n("Name"));
00384 resList->setColumnAlignment(1, AlignHCenter);
00385 resList->addColumn(i18n("Type"));
00386 resList->setColumnAlignment(2, AlignHCenter);
00387 resList->addColumn(i18n("Initials"));
00388 resList->setColumnAlignment(3, AlignLeft);
00389 resList->addColumn(i18n("Email"));
00390 resList->setColumnAlignment(4, AlignHCenter);
00391 resList->addColumn(i18n("Calendar Name"));
00392 resList->setColumnAlignment(5, AlignRight);
00393 resList->addColumn(i18n("Available From"));
00394 resList->setColumnAlignment(6, AlignRight);
00395 resList->addColumn(i18n("Available Until"));
00396 resList->setColumnAlignment(7, AlignRight);
00397 resList->addColumn(i18n("%"));
00398 resList->setColumnAlignment(8, AlignRight);
00399 resList->addColumn(i18n("Normal Rate"));
00400 resList->setColumnAlignment(9, AlignRight);
00401 resList->addColumn(i18n("Overtime Rate"));
00402
00403 m_showAppointments = false;
00404 m_appview = new ResourceAppointmentsView(view, this);
00405 m_appview->hide();
00406 draw(view->getProject());
00407
00408
00409 connect(resList, SIGNAL(selectionChanged()), SLOT(resSelectionChanged()));
00410 connect(resList, SIGNAL( contextMenuRequested(QListViewItem*, const QPoint&, int)), SLOT(popupMenuRequested(QListViewItem*, const QPoint&, int)));
00411
00412 connect(resList, SIGNAL(doubleClicked(QListViewItem*, const QPoint&, int)), SLOT(slotItemDoubleClicked(QListViewItem*)));
00413
00414 }
00415
00416 void ResourceView::zoom(double )
00417 {
00418 }
00419
00420 Resource *ResourceView::currentResource() {
00421 if (m_selectedItem)
00422 return m_selectedItem->resource;
00423 return 0;
00424 }
00425
00426 void ResourceView::draw(Project &project)
00427 {
00428
00429 resList->clear();
00430 m_appview->clear();
00431 m_selectedItem = 0;
00432
00433 QPtrListIterator<ResourceGroup> it(project.resourceGroups());
00434 for (; it.current(); ++it) {
00435 KListViewItem *item = new KListViewItem(resList, it.current()->name());
00436 item->setOpen(true);
00437 drawResources(project, item, it.current());
00438 }
00439 if (m_selectedItem) {
00440 resList->setSelected(m_selectedItem, true);
00441 } else {
00442 resSelectionChanged(m_selectedItem);
00443 }
00444 }
00445
00446
00447 void ResourceView::drawResources(const Project &proj, QListViewItem *parent, ResourceGroup *group)
00448 {
00449
00450 QPtrListIterator<Resource> it(group->resources());
00451 for (; it.current(); ++it) {
00452 Resource *r = it.current();
00453 ResourceItemPrivate *item = new ResourceItemPrivate(r, parent);
00454
00455 item->setColumnState(0, 0);
00456 item->setColumnState(4, 0);
00457 item->setColumnState(5, 0);
00458 item->setColumnState(6, 0);
00459 item->setColumnState(7, 0);
00460 if (r->calendar() == 0) {
00461 item->setColumnState(0, 1);
00462 item->setColumnState(4, 1);
00463 }
00464 if (proj.constraint() == Node::MustFinishOn) {
00465 if (proj.mustFinishOn() <= r->availableFrom()) {
00466 item->setColumnState(0, 1);
00467 item->setColumnState(5, 1);
00468 }
00469 } else {
00470 if (proj.mustStartOn() >= r->availableUntil()) {
00471 item->setColumnState(0, 1);
00472 item->setColumnState(6, 1);
00473 }
00474 }
00475 if (r->units() == 0) {
00476 item->setColumnState(0, 1);
00477 item->setColumnState(7, 1);
00478 }
00479
00480 item->setText(0, r->name());
00481 switch (r->type()) {
00482 case Resource::Type_Work:
00483 item->setText(1, i18n("Work"));
00484 break;
00485 case Resource::Type_Material:
00486 item->setText(1, i18n("Material"));
00487 break;
00488 default:
00489 item->setText(1, i18n("Undefined"));
00490 break;
00491 }
00492 item->setText(2, r->initials());
00493 item->setText(3, r->email());
00494 item->setText(4, r->calendar() ? r->calendar()->name() : i18n("None"));
00495 item->setText(5, KGlobal::locale()->formatDateTime(r->availableFrom()));
00496 item->setText(6, KGlobal::locale()->formatDateTime(r->availableUntil()));
00497 item->setText(7, QString().setNum(r->units()));
00498 item->setText(8, KGlobal::locale()->formatMoney(r->normalRate()));
00499 item->setText(9, KGlobal::locale()->formatMoney(r->overtimeRate()));
00500 if (!m_selectedItem) {
00501 m_selectedItem = item;
00502 }
00503 }
00504 }
00505
00506
00507 void ResourceView::resSelectionChanged() {
00508
00509 resSelectionChanged(resList->selectedItem());
00510 }
00511
00512 void ResourceView::resSelectionChanged(QListViewItem *item) {
00513
00514 ResourceItemPrivate *ritem = dynamic_cast<ResourceItemPrivate *>(item);
00515 if (ritem) {
00516 m_selectedItem = ritem;
00517 if (m_showAppointments) {
00518 m_appview->show();
00519 m_appview->draw(ritem->resource, m_mainview->getProject().startTime().date(), m_mainview->getProject().endTime().date());
00520 } else {
00521 m_appview->hide();
00522 }
00523 return;
00524 }
00525 m_selectedItem = 0;
00526 m_appview->clear();
00527 }
00528
00529
00530 void ResourceView::slotItemDoubleClicked(QListViewItem*) {
00531 emit itemDoubleClicked();
00532 }
00533
00534 void ResourceView::popupMenuRequested(QListViewItem* item, const QPoint & pos, int)
00535 {
00536 ResourceItemPrivate *ritem = dynamic_cast<ResourceItemPrivate *>(item);
00537 if (ritem) {
00538 if (ritem != m_selectedItem)
00539 resSelectionChanged(ritem);
00540 QPopupMenu *menu = m_mainview->popupMenu("resource_popup");
00541 if (menu)
00542 {
00543 menu->exec(pos);
00544
00545 }
00546 else
00547 kdDebug()<<k_funcinfo<<"No menu!"<<endl;
00548 }
00549 }
00550
00551 QValueList<int> ResourceView::listOffsets(int pageHeight) const {
00552 QValueList<int> lst;
00553 int hh = resList->headerHeight();
00554 int ph = pageHeight-hh;
00555 int lh = resList->contentsHeight() - hh;
00556 int ly = 0;
00557 kdDebug()<<k_funcinfo<<ly<<", "<<lh<<endl;
00558 while (ly < lh) {
00559 lst << ly;
00560 ly = resList->calculateY(ly+1, ly+ph);
00561
00562 }
00563 return lst;
00564 }
00565
00566 void ResourceView::print(KPrinter &printer) {
00567
00568 QPaintDeviceMetrics m = QPaintDeviceMetrics ( &printer );
00569 uint top, left, bottom, right;
00570 printer.margins(&top, &left, &bottom, &right);
00571
00572 QPainter p;
00573 p.begin(&printer);
00574 p.setViewport(left, top, m.width()-left-right, m.height()-top-bottom);
00575 p.setClipRect(left, top, m.width()-left-right, m.height()-top-bottom);
00576 QRect preg = p.clipRegion(QPainter::CoordPainter).boundingRect();
00577
00578
00579 int ch = resList->contentsHeight();
00580 int cw = resList->contentsWidth();
00581 double scale = (double)preg.width()/(double)(cw);
00582
00583 if (scale < 1.0) {
00584 p.scale(scale, scale);
00585 }
00586 int ph = preg.height()-resList->headerHeight();
00587 QValueList<int> lst = listOffsets(preg.height());
00588 for (int i=0; i < lst.count(); ++i) {
00589
00590 if (i > 0) {
00591 printer.newPage();
00592 }
00593 resList->paintToPrinter(&p, 0, lst[i], cw, ph);
00594 }
00595
00596 p.end();
00597 }
00598
00599 bool ResourceView::setContext(Context::Resourceview &) {
00600
00601 return true;
00602 }
00603
00604 void ResourceView::getContext(Context::Resourceview &) const {
00605
00606 }
00607
00608
00609 }
00610
00611 #include "kptresourceview.moc"