lib

editoritem.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr>
00003    Copyright (C) 2004 Alexander Dymo <cloudtemple@mskat.net>
00004    Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00019  * Boston, MA 02110-1301, USA.
00020 */
00021 
00022 #include "editoritem.h"
00023 #include "editor.h"
00024 #include "property.h"
00025 #include "widget.h"
00026 #include "factory.h"
00027 #include "utils.h"
00028 
00029 #include <qpainter.h>
00030 #include <qpixmap.h>
00031 #include <qheader.h>
00032 #include <qstyle.h>
00033 #include <qlabel.h>
00034 #include <qlayout.h>
00035 
00036 #include <kdebug.h>
00037 #include <kiconloader.h>
00038 #include <kstyle.h>
00039 #include <kpopupmenu.h>
00040 #include <kapplication.h>
00041 
00042 #define BRANCHBOX_SIZE 9
00043 
00044 namespace KoProperty {
00045 class EditorItemPrivate
00046 {
00047     public:
00048         EditorItemPrivate()
00049         : property(0) {}
00050         ~EditorItemPrivate() {}
00051 
00052         Property  *property;
00053         Editor  *editor;
00054 };
00055 
00057 static void paintListViewExpander(QPainter* p, QWidget* w, int height, const QColorGroup& cg, bool isOpen)
00058 {
00059     const int marg = (height -2 - BRANCHBOX_SIZE) / 2;
00060     int xmarg = marg;
00061 //      if (dynamic_cast<EditorGroupItem*>(item))
00062 //              xmarg = xmarg * 10 / 14 -1;
00063 #if 0 
00065     KStyle* kstyle = dynamic_cast<KStyle*>(widget->style());
00066     if (kstyle) {
00067         kstyle->drawKStylePrimitive(
00068             KStyle::KPE_ListViewExpander, p, w, QRect( xmarg, marg, BRANCHBOX_SIZE, BRANCHBOX_SIZE ), 
00069             cg, isOpen ? 0 : QStyle::Style_On,
00070                 QStyleOption::Default);
00071     }
00072     else {
00073 #endif
00074         Q_UNUSED(w);
00075         //draw by hand
00076         p->setPen( KPROPEDITOR_ITEM_BORDER_COLOR );
00077         p->drawRect(xmarg, marg, BRANCHBOX_SIZE, BRANCHBOX_SIZE);
00078         p->fillRect(xmarg+1, marg + 1, BRANCHBOX_SIZE-2, BRANCHBOX_SIZE-2,
00079 //          item->listView()->paletteBackgroundColor());
00080             cg.base());
00081 //      p->setPen( item->listView()->paletteForegroundColor() );
00082         p->setPen( cg.foreground() );
00083         p->drawLine(xmarg+2, marg+BRANCHBOX_SIZE/2, xmarg+BRANCHBOX_SIZE-3, marg+BRANCHBOX_SIZE/2);
00084         if(!isOpen) {
00085             p->drawLine(xmarg+BRANCHBOX_SIZE/2, marg+2,
00086                 xmarg+BRANCHBOX_SIZE/2, marg+BRANCHBOX_SIZE-3);
00087         }
00088 //  }
00089 }
00090 
00093 class GroupWidgetBase : public QWidget
00094 {
00095     public:
00096         GroupWidgetBase(QWidget* parent)
00097         : QWidget(parent)
00098         , m_isOpen(true)
00099         , m_mouseDown(false)
00100         {
00101             setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed, 0, 1));
00102         }
00103 
00104         void setText( const QString &text )
00105         {
00106             m_titleStr = text;
00107         }
00108 
00109         void setIcon( const QPixmap &pix )
00110         {
00111             m_miniicon = pix;
00112         }
00113 
00114         virtual bool isOpen() const
00115         {
00116             return m_isOpen;
00117         }
00118 
00119         virtual void setOpen(bool set)
00120         {
00121             m_isOpen = set;
00122         }
00123 
00124         virtual QSize sizeHint () const
00125         {
00126             QSize s( QWidget::sizeHint() );
00127             s.setHeight(fontMetrics().height()*2);
00128             return s;
00129         }
00130 
00131     protected:
00132         virtual void paintEvent(QPaintEvent *) {
00133             QRect r(rect());
00134             QPainter p(this);
00135             QStyle::StyleFlags flags = m_mouseDown ? QStyle::Style_Down : QStyle::Style_Default;
00136             kapp->style().drawPrimitive(QStyle::PE_HeaderSection, &p, r, palette().active(), flags);
00137 
00138             paintListViewExpander(&p, this, r.height()+2, palette().active(), isOpen());
00139             if (!m_miniicon.isNull()) {
00140                 p.drawPixmap(24, (r.height()-m_miniicon.height())/2, m_miniicon);
00141             }
00142 
00143             if (!m_titleStr.isNull())
00144             {
00145                 int indent = 16 + (m_miniicon.isNull() ? 0 : (m_miniicon.width()+4));
00146                 p.setPen(palette().active().text());
00147                 QFont f = p.font();
00148                 f.setBold(true);
00149                 p.setFont(f);
00150                 p.drawText(indent+8, 0, width()-(indent+8),
00151                         height(), AlignLeft | AlignVCenter | SingleLine,
00152                         m_titleStr);
00153             }
00154 //          p.setPen(palette().active().mid());
00155 //          p.drawLine(0, 0, r.right(), 0);
00156         }
00157 
00158         virtual bool event( QEvent * e ) {
00159             if (e->type()==QEvent::MouseButtonPress || e->type()==QEvent::MouseButtonRelease) {
00160                 QMouseEvent* me = static_cast<QMouseEvent*>(e);
00161                 if (me->button() == Qt::LeftButton) {
00162                     m_mouseDown = e->type()==QEvent::MouseButtonPress;
00163                     update();
00164                 }
00165             }
00166             return QWidget::event(e);
00167         }
00168 
00169     protected:
00170         QString m_titleStr;
00171         QPixmap m_miniicon;
00172         bool m_isOpen : 1;
00173         bool m_mouseDown : 1;
00174 };
00175 
00176 class GroupWidget : public GroupWidgetBase
00177 {
00178     public:
00179         GroupWidget(EditorGroupItem *parentItem)
00180         : GroupWidgetBase(parentItem->listView()->viewport())
00181         , m_parentItem(parentItem)
00182         {
00183         }
00184 
00185         virtual bool isOpen() const
00186         {
00187             return m_parentItem->isOpen();
00188         }
00189 
00190     protected:
00191         EditorGroupItem *m_parentItem;
00192 };
00193 
00194 class GroupContainer::Private
00195 {
00196     public:
00197         Private() {}
00198         QVBoxLayout* lyr;
00199         GroupWidgetBase *groupWidget;
00200         QGuardedPtr<QWidget> contents;
00201 };
00202 
00203 }//namespace
00204 
00205 using namespace KoProperty;
00206 
00207 GroupContainer::GroupContainer(const QString& title, QWidget* parent)
00208 : QWidget(parent)
00209 , d(new Private())
00210 {
00211     setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed, 0, 1));
00212     d->lyr = new QVBoxLayout(this);
00213     d->groupWidget = new GroupWidgetBase(this);
00214     d->groupWidget->setText( title );
00215     d->lyr->addWidget(d->groupWidget);
00216     d->lyr->addSpacing(4);
00217 }
00218 
00219 GroupContainer::~GroupContainer()
00220 {
00221     delete d;
00222 }
00223 
00224 void GroupContainer::setContents( QWidget* contents )
00225 {
00226     if (d->contents) {
00227         d->contents->hide();
00228         d->lyr->remove(d->contents);
00229         delete d->contents;
00230     }
00231     d->contents = contents;
00232     if (d->contents) {
00233         d->lyr->addWidget(d->contents);
00234         d->contents->show();
00235     }
00236     update();
00237 }
00238 
00239 bool GroupContainer::event( QEvent * e ) {
00240     if (e->type()==QEvent::MouseButtonPress) {
00241         QMouseEvent* me = static_cast<QMouseEvent*>(e);
00242         if (me->button() == Qt::LeftButton && d->contents && d->groupWidget->rect().contains(me->pos())) {
00243             d->groupWidget->setOpen(!d->groupWidget->isOpen());
00244             if (d->groupWidget->isOpen())
00245                 d->contents->show();
00246             else
00247                 d->contents->hide();
00248             d->lyr->invalidate();
00249             update();
00250         }
00251     }
00252     return QWidget::event(e);
00253 }
00254 
00256 
00257 EditorItem::EditorItem(Editor *editor, EditorItem *parent, Property *property, QListViewItem *after)
00258  : KListViewItem(parent, after,
00259     property->captionForDisplaying().isEmpty() ? property->name() : property->captionForDisplaying())
00260 {
00261     d = new EditorItemPrivate();
00262     d->property = property;
00263     d->editor = editor;
00264 
00265     setMultiLinesEnabled(true);
00266     //setHeight(static_cast<Editor*>(listView())->baseRowHeight()*3);
00267 /*
00268     if (property && !property->caption().isEmpty()) {
00269             QSimpleRichText srt(property->caption(), font());
00270             srt.setWidth(columnWidth(0)-KPROPEDITOR_ITEM_MARGIN*2-20+1);
00271             int oldHeight = it.current()->height();
00272             int textHeight = srt.height()+KPROPEDITOR_ITEM_MARGIN;
00273             int textLines = textHeight / d->baseRowHeight + (((textHeight % d->baseRowHeight) > 0) ? 1 : 0);
00274             kdDebug() << " textLines: " << textLines << endl;
00275             if (textLines != newNumLines) {
00276                 dynamic_cast<EditorItem*>(it.current())->setHeight(newNumLines * d->baseRowHeight);
00277             }
00278             kdDebug() << it.current()->text(0) << ":  "  << oldHeight << " -> " << newHeight << endl;
00279         }
00280 */
00281 }
00282 
00283 EditorItem::EditorItem(KListView *parent)
00284  : KListViewItem(parent)
00285 {
00286     d = new EditorItemPrivate();
00287     d->property = 0;
00288     d->editor = 0;
00289     setMultiLinesEnabled(true);
00290 }
00291 
00292 EditorItem::EditorItem(EditorItem *parent, const QString &text)
00293  : KListViewItem(parent, text)
00294 {
00295     d = new EditorItemPrivate();
00296     d->property = 0;
00297     d->editor = 0;
00298     setMultiLinesEnabled(true);
00299 }
00300 
00301 EditorItem::EditorItem(EditorItem *parent, EditorItem *after, const QString &text)
00302  : KListViewItem(parent, after, text)
00303 {
00304     d = new EditorItemPrivate();
00305     d->property = 0;
00306     d->editor = 0;
00307     setMultiLinesEnabled(true);
00308 }
00309 
00310 EditorItem::~EditorItem()
00311 {
00312     delete d;
00313 }
00314 
00315 Property*
00316 EditorItem::property()
00317 {
00318     return d->property;
00319 }
00320 
00321 void
00322 EditorItem::paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int align)
00323 {
00324     //int margin = static_cast<Editor*>(listView())->itemMargin();
00325     if(!d->property)
00326         return;
00327 
00328     if(column == 0)
00329     {
00330         QFont font = listView()->font();
00331         if(d->property->isModified())
00332             font.setBold(true);
00333         p->setFont(font);
00334         p->setBrush(cg.highlight());
00335         p->setPen(cg.highlightedText());
00336         KListViewItem::paintCell(p, cg, column, width, align);
00337         p->fillRect(parent() ? 0 : 50, 0, width, height()-1,
00338             QBrush(isSelected() ? cg.highlight() : backgroundColor()));
00339         p->setPen(isSelected() ? cg.highlightedText() : cg.text());
00340         int delta = -20+KPROPEDITOR_ITEM_MARGIN;
00341         if ((firstChild() && dynamic_cast<EditorGroupItem*>(parent()))) {
00342             delta = -KPROPEDITOR_ITEM_MARGIN-1;
00343         }
00344         if (dynamic_cast<EditorDummyItem*>(parent())) {
00345             delta = KPROPEDITOR_ITEM_MARGIN*2;
00346         }
00347         else if (parent() && dynamic_cast<EditorDummyItem*>(parent()->parent())) {
00348             if (dynamic_cast<EditorGroupItem*>(parent()))
00349                 delta += KPROPEDITOR_ITEM_MARGIN*2;
00350             else
00351                 delta += KPROPEDITOR_ITEM_MARGIN*5;
00352         }
00353         p->drawText(
00354             QRect(delta,2, width+listView()->columnWidth(1)-KPROPEDITOR_ITEM_MARGIN*2, height()),
00355             Qt::AlignLeft | Qt::AlignTop /*| Qt::SingleLine*/, text(0));
00356 
00357         p->setPen( KPROPEDITOR_ITEM_BORDER_COLOR );
00358         p->drawLine(width-1, 0, width-1, height()-1);
00359         p->drawLine(0, -1, width-1, -1);
00360 
00361         p->setPen( KPROPEDITOR_ITEM_BORDER_COLOR ); 
00362         if (dynamic_cast<EditorDummyItem*>(parent()))
00363             p->drawLine(0, 0, 0, height()-1 );
00364     }
00365     else if(column == 1)
00366     {
00367         QColorGroup icg(cg);
00368         icg.setColor(QColorGroup::Background, backgroundColor());
00369         p->setBackgroundColor(backgroundColor());
00370         Widget *widget = d->editor->createWidgetForProperty(d->property, false /*don't change Widget::property() */);
00371         if(widget) {
00372             QRect r(0, 0, d->editor->header()->sectionSize(1), height() - (widget->hasBorders() ? 0 : 1));
00373             p->setClipRect(r, QPainter::CoordPainter);
00374             p->setClipping(true);
00375             widget->drawViewer(p, icg, r, d->property->value());
00376             p->setClipping(false);
00377         }
00378     }
00379     p->setPen( KPROPEDITOR_ITEM_BORDER_COLOR ); 
00380     p->drawLine(0, height()-1, width, height()-1 );
00381 }
00382 
00383 void
00384 EditorItem::paintBranches(QPainter *p, const QColorGroup &cg, int w, int y, int h)
00385 {
00386     p->eraseRect(0,0,w,h);
00387     KListViewItem *item = static_cast<KListViewItem*>(firstChild());
00388     if(!item)
00389         return;
00390 
00391     QColor backgroundColor;
00392     p->save();
00393     p->translate(0,y);
00394     QFont font = listView()->font();
00395     while(item)
00396     {
00397         if(item->isSelected())
00398             backgroundColor = cg.highlight();
00399         else {
00400             if (dynamic_cast<EditorGroupItem*>(item))
00401                 backgroundColor = cg.base();
00402             else
00403                 backgroundColor = item->backgroundColor();
00404         }
00405 //      p->fillRect(-50,0,50, item->height(), QBrush(backgroundColor));
00406         p->save();
00407         p->setPen( KPROPEDITOR_ITEM_BORDER_COLOR );
00408         int delta = 0;
00409         int fillWidth = w;
00410         int x = 0;
00411         if (dynamic_cast<EditorGroupItem*>(item->parent())) {
00412             delta = 0;//-19;
00413             fillWidth += 19;
00414         }
00415         else {
00416             if (dynamic_cast<EditorGroupItem*>(item) || /*for flat mode*/ dynamic_cast<EditorDummyItem*>(item->parent()))
00417                 x = 19;
00418             else
00419                 x = -19;
00420             fillWidth += 19;
00421         }
00422         if (dynamic_cast<EditorDummyItem*>(item->parent())) {
00423             x = 19;
00424         }
00425         else if (item->parent() && dynamic_cast<EditorDummyItem*>(item->parent()->parent())) {
00426             x = 0;
00427         }
00428         p->fillRect(x+1, 0, fillWidth-1, item->height()-1, QBrush(backgroundColor));
00429         p->drawLine(x, item->height()-1, w, item->height()-1 );
00430         if (!dynamic_cast<EditorGroupItem*>(item))
00431             p->drawLine(x, 0, x, item->height()-1 );
00432         p->restore();
00433 
00434 //  for (int i=0; i<10000000; i++)
00435 //      ;
00436 //      if(item->isSelected())  {
00437 //          p->fillRect(parent() ? 0 : 50, 0, w, item->height()-1, QBrush(cg.highlight()));
00438 //          p->fillRect(-50,0,50, item->height(), QBrush(cg.highlight()));
00439 //      }
00440 
00441         //sorry, but we need to draw text here again
00442         font.setBold( dynamic_cast<EditorGroupItem*>(item)
00443             || (static_cast<EditorItem*>(item)->property() && static_cast<EditorItem*>(item)->property()->isModified()) );
00444         p->setFont(font);
00445         p->setPen(item->isSelected() ? cg.highlightedText() : cg.text());
00446         if (item->firstChild() && dynamic_cast<EditorGroupItem*>(item->parent())) {
00447             delta = 19-KPROPEDITOR_ITEM_MARGIN-1;
00448         }
00449         else if (dynamic_cast<EditorDummyItem*>(item->parent())) {
00450             delta = 19;
00451         }
00452         if (item->parent() && dynamic_cast<EditorDummyItem*>(item->parent()->parent())) {
00453             if (dynamic_cast<EditorGroupItem*>(item->parent()))
00454                 delta += KPROPEDITOR_ITEM_MARGIN*2;
00455             else
00456                 delta += KPROPEDITOR_ITEM_MARGIN*5;
00457         }
00458 
00459         if (!dynamic_cast<EditorDummyItem*>(item->parent()))
00460             p->drawText(QRect(delta+1,0, w+listView()->columnWidth(1), item->height()),
00461             Qt::AlignLeft | Qt::AlignVCenter /*| Qt::SingleLine*/, item->text(0));
00462 
00463         if(item->firstChild())  {
00464             paintListViewExpander(p, listView(), item->height(),
00465                 cg, item->isOpen());
00466         }
00467 
00468         // draw icon (if there is one)
00469         EditorItem *editorItem = dynamic_cast<EditorItem*>(item);
00470         if (editorItem && editorItem->property() && !editorItem->property()->icon().isEmpty()) {
00471             //int margin = listView()->itemMargin();
00472             QPixmap pix = SmallIcon(editorItem->property()->icon());
00473             if (!pix.isNull())
00474                 p->drawPixmap(-19+(19-pix.width())/2, (item->height() - pix.height()) / 2, pix);
00475         }
00476 
00477         p->translate(0, item->totalHeight());
00478         item = (KListViewItem*)item->nextSibling();
00479     }
00480     p->restore();
00481 }
00482 
00483 void
00484 EditorItem::paintFocus(QPainter *, const QColorGroup &, const QRect & )
00485 {
00486 }
00487 
00488 int
00489 EditorItem::compare( QListViewItem *i, int col, bool ascending ) const
00490 {
00491     if (!ascending)
00492         return -QListViewItem::key( col, ascending ).localeAwareCompare( i->key( col, ascending ) );
00493 
00494     if (d->property) {
00495 //      kopropertydbg << d->property->name() << " " << d->property->sortingKey() << " | "
00496 //          << static_cast<EditorItem*>(i)->property()->name() << " "
00497 //          << static_cast<EditorItem*>(i)->property()->sortingKey() << endl;
00498         return d->property->sortingKey()
00499             - ((dynamic_cast<EditorItem*>(i) && dynamic_cast<EditorItem*>(i)->property()) 
00500                 ? dynamic_cast<EditorItem*>(i)->property()->sortingKey() : 0);
00501     }
00502 
00503     return 0;
00504 //  return d->order - static_cast<EditorItem*>(i)->d->order;
00505 }
00506 
00507 void
00508 EditorItem::setHeight( int height )
00509 {
00510     KListViewItem::setHeight(height);
00511 }
00512 
00514 
00515 EditorGroupItem::EditorGroupItem(EditorItem *parent, EditorItem *after, const QString &text, const QString &icon, int sortOrder)
00516  : EditorItem(parent, after, text)
00517  , m_label(0)
00518  , m_sortOrder(sortOrder)
00519 {
00520     init(icon);
00521 }
00522 
00523 EditorGroupItem::EditorGroupItem(EditorItem *parent, const QString &text, const QString &icon, int sortOrder)
00524  : EditorItem(parent, text)
00525  , m_label(0)
00526  , m_sortOrder(sortOrder)
00527 {
00528     init(icon);
00529 }
00530 
00531 EditorGroupItem::~EditorGroupItem()
00532 {
00533     delete m_label;
00534 }
00535 
00536 QWidget* EditorGroupItem::label() const
00537 {
00538     return m_label;
00539 }
00540 
00541 void EditorGroupItem::init(const QString &icon)
00542 {
00543     setOpen(true);
00544     setSelectable(false);
00545     m_label = new GroupWidget(this);
00546     m_label->setText(text(0)); //todo: icon?
00547     if (!icon.isEmpty())
00548         m_label->setIcon( SmallIcon(icon) );
00549     m_label->show();
00550 }
00551 
00552 void
00553 EditorGroupItem::paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int /*align*/)
00554 {
00555     Q_UNUSED(p);
00556     Q_UNUSED(cg);
00557     Q_UNUSED(column);
00558     Q_UNUSED(width);
00559     //no need to draw anything since there's a label on top of it
00560 //  p->fillRect(0, 0, width, height(), cg.base());
00561 
00562     //if(column == 1)
00563     //  return;
00564     /*p->setPen( KPROPEDITOR_ITEM_BORDER_COLOR ); //! \todo custom color?
00565 
00566     p->setClipRect(listView()->itemRect(this));
00567     if(column == 1)
00568         p->translate(-listView()->columnWidth(0) + 20, 0);
00569     int totalWidth = listView()->columnWidth(0) + listView()->columnWidth(1) - 20;
00570     p->eraseRect(QRect(0,0, totalWidth,height()-1));
00571     p->drawLine(0, height()-1, totalWidth-1, height()-1);
00572 
00573     QFont font = listView()->font();
00574     font.setBold(true);
00575     p->setFont(font);
00576     p->setBrush(cg.highlight());
00577     //p->setPen(cg.highlightedText());
00578     KListViewItem::paintCell(p, cg, column, width, align);
00579     p->setPen(cg.text());
00580     p->drawText(QRect(0,0, totalWidth, height()),
00581         Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine, text(0));*/
00582 }
00583 
00584 void
00585 EditorGroupItem::setup()
00586 {
00587     KListViewItem::setup();
00588     setHeight( height()+4 );
00589 }
00590 
00591 int
00592 EditorGroupItem::compare( QListViewItem *i, int col, bool ascending ) const
00593 {
00594     Q_UNUSED(col);
00595     Q_UNUSED(ascending);
00596     if (dynamic_cast<EditorGroupItem*>(i)) {
00597         return m_sortOrder 
00598             - dynamic_cast<EditorGroupItem*>(i)->m_sortOrder;
00599     }
00600     return 0;
00601 }
00602 
00604 
00605 EditorDummyItem::EditorDummyItem(KListView *listview)
00606  : EditorItem(listview)
00607 {
00608     setSelectable(false);
00609     setOpen(true);
00610 }
00611 
00612 EditorDummyItem::~EditorDummyItem()
00613 {}
00614 
00615 void
00616 EditorDummyItem::setup()
00617 {
00618     setHeight(0);
00619 }
KDE Home | KDE Accessibility Home | Description of Access Keys