diff options
Diffstat (limited to 'lib/koproperty/editoritem.cpp')
-rw-r--r-- | lib/koproperty/editoritem.cpp | 619 |
1 files changed, 619 insertions, 0 deletions
diff --git a/lib/koproperty/editoritem.cpp b/lib/koproperty/editoritem.cpp new file mode 100644 index 00000000..604c9fab --- /dev/null +++ b/lib/koproperty/editoritem.cpp @@ -0,0 +1,619 @@ +/* This file is part of the KDE project + Copyright (C) 2004 Cedric Pasteur <cedric.pasteur@free.fr> + Copyright (C) 2004 Alexander Dymo <cloudtemple@mskat.net> + Copyright (C) 2004-2006 Jaroslaw Staniek <js@iidea.pl> + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "editoritem.h" +#include "editor.h" +#include "property.h" +#include "widget.h" +#include "factory.h" +#include "utils.h" + +#include <qpainter.h> +#include <qpixmap.h> +#include <qheader.h> +#include <qstyle.h> +#include <qlabel.h> +#include <qlayout.h> + +#include <kdebug.h> +#include <kiconloader.h> +#include <kstyle.h> +#include <kpopupmenu.h> +#include <kapplication.h> + +#define BRANCHBOX_SIZE 9 + +namespace KoProperty { +class EditorItemPrivate +{ + public: + EditorItemPrivate() + : property(0) {} + ~EditorItemPrivate() {} + + Property *property; + Editor *editor; +}; + +//! @internal +static void paintListViewExpander(QPainter* p, QWidget* w, int height, const QColorGroup& cg, bool isOpen) +{ + const int marg = (height -2 - BRANCHBOX_SIZE) / 2; + int xmarg = marg; +// if (dynamic_cast<EditorGroupItem*>(item)) +// xmarg = xmarg * 10 / 14 -1; +#if 0 +//! @todo disabled: kstyles do not paint background yet... reenable in the future... + KStyle* kstyle = dynamic_cast<KStyle*>(widget->style()); + if (kstyle) { + kstyle->drawKStylePrimitive( + KStyle::KPE_ListViewExpander, p, w, QRect( xmarg, marg, BRANCHBOX_SIZE, BRANCHBOX_SIZE ), + cg, isOpen ? 0 : QStyle::Style_On, + QStyleOption::Default); + } + else { +#endif + Q_UNUSED(w); + //draw by hand + p->setPen( KPROPEDITOR_ITEM_BORDER_COLOR ); + p->drawRect(xmarg, marg, BRANCHBOX_SIZE, BRANCHBOX_SIZE); + p->fillRect(xmarg+1, marg + 1, BRANCHBOX_SIZE-2, BRANCHBOX_SIZE-2, +// item->listView()->paletteBackgroundColor()); + cg.base()); +// p->setPen( item->listView()->paletteForegroundColor() ); + p->setPen( cg.foreground() ); + p->drawLine(xmarg+2, marg+BRANCHBOX_SIZE/2, xmarg+BRANCHBOX_SIZE-3, marg+BRANCHBOX_SIZE/2); + if(!isOpen) { + p->drawLine(xmarg+BRANCHBOX_SIZE/2, marg+2, + xmarg+BRANCHBOX_SIZE/2, marg+BRANCHBOX_SIZE-3); + } +// } +} + +//! @internal +//! Based on KPopupTitle, see kpopupmenu.cpp +class GroupWidgetBase : public QWidget +{ + public: + GroupWidgetBase(QWidget* parent) + : QWidget(parent) + , m_isOpen(true) + , m_mouseDown(false) + { + setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed, 0, 1)); + } + + void setText( const QString &text ) + { + m_titleStr = text; + } + + void setIcon( const QPixmap &pix ) + { + m_miniicon = pix; + } + + virtual bool isOpen() const + { + return m_isOpen; + } + + virtual void setOpen(bool set) + { + m_isOpen = set; + } + + virtual QSize sizeHint () const + { + QSize s( QWidget::sizeHint() ); + s.setHeight(fontMetrics().height()*2); + return s; + } + + protected: + virtual void paintEvent(QPaintEvent *) { + QRect r(rect()); + QPainter p(this); + QStyle::StyleFlags flags = m_mouseDown ? QStyle::Style_Down : QStyle::Style_Default; + kapp->style().drawPrimitive(QStyle::PE_HeaderSection, &p, r, palette().active(), flags); + + paintListViewExpander(&p, this, r.height()+2, palette().active(), isOpen()); + if (!m_miniicon.isNull()) { + p.drawPixmap(24, (r.height()-m_miniicon.height())/2, m_miniicon); + } + + if (!m_titleStr.isNull()) + { + int indent = 16 + (m_miniicon.isNull() ? 0 : (m_miniicon.width()+4)); + p.setPen(palette().active().text()); + QFont f = p.font(); + f.setBold(true); + p.setFont(f); + p.drawText(indent+8, 0, width()-(indent+8), + height(), AlignLeft | AlignVCenter | SingleLine, + m_titleStr); + } +// p.setPen(palette().active().mid()); +// p.drawLine(0, 0, r.right(), 0); + } + + virtual bool event( QEvent * e ) { + if (e->type()==QEvent::MouseButtonPress || e->type()==QEvent::MouseButtonRelease) { + QMouseEvent* me = static_cast<QMouseEvent*>(e); + if (me->button() == Qt::LeftButton) { + m_mouseDown = e->type()==QEvent::MouseButtonPress; + update(); + } + } + return QWidget::event(e); + } + + protected: + QString m_titleStr; + QPixmap m_miniicon; + bool m_isOpen : 1; + bool m_mouseDown : 1; +}; + +class GroupWidget : public GroupWidgetBase +{ + public: + GroupWidget(EditorGroupItem *parentItem) + : GroupWidgetBase(parentItem->listView()->viewport()) + , m_parentItem(parentItem) + { + } + + virtual bool isOpen() const + { + return m_parentItem->isOpen(); + } + + protected: + EditorGroupItem *m_parentItem; +}; + +class GroupContainer::Private +{ + public: + Private() {} + QVBoxLayout* lyr; + GroupWidgetBase *groupWidget; + QGuardedPtr<QWidget> contents; +}; + +}//namespace + +using namespace KoProperty; + +GroupContainer::GroupContainer(const QString& title, QWidget* parent) +: QWidget(parent) +, d(new Private()) +{ + setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed, 0, 1)); + d->lyr = new QVBoxLayout(this); + d->groupWidget = new GroupWidgetBase(this); + d->groupWidget->setText( title ); + d->lyr->addWidget(d->groupWidget); + d->lyr->addSpacing(4); +} + +GroupContainer::~GroupContainer() +{ + delete d; +} + +void GroupContainer::setContents( QWidget* contents ) +{ + if (d->contents) { + d->contents->hide(); + d->lyr->remove(d->contents); + delete d->contents; + } + d->contents = contents; + if (d->contents) { + d->lyr->addWidget(d->contents); + d->contents->show(); + } + update(); +} + +bool GroupContainer::event( QEvent * e ) { + if (e->type()==QEvent::MouseButtonPress) { + QMouseEvent* me = static_cast<QMouseEvent*>(e); + if (me->button() == Qt::LeftButton && d->contents && d->groupWidget->rect().contains(me->pos())) { + d->groupWidget->setOpen(!d->groupWidget->isOpen()); + if (d->groupWidget->isOpen()) + d->contents->show(); + else + d->contents->hide(); + d->lyr->invalidate(); + update(); + } + } + return QWidget::event(e); +} + +////////////////////////////////////////////////////// + +EditorItem::EditorItem(Editor *editor, EditorItem *parent, Property *property, QListViewItem *after) + : KListViewItem(parent, after, + property->captionForDisplaying().isEmpty() ? property->name() : property->captionForDisplaying()) +{ + d = new EditorItemPrivate(); + d->property = property; + d->editor = editor; + + setMultiLinesEnabled(true); + //setHeight(static_cast<Editor*>(listView())->baseRowHeight()*3); +/* + if (property && !property->caption().isEmpty()) { + QSimpleRichText srt(property->caption(), font()); + srt.setWidth(columnWidth(0)-KPROPEDITOR_ITEM_MARGIN*2-20+1); + int oldHeight = it.current()->height(); + int textHeight = srt.height()+KPROPEDITOR_ITEM_MARGIN; + int textLines = textHeight / d->baseRowHeight + (((textHeight % d->baseRowHeight) > 0) ? 1 : 0); + kdDebug() << " textLines: " << textLines << endl; + if (textLines != newNumLines) { + dynamic_cast<EditorItem*>(it.current())->setHeight(newNumLines * d->baseRowHeight); + } + kdDebug() << it.current()->text(0) << ": " << oldHeight << " -> " << newHeight << endl; + } +*/ +} + +EditorItem::EditorItem(KListView *parent) + : KListViewItem(parent) +{ + d = new EditorItemPrivate(); + d->property = 0; + d->editor = 0; + setMultiLinesEnabled(true); +} + +EditorItem::EditorItem(EditorItem *parent, const QString &text) + : KListViewItem(parent, text) +{ + d = new EditorItemPrivate(); + d->property = 0; + d->editor = 0; + setMultiLinesEnabled(true); +} + +EditorItem::EditorItem(EditorItem *parent, EditorItem *after, const QString &text) + : KListViewItem(parent, after, text) +{ + d = new EditorItemPrivate(); + d->property = 0; + d->editor = 0; + setMultiLinesEnabled(true); +} + +EditorItem::~EditorItem() +{ + delete d; +} + +Property* +EditorItem::property() +{ + return d->property; +} + +void +EditorItem::paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int align) +{ + //int margin = static_cast<Editor*>(listView())->itemMargin(); + if(!d->property) + return; + + if(column == 0) + { + QFont font = listView()->font(); + if(d->property->isModified()) + font.setBold(true); + p->setFont(font); + p->setBrush(cg.highlight()); + p->setPen(cg.highlightedText()); + KListViewItem::paintCell(p, cg, column, width, align); + p->fillRect(parent() ? 0 : 50, 0, width, height()-1, + QBrush(isSelected() ? cg.highlight() : backgroundColor())); + p->setPen(isSelected() ? cg.highlightedText() : cg.text()); + int delta = -20+KPROPEDITOR_ITEM_MARGIN; + if ((firstChild() && dynamic_cast<EditorGroupItem*>(parent()))) { + delta = -KPROPEDITOR_ITEM_MARGIN-1; + } + if (dynamic_cast<EditorDummyItem*>(parent())) { + delta = KPROPEDITOR_ITEM_MARGIN*2; + } + else if (parent() && dynamic_cast<EditorDummyItem*>(parent()->parent())) { + if (dynamic_cast<EditorGroupItem*>(parent())) + delta += KPROPEDITOR_ITEM_MARGIN*2; + else + delta += KPROPEDITOR_ITEM_MARGIN*5; + } + p->drawText( + QRect(delta,2, width+listView()->columnWidth(1)-KPROPEDITOR_ITEM_MARGIN*2, height()), + Qt::AlignLeft | Qt::AlignTop /*| Qt::SingleLine*/, text(0)); + + p->setPen( KPROPEDITOR_ITEM_BORDER_COLOR ); + p->drawLine(width-1, 0, width-1, height()-1); + p->drawLine(0, -1, width-1, -1); + + p->setPen( KPROPEDITOR_ITEM_BORDER_COLOR ); //! \todo custom color? + if (dynamic_cast<EditorDummyItem*>(parent())) + p->drawLine(0, 0, 0, height()-1 ); + } + else if(column == 1) + { + QColorGroup icg(cg); + icg.setColor(QColorGroup::Background, backgroundColor()); + p->setBackgroundColor(backgroundColor()); + Widget *widget = d->editor->createWidgetForProperty(d->property, false /*don't change Widget::property() */); + if(widget) { + QRect r(0, 0, d->editor->header()->sectionSize(1), height() - (widget->hasBorders() ? 0 : 1)); + p->setClipRect(r, QPainter::CoordPainter); + p->setClipping(true); + widget->drawViewer(p, icg, r, d->property->value()); + p->setClipping(false); + } + } + p->setPen( KPROPEDITOR_ITEM_BORDER_COLOR ); //! \todo custom color? + p->drawLine(0, height()-1, width, height()-1 ); +} + +void +EditorItem::paintBranches(QPainter *p, const QColorGroup &cg, int w, int y, int h) +{ + p->eraseRect(0,0,w,h); + KListViewItem *item = static_cast<KListViewItem*>(firstChild()); + if(!item) + return; + + QColor backgroundColor; + p->save(); + p->translate(0,y); + QFont font = listView()->font(); + while(item) + { + if(item->isSelected()) + backgroundColor = cg.highlight(); + else { + if (dynamic_cast<EditorGroupItem*>(item)) + backgroundColor = cg.base(); + else + backgroundColor = item->backgroundColor(); + } +// p->fillRect(-50,0,50, item->height(), QBrush(backgroundColor)); + p->save(); + p->setPen( KPROPEDITOR_ITEM_BORDER_COLOR ); + int delta = 0; + int fillWidth = w; + int x = 0; + if (dynamic_cast<EditorGroupItem*>(item->parent())) { + delta = 0;//-19; + fillWidth += 19; + } + else { + if (dynamic_cast<EditorGroupItem*>(item) || /*for flat mode*/ dynamic_cast<EditorDummyItem*>(item->parent())) + x = 19; + else + x = -19; + fillWidth += 19; + } + if (dynamic_cast<EditorDummyItem*>(item->parent())) { + x = 19; + } + else if (item->parent() && dynamic_cast<EditorDummyItem*>(item->parent()->parent())) { + x = 0; + } + p->fillRect(x+1, 0, fillWidth-1, item->height()-1, QBrush(backgroundColor)); + p->drawLine(x, item->height()-1, w, item->height()-1 ); + if (!dynamic_cast<EditorGroupItem*>(item)) + p->drawLine(x, 0, x, item->height()-1 ); + p->restore(); + +// for (int i=0; i<10000000; i++) +// ; +// if(item->isSelected()) { +// p->fillRect(parent() ? 0 : 50, 0, w, item->height()-1, QBrush(cg.highlight())); +// p->fillRect(-50,0,50, item->height(), QBrush(cg.highlight())); +// } + + //sorry, but we need to draw text here again + font.setBold( dynamic_cast<EditorGroupItem*>(item) + || (static_cast<EditorItem*>(item)->property() && static_cast<EditorItem*>(item)->property()->isModified()) ); + p->setFont(font); + p->setPen(item->isSelected() ? cg.highlightedText() : cg.text()); + if (item->firstChild() && dynamic_cast<EditorGroupItem*>(item->parent())) { + delta = 19-KPROPEDITOR_ITEM_MARGIN-1; + } + else if (dynamic_cast<EditorDummyItem*>(item->parent())) { + delta = 19; + } + if (item->parent() && dynamic_cast<EditorDummyItem*>(item->parent()->parent())) { + if (dynamic_cast<EditorGroupItem*>(item->parent())) + delta += KPROPEDITOR_ITEM_MARGIN*2; + else + delta += KPROPEDITOR_ITEM_MARGIN*5; + } + + if (!dynamic_cast<EditorDummyItem*>(item->parent())) + p->drawText(QRect(delta+1,0, w+listView()->columnWidth(1), item->height()), + Qt::AlignLeft | Qt::AlignVCenter /*| Qt::SingleLine*/, item->text(0)); + + if(item->firstChild()) { + paintListViewExpander(p, listView(), item->height(), + cg, item->isOpen()); + } + + // draw icon (if there is one) + EditorItem *editorItem = dynamic_cast<EditorItem*>(item); + if (editorItem && editorItem->property() && !editorItem->property()->icon().isEmpty()) { + //int margin = listView()->itemMargin(); + QPixmap pix = SmallIcon(editorItem->property()->icon()); + if (!pix.isNull()) + p->drawPixmap(-19+(19-pix.width())/2, (item->height() - pix.height()) / 2, pix); + } + + p->translate(0, item->totalHeight()); + item = (KListViewItem*)item->nextSibling(); + } + p->restore(); +} + +void +EditorItem::paintFocus(QPainter *, const QColorGroup &, const QRect & ) +{ +} + +int +EditorItem::compare( QListViewItem *i, int col, bool ascending ) const +{ + if (!ascending) + return -QListViewItem::key( col, ascending ).localeAwareCompare( i->key( col, ascending ) ); + + if (d->property) { +// kopropertydbg << d->property->name() << " " << d->property->sortingKey() << " | " +// << static_cast<EditorItem*>(i)->property()->name() << " " +// << static_cast<EditorItem*>(i)->property()->sortingKey() << endl; + return d->property->sortingKey() + - ((dynamic_cast<EditorItem*>(i) && dynamic_cast<EditorItem*>(i)->property()) + ? dynamic_cast<EditorItem*>(i)->property()->sortingKey() : 0); + } + + return 0; +// return d->order - static_cast<EditorItem*>(i)->d->order; +} + +void +EditorItem::setHeight( int height ) +{ + KListViewItem::setHeight(height); +} + +////////////////////////////////////////////////////// + +EditorGroupItem::EditorGroupItem(EditorItem *parent, EditorItem *after, const QString &text, const QString &icon, int sortOrder) + : EditorItem(parent, after, text) + , m_label(0) + , m_sortOrder(sortOrder) +{ + init(icon); +} + +EditorGroupItem::EditorGroupItem(EditorItem *parent, const QString &text, const QString &icon, int sortOrder) + : EditorItem(parent, text) + , m_label(0) + , m_sortOrder(sortOrder) +{ + init(icon); +} + +EditorGroupItem::~EditorGroupItem() +{ + delete m_label; +} + +QWidget* EditorGroupItem::label() const +{ + return m_label; +} + +void EditorGroupItem::init(const QString &icon) +{ + setOpen(true); + setSelectable(false); + m_label = new GroupWidget(this); + m_label->setText(text(0)); //todo: icon? + if (!icon.isEmpty()) + m_label->setIcon( SmallIcon(icon) ); + m_label->show(); +} + +void +EditorGroupItem::paintCell(QPainter *p, const QColorGroup & cg, int column, int width, int /*align*/) +{ + Q_UNUSED(p); + Q_UNUSED(cg); + Q_UNUSED(column); + Q_UNUSED(width); + //no need to draw anything since there's a label on top of it +// p->fillRect(0, 0, width, height(), cg.base()); + + //if(column == 1) + // return; + /*p->setPen( KPROPEDITOR_ITEM_BORDER_COLOR ); //! \todo custom color? + + p->setClipRect(listView()->itemRect(this)); + if(column == 1) + p->translate(-listView()->columnWidth(0) + 20, 0); + int totalWidth = listView()->columnWidth(0) + listView()->columnWidth(1) - 20; + p->eraseRect(QRect(0,0, totalWidth,height()-1)); + p->drawLine(0, height()-1, totalWidth-1, height()-1); + + QFont font = listView()->font(); + font.setBold(true); + p->setFont(font); + p->setBrush(cg.highlight()); + //p->setPen(cg.highlightedText()); + KListViewItem::paintCell(p, cg, column, width, align); + p->setPen(cg.text()); + p->drawText(QRect(0,0, totalWidth, height()), + Qt::AlignLeft | Qt::AlignVCenter | Qt::SingleLine, text(0));*/ +} + +void +EditorGroupItem::setup() +{ + KListViewItem::setup(); + setHeight( height()+4 ); +} + +int +EditorGroupItem::compare( QListViewItem *i, int col, bool ascending ) const +{ + Q_UNUSED(col); + Q_UNUSED(ascending); + if (dynamic_cast<EditorGroupItem*>(i)) { + return m_sortOrder + - dynamic_cast<EditorGroupItem*>(i)->m_sortOrder; + } + return 0; +} + +//////////////////////////////////////////////////////// + +EditorDummyItem::EditorDummyItem(KListView *listview) + : EditorItem(listview) +{ + setSelectable(false); + setOpen(true); +} + +EditorDummyItem::~EditorDummyItem() +{} + +void +EditorDummyItem::setup() +{ + setHeight(0); +} |