summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/Makefile.am43
-rw-r--r--src/gui/boolfieldwidget.cpp61
-rw-r--r--src/gui/boolfieldwidget.h51
-rw-r--r--src/gui/choicefieldwidget.cpp69
-rw-r--r--src/gui/choicefieldwidget.h51
-rw-r--r--src/gui/collectiontypecombo.cpp53
-rw-r--r--src/gui/collectiontypecombo.h33
-rw-r--r--src/gui/combobox.cpp71
-rw-r--r--src/gui/combobox.h52
-rw-r--r--src/gui/counteditem.cpp113
-rw-r--r--src/gui/counteditem.h49
-rw-r--r--src/gui/datefieldwidget.cpp52
-rw-r--r--src/gui/datefieldwidget.h51
-rw-r--r--src/gui/datewidget.cpp279
-rw-r--r--src/gui/datewidget.h74
-rw-r--r--src/gui/fieldwidget.cpp201
-rw-r--r--src/gui/fieldwidget.h91
-rw-r--r--src/gui/imagefieldwidget.cpp54
-rw-r--r--src/gui/imagefieldwidget.h51
-rw-r--r--src/gui/imagewidget.cpp257
-rw-r--r--src/gui/imagewidget.h78
-rw-r--r--src/gui/kwidgetlister.cpp178
-rw-r--r--src/gui/kwidgetlister.h150
-rw-r--r--src/gui/lineedit.cpp150
-rw-r--r--src/gui/lineedit.h72
-rw-r--r--src/gui/linefieldwidget.cpp90
-rw-r--r--src/gui/linefieldwidget.h51
-rw-r--r--src/gui/listboxtext.cpp74
-rw-r--r--src/gui/listboxtext.h50
-rw-r--r--src/gui/listview.cpp347
-rw-r--r--src/gui/listview.h180
-rw-r--r--src/gui/numberfieldwidget.cpp143
-rw-r--r--src/gui/numberfieldwidget.h57
-rw-r--r--src/gui/overlaywidget.cpp104
-rw-r--r--src/gui/overlaywidget.h54
-rw-r--r--src/gui/parafieldwidget.cpp63
-rw-r--r--src/gui/parafieldwidget.h50
-rw-r--r--src/gui/previewdialog.cpp56
-rw-r--r--src/gui/previewdialog.h47
-rw-r--r--src/gui/progress.cpp33
-rw-r--r--src/gui/progress.h39
-rw-r--r--src/gui/ratingfieldwidget.cpp59
-rw-r--r--src/gui/ratingfieldwidget.h50
-rw-r--r--src/gui/ratingwidget.cpp170
-rw-r--r--src/gui/ratingwidget.h75
-rw-r--r--src/gui/richtextlabel.cpp47
-rw-r--r--src/gui/richtextlabel.h46
-rw-r--r--src/gui/stringmapdialog.cpp125
-rw-r--r--src/gui/stringmapdialog.h71
-rw-r--r--src/gui/tabcontrol.cpp77
-rw-r--r--src/gui/tabcontrol.h48
-rw-r--r--src/gui/tablefieldwidget.cpp330
-rw-r--r--src/gui/tablefieldwidget.h74
-rw-r--r--src/gui/urlfieldwidget.cpp98
-rw-r--r--src/gui/urlfieldwidget.h66
55 files changed, 5158 insertions, 0 deletions
diff --git a/src/gui/Makefile.am b/src/gui/Makefile.am
new file mode 100644
index 0000000..cb6f5e8
--- /dev/null
+++ b/src/gui/Makefile.am
@@ -0,0 +1,43 @@
+AM_CPPFLAGS = $(all_includes)
+
+noinst_LIBRARIES = libgui.a
+libgui_a_SOURCES = combobox.cpp counteditem.cpp datewidget.cpp \
+ tabcontrol.cpp kwidgetlister.cpp stringmapdialog.cpp listview.cpp richtextlabel.cpp \
+ lineedit.cpp boolfieldwidget.cpp choicefieldwidget.cpp linefieldwidget.cpp \
+ numberfieldwidget.cpp parafieldwidget.cpp urlfieldwidget.cpp tablefieldwidget.cpp \
+ imagefieldwidget.cpp datefieldwidget.cpp imagewidget.cpp fieldwidget.cpp ratingwidget.cpp \
+ ratingfieldwidget.cpp overlaywidget.cpp progress.cpp listboxtext.cpp collectiontypecombo.cpp \
+ previewdialog.cpp
+
+libgui_a_METASOURCES = AUTO
+KDE_OPTIONS = noautodist
+EXTRA_DIST = combobox.h combobox.cpp \
+counteditem.h counteditem.cpp \
+datewidget.h datewidget.cpp \
+kwidgetlister.h kwidgetlister.cpp \
+listview.h listview.cpp \
+richtextlabel.h richtextlabel.cpp \
+stringmapdialog.h stringmapdialog.cpp \
+tabcontrol.h tabcontrol.cpp \
+lineedit.h lineedit.cpp \
+boolfieldwidget.h boolfieldwidget.cpp \
+choicefieldwidget.h choicefieldwidget.cpp \
+datefieldwidget.h datefieldwidget.cpp \
+imagefieldwidget.h imagefieldwidget.cpp \
+linefieldwidget.h linefieldwidget.cpp \
+numberfieldwidget.h numberfieldwidget.cpp \
+parafieldwidget.h parafieldwidget.cpp \
+tablefieldwidget.h tablefieldwidget.cpp \
+urlfieldwidget.h urlfieldwidget.cpp \
+ratingwidget.h ratingwidget.cpp \
+imagewidget.h imagewidget.cpp \
+fieldwidget.h fieldwidget.cpp \
+ratingfieldwidget.h ratingfieldwidget.cpp \
+overlaywidget.h overlaywidget.cpp \
+progress.h progress.cpp \
+listboxtext.h listboxtext.cpp \
+collectiontypecombo.h collectiontypecombo.cpp \
+previewdialog.h previewdialog.cpp
+
+CLEANFILES = *~
+
diff --git a/src/gui/boolfieldwidget.cpp b/src/gui/boolfieldwidget.cpp
new file mode 100644
index 0000000..5a8e88b
--- /dev/null
+++ b/src/gui/boolfieldwidget.cpp
@@ -0,0 +1,61 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "boolfieldwidget.h"
+#include "../field.h"
+#include "../latin1literal.h"
+
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qlayout.h>
+
+using Tellico::GUI::BoolFieldWidget;
+
+BoolFieldWidget::BoolFieldWidget(Data::FieldPtr field_, QWidget* parent_, const char* name_/*=0*/)
+ : FieldWidget(field_, parent_, name_) {
+
+ m_checkBox = new QCheckBox(this);
+ connect(m_checkBox, SIGNAL(clicked()), SIGNAL(modified()));
+ registerWidget();
+}
+
+QString BoolFieldWidget::text() const {
+ if(m_checkBox->isChecked()) {
+ return QString::fromLatin1("true");
+ }
+
+ return QString();
+}
+
+void BoolFieldWidget::setText(const QString& text_) {
+ blockSignals(true);
+
+ m_checkBox->blockSignals(true);
+ // be lax, don't have to check for "1" or "true"
+ // just check for a non-empty string
+ m_checkBox->setChecked(!text_.isEmpty());
+ m_checkBox->blockSignals(false);
+
+ blockSignals(false);
+}
+
+void BoolFieldWidget::clear() {
+ m_checkBox->setChecked(false);
+ editMultiple(false);
+}
+
+QWidget* BoolFieldWidget::widget() {
+ return m_checkBox;
+}
+
+#include "boolfieldwidget.moc"
diff --git a/src/gui/boolfieldwidget.h b/src/gui/boolfieldwidget.h
new file mode 100644
index 0000000..81af5a6
--- /dev/null
+++ b/src/gui/boolfieldwidget.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef BOOLFIELDWIDGET_H
+#define BOOLFIELDWIDGET_H
+
+#include "fieldwidget.h"
+#include "../datavectors.h"
+
+class QCheckBox;
+class QString;
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * @author Robby Stephenson
+ */
+class BoolFieldWidget : public FieldWidget {
+Q_OBJECT
+
+public:
+ BoolFieldWidget(Data::FieldPtr field, QWidget* parent, const char* name=0);
+ virtual ~BoolFieldWidget() {}
+
+ virtual QString text() const;
+ virtual void setText(const QString& text);
+
+public slots:
+ virtual void clear();
+
+protected:
+ virtual QWidget* widget();
+
+private:
+ QCheckBox* m_checkBox;
+};
+
+ } // end GUI namespace
+} // end namespace
+#endif
diff --git a/src/gui/choicefieldwidget.cpp b/src/gui/choicefieldwidget.cpp
new file mode 100644
index 0000000..e9c6870
--- /dev/null
+++ b/src/gui/choicefieldwidget.cpp
@@ -0,0 +1,69 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "choicefieldwidget.h"
+#include "../field.h"
+
+#include <kcombobox.h>
+
+#include <qlabel.h>
+#include <qlayout.h>
+
+using Tellico::GUI::ChoiceFieldWidget;
+
+ChoiceFieldWidget::ChoiceFieldWidget(Data::FieldPtr field_, QWidget* parent_, const char* name_/*=0*/)
+ : FieldWidget(field_, parent_, name_), m_comboBox(0) {
+
+ m_comboBox = new KComboBox(this);
+ connect(m_comboBox, SIGNAL(activated(int)), SIGNAL(modified()));
+ // always have empty choice
+ m_comboBox->insertItem(QString::null);
+ m_comboBox->insertStringList(field_->allowed());
+ m_comboBox->setMinimumWidth(5*fontMetrics().maxWidth());
+
+ registerWidget();
+}
+
+QString ChoiceFieldWidget::text() const {
+ return m_comboBox->currentText();
+}
+
+void ChoiceFieldWidget::setText(const QString& text_) {
+ blockSignals(true);
+
+ m_comboBox->blockSignals(true);
+ m_comboBox->setCurrentItem(text_);
+ m_comboBox->blockSignals(false);
+
+ blockSignals(false);
+}
+
+void ChoiceFieldWidget::clear() {
+ m_comboBox->setCurrentItem(0); // first item is empty
+ editMultiple(false);
+}
+
+void ChoiceFieldWidget::updateFieldHook(Data::FieldPtr, Data::FieldPtr newField_) {
+ QString value = text();
+ m_comboBox->clear();
+ // always have empty choice
+ m_comboBox->insertItem(QString::null);
+ m_comboBox->insertStringList(newField_->allowed());
+ m_comboBox->setCurrentText(value);
+}
+
+QWidget* ChoiceFieldWidget::widget() {
+ return m_comboBox;
+}
+
+#include "choicefieldwidget.moc"
diff --git a/src/gui/choicefieldwidget.h b/src/gui/choicefieldwidget.h
new file mode 100644
index 0000000..a2c40f5
--- /dev/null
+++ b/src/gui/choicefieldwidget.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef CHOICEFIELDWIDGET_H
+#define CHOICEFIELDWIDGET_H
+
+#include "fieldwidget.h"
+#include "../datavectors.h"
+
+class KComboBox;
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * @author Robby Stephenson
+ */
+class ChoiceFieldWidget : public FieldWidget {
+Q_OBJECT
+
+public:
+ ChoiceFieldWidget(Data::FieldPtr field, QWidget* parent, const char* name=0);
+ virtual ~ChoiceFieldWidget() {}
+
+ virtual QString text() const;
+ virtual void setText(const QString& text);
+
+public slots:
+ virtual void clear();
+
+protected:
+ virtual QWidget* widget();
+ virtual void updateFieldHook(Data::FieldPtr oldField, Data::FieldPtr newField);
+
+private:
+ KComboBox* m_comboBox;
+};
+
+ } // end GUI namespace
+} // end namespace
+#endif
diff --git a/src/gui/collectiontypecombo.cpp b/src/gui/collectiontypecombo.cpp
new file mode 100644
index 0000000..66749a3
--- /dev/null
+++ b/src/gui/collectiontypecombo.cpp
@@ -0,0 +1,53 @@
+/***************************************************************************
+ copyright : (C) 2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "collectiontypecombo.h"
+#include "../collection.h"
+#include "../collectionfactory.h"
+
+using Tellico::GUI::CollectionTypeCombo;
+
+CollectionTypeCombo::CollectionTypeCombo(QWidget* parent_) : ComboBox(parent_) {
+ reset();
+}
+
+void CollectionTypeCombo::reset() {
+ clear();
+ // I want to sort the collection names
+ const CollectionNameMap nameMap = CollectionFactory::nameMap();
+ QMap<QString, int> rNameMap;
+ for(CollectionNameMap::ConstIterator it = nameMap.begin(); it != nameMap.end(); ++it) {
+ rNameMap.insert(it.data(), it.key());
+ }
+ const QValueList<int> collTypes = rNameMap.values();
+ const QStringList collNames = rNameMap.keys();
+ int custom = -1;
+ const int total = collTypes.count();
+ // when i equals the size, then go back and do custom
+ for(int i = 0; i <= total; ++i) {
+ // put custom last
+ if(custom > -1 && count() >= total) {
+ break; // already done it!
+ } else if(i == total) {
+ i = custom;
+ } else if(collTypes[i] == Data::Collection::Base) {
+ custom = i;
+ continue;
+ }
+ insertItem(collNames[i], collTypes[i]);
+ }
+}
+
+void CollectionTypeCombo::setCurrentType(int type_) {
+ setCurrentData(type_);
+}
diff --git a/src/gui/collectiontypecombo.h b/src/gui/collectiontypecombo.h
new file mode 100644
index 0000000..8d3ef80
--- /dev/null
+++ b/src/gui/collectiontypecombo.h
@@ -0,0 +1,33 @@
+/***************************************************************************
+ copyright : (C) 2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TELLICO_GUI_COLLECTIONTYPECOMBO_H
+#define TELLICO_GUI_COLLECTIONTYPECOMBO_H
+
+#include "combobox.h"
+
+namespace Tellico {
+
+namespace GUI {
+
+class CollectionTypeCombo : public ComboBox {
+public:
+ CollectionTypeCombo(QWidget* parent);
+ void reset();
+ void setCurrentType(int type);
+ int currentType() const { return currentData().toInt(); }
+};
+
+ }
+}
+#endif
diff --git a/src/gui/combobox.cpp b/src/gui/combobox.cpp
new file mode 100644
index 0000000..1aff29b
--- /dev/null
+++ b/src/gui/combobox.cpp
@@ -0,0 +1,71 @@
+/***************************************************************************
+ copyright : (C) 2001-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "combobox.h"
+
+#include <kdebug.h>
+
+using Tellico::GUI::ComboBox;
+
+ComboBox::ComboBox(QWidget* parent_) : KComboBox(parent_) {
+ setEditable(false);
+}
+
+void ComboBox::clear() {
+ KComboBox::clear();
+ m_data.clear();
+}
+
+void ComboBox::insertItem(const QString& s_, const QVariant& t_, int idx_/* =-1 */) {
+ KComboBox::insertItem(s_, idx_);
+ if(idx_ < 0) {
+ m_data.push_back(t_);
+ } else {
+ while(idx_ > static_cast<int>(m_data.count())) {
+ m_data.push_back(QVariant());
+ }
+ m_data.insert(m_data.at(idx_), t_);
+ }
+}
+
+void ComboBox::insertItems(const QStringList& s_, const QValueList<QVariant>& t_, int idx_ /*=-1*/) {
+ if(s_.count() != t_.count()) {
+ kdWarning() << "ComboBox::insertItems() - must have equal number of items in list!" << endl;
+ return;
+ }
+
+ for(uint i = 0; i < s_.count(); ++i) {
+ insertItem(s_[i], t_[i], idx_+i);
+ }
+}
+
+const QVariant& ComboBox::currentData() const {
+ return data(currentItem());
+}
+
+const QVariant& ComboBox::data(uint idx_) const {
+ if(idx_ >= m_data.count()) {
+ static QVariant t; // inescapable
+ return t;
+ }
+ return m_data[idx_];
+}
+
+void ComboBox::setCurrentData(const QVariant& data_) {
+ for(uint i = 0; i < m_data.count(); ++i) {
+ if(m_data[i] == data_) {
+ setCurrentItem(i);
+ break;
+ }
+ }
+}
diff --git a/src/gui/combobox.h b/src/gui/combobox.h
new file mode 100644
index 0000000..d02dbb8
--- /dev/null
+++ b/src/gui/combobox.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ copyright : (C) 2001-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TELLICO_GUI_COMBOBOX_H
+#define TELLICO_GUI_COMBOBOX_H
+
+#include <kcombobox.h>
+
+#include <qvariant.h>
+#include <qvaluelist.h>
+
+class QString;
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * A combobox for mapping a QVariant to each item.
+ *
+ * @author Robby Stephenson
+ */
+class ComboBox : public KComboBox {
+public:
+ ComboBox(QWidget* parent_);
+
+ void clear();
+ const QVariant& currentData() const;
+ const QVariant& data(uint index) const;
+ void insertItem(const QString& string, const QVariant& datum, int index = -1);
+ void insertItems(const QStringList& strings, const QValueList<QVariant>& data, int index = -1);
+
+ // set current item to match data
+ void setCurrentData(const QVariant& data);
+
+private:
+ QValueList<QVariant> m_data;
+};
+
+ } // end namespace
+} //end namespace
+
+#endif
diff --git a/src/gui/counteditem.cpp b/src/gui/counteditem.cpp
new file mode 100644
index 0000000..08b4f25
--- /dev/null
+++ b/src/gui/counteditem.cpp
@@ -0,0 +1,113 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "counteditem.h"
+#include "../tellico_utils.h"
+#include "../tellico_debug.h"
+
+#include <kglobalsettings.h>
+#include <kstringhandler.h>
+
+#include <qpainter.h>
+#include <qpixmap.h>
+
+using Tellico::GUI::CountedItem;
+
+int CountedItem::compare(QListViewItem* item_, int col_, bool asc_) const {
+ GUI::ListView* lv = listView();
+ GUI::CountedItem* item = static_cast<GUI::CountedItem*>(item_);
+ if(lv->sortStyle() == GUI::ListView::SortByCount) {
+ if(count() < item->count()) {
+ return -1;
+ } else if(count() > item->count()) {
+ return 1;
+ } else {
+ return GUI::ListViewItem::compare(item, col_, asc_);
+ }
+ }
+ // for now, only other style is by text
+ return GUI::ListViewItem::compare(item, col_, asc_);
+}
+
+void CountedItem::paintCell(QPainter* p_, const QColorGroup& cg_,
+ int column_, int width_, int align_) {
+ if(!p_) {
+ return;
+ }
+
+ // always paint the cell
+
+ // show count is only for first column
+ if(column_ != 0) {
+ ListViewItem::paintCell(p_, cg_, column_, width_, align_);
+ return;
+ }
+
+ // set a catchable text so that we can have our own implementation (see further down)
+ // but still benefit from KListView::paintCell
+ QString oldText = text(column_);
+// if(oldText.isEmpty()) {
+ if(oldText == '\t') {
+ return; // avoid endless loop!
+ }
+
+ setText(column_, QChar('\t'));
+ ListViewItem::paintCell(p_, cg_, column_, width_, align_);
+ setText(column_, oldText);
+
+ int marg = listView()->itemMargin();
+ int r = marg;
+ const QPixmap* icon = pixmap(column_);
+ if(icon) {
+ r += icon->width() + marg;
+ }
+
+ QFontMetrics fm = p_->fontMetrics();
+ QString numText = QString::fromLatin1(" (%1)").arg(count());
+ // don't call CountedListViewItem::width() because that includes the count already
+ int w = ListViewItem::width(fm, listView(), column_);
+ int countWidth = fm.width(numText);
+ if(w+marg+r+countWidth > width_) {
+ oldText = KStringHandler::rPixelSqueeze(oldText, fm, width_-marg-r-countWidth);
+ }
+ if(isSelected()) {
+ p_->setPen(cg_.highlightedText());
+ } else {
+ p_->setPen(cg_.text());
+ }
+ QRect br(0, height(), r, 0);
+ if(!oldText.isEmpty() && !oldText.startsWith(QChar('\t'))) {
+ p_->drawText(r, 0, width_-marg-r, height(), align_ | AlignVCenter, oldText, -1, &br);
+ }
+
+ if(isSelected()) {
+ p_->setPen(cg_.highlightedText());
+ } else {
+ if(!Tellico::contrastColor.isValid()) {
+ updateContrastColor(cg_);
+ }
+ p_->setPen(Tellico::contrastColor);
+ }
+ p_->drawText(br.right(), 0, width_-marg-br.right(), height(), align_ | Qt::AlignVCenter, numText);
+}
+
+int CountedItem::width(const QFontMetrics& fm_, const QListView* lv_, int column_) const {
+ int w = ListViewItem::width(fm_, lv_, column_);
+
+ // show count is only for first column
+ if(column_ == 0) {
+ QString numText = QString::fromLatin1(" (%1)").arg(count());
+ w += fm_.width(numText) + 2; // add a little pad
+ }
+ return w;
+}
diff --git a/src/gui/counteditem.h b/src/gui/counteditem.h
new file mode 100644
index 0000000..9ea0138
--- /dev/null
+++ b/src/gui/counteditem.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef COUNTEDITEM_H
+#define COUNTEDITEM_H
+
+#include "listview.h"
+
+class QPainter;
+class QColorGroup;
+class QFontMetrics;
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * @author Robby Stephenson
+ */
+class CountedItem : public GUI::ListViewItem {
+public:
+ CountedItem(ListView* parent) : ListViewItem(parent) {}
+ CountedItem(ListViewItem* parent) : ListViewItem(parent) {}
+
+ virtual int compare(QListViewItem* item, int col, bool ascending) const;
+ /**
+ * Paints the cell, adding the number count.
+ */
+ virtual void paintCell(QPainter* p, const QColorGroup& cg,
+ int column, int width, int align);
+ virtual int width(const QFontMetrics& fm, const QListView* lv, int c) const;
+
+ virtual int count() const { return childCount(); }
+ virtual int realChildCount() const { return count(); }
+};
+
+ } // end namespace
+} // end namespace
+
+#endif
diff --git a/src/gui/datefieldwidget.cpp b/src/gui/datefieldwidget.cpp
new file mode 100644
index 0000000..d0609d6
--- /dev/null
+++ b/src/gui/datefieldwidget.cpp
@@ -0,0 +1,52 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "datefieldwidget.h"
+#include "datewidget.h"
+#include "../field.h"
+
+using Tellico::GUI::DateFieldWidget;
+
+DateFieldWidget::DateFieldWidget(Data::FieldPtr field_, QWidget* parent_, const char* name_/*=0*/)
+ : FieldWidget(field_, parent_, name_) {
+
+ m_widget = new DateWidget(this);
+ connect(m_widget, SIGNAL(signalModified()), SIGNAL(modified()));
+
+ registerWidget();
+}
+
+QString DateFieldWidget::text() const {
+ return m_widget->text();
+}
+
+void DateFieldWidget::setText(const QString& text_) {
+ blockSignals(true);
+ m_widget->blockSignals(true);
+
+ m_widget->setDate(text_);
+
+ m_widget->blockSignals(false);
+ blockSignals(false);
+}
+
+void DateFieldWidget::clear() {
+ m_widget->clear();
+ editMultiple(false);
+}
+
+QWidget* DateFieldWidget::widget() {
+ return m_widget;
+}
+
+#include "datefieldwidget.moc"
diff --git a/src/gui/datefieldwidget.h b/src/gui/datefieldwidget.h
new file mode 100644
index 0000000..e3c2d55
--- /dev/null
+++ b/src/gui/datefieldwidget.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef DATEFIELDWIDGET_H
+#define DATEFIELDWIDGET_H
+
+#include "fieldwidget.h"
+#include "../datavectors.h"
+
+class QString;
+
+namespace Tellico {
+ namespace GUI {
+ class DateWidget;
+
+/**
+ * @author Robby Stephenson
+ */
+class DateFieldWidget : public FieldWidget {
+Q_OBJECT
+
+public:
+ DateFieldWidget(Data::FieldPtr field, QWidget* parent, const char* name=0);
+ virtual ~DateFieldWidget() {}
+
+ virtual QString text() const;
+ virtual void setText(const QString& text);
+
+public slots:
+ virtual void clear();
+
+protected:
+ virtual QWidget* widget();
+
+private:
+ DateWidget* m_widget;
+};
+
+ } // end GUI namespace
+} // end namespace
+#endif
diff --git a/src/gui/datewidget.cpp b/src/gui/datewidget.cpp
new file mode 100644
index 0000000..42e2d4c
--- /dev/null
+++ b/src/gui/datewidget.cpp
@@ -0,0 +1,279 @@
+/***************************************************************************
+ copyright : (C) 2003-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+// this class borrows heavily from kdateedit.h in the kdepim module
+// which is Copyright (c) 2002 Cornelius Schumacher <schumacher@kde.org>
+// and published under the LGPL
+
+#include "datewidget.h"
+
+#include <kdebug.h>
+#include <kcombobox.h>
+#include <kpushbutton.h>
+#include <kdatepicker.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kglobalsettings.h>
+#include <kcalendarsystem.h>
+
+#include <qvbox.h>
+#include <qlayout.h>
+
+using Tellico::GUI::SpinBox;
+using Tellico::GUI::DateWidget;
+
+SpinBox::SpinBox(int min, int max, QWidget *parent) : QSpinBox(min, max, 1, parent)
+{
+ editor()->setAlignment(AlignRight);
+ // I want to be able to omit the day
+ // an empty string just removes the special value, so set white space
+ setSpecialValueText(QChar(' '));
+}
+
+DateWidget::DateWidget(QWidget* parent_, const char* name_) : QWidget(parent_, name_) {
+ QHBoxLayout* l = new QHBoxLayout(this, 0, 4);
+
+ KLocale* locale = KGlobal::locale();
+
+ // 0 allows empty value
+ m_daySpin = new SpinBox(0, 31, this);
+ l->addWidget(m_daySpin, 1);
+
+ m_monthCombo = new KComboBox(false, this);
+ l->addWidget(m_monthCombo, 1);
+ // allow empty item
+ m_monthCombo->insertItem(QString::null);
+ QDate d;
+ for(int i = 1; ; ++i) {
+ QString str = locale->calendar()->monthName(i, locale->calendar()->year(d));
+ if(str.isNull()) {
+ break;
+ }
+ m_monthCombo->insertItem(str);
+ }
+
+ m_yearSpin = new SpinBox(locale->calendar()->minValidYear(),
+ locale->calendar()->maxValidYear(), this);
+ l->addWidget(m_yearSpin, 1);
+
+ connect(m_daySpin, SIGNAL(valueChanged(int)), SLOT(slotDateChanged()));
+ connect(m_monthCombo, SIGNAL(activated(int)), SLOT(slotDateChanged()));
+ connect(m_yearSpin, SIGNAL(valueChanged(int)), SLOT(slotDateChanged()));
+
+ m_dateButton = new KPushButton(this);
+ m_dateButton->setIconSet(SmallIconSet(QString::fromLatin1("date")));
+ connect(m_dateButton, SIGNAL(clicked()), SLOT(slotShowPicker()));
+ l->addWidget(m_dateButton, 0);
+
+ m_frame = new QVBox(0, 0, WType_Popup);
+ m_frame->setFrameStyle(QFrame::PopupPanel | QFrame::Raised);
+ m_frame->setLineWidth(3);
+ m_frame->hide();
+
+ m_picker = new KDatePicker(m_frame, 0); // must include name to get correct constructor
+ connect(m_picker, SIGNAL(dateEntered(QDate)), SLOT(slotDateEntered(QDate)));
+ connect(m_picker, SIGNAL(dateSelected(QDate)), SLOT(slotDateSelected(QDate)));
+}
+
+void DateWidget::slotDateChanged() {
+ int day = m_daySpin->value();
+ day = QMIN(QMAX(day, m_daySpin->minValue()), m_daySpin->maxValue());
+
+ int m = m_monthCombo->currentItem();
+ m = QMIN(QMAX(m, 0), m_monthCombo->count()-1);
+
+ int y = m_yearSpin->value();
+ y = QMIN(QMAX(y, m_yearSpin->minValue()), m_yearSpin->maxValue());
+
+ // if all are valid, set this date
+ if(day > m_daySpin->minValue() && m > 0 && y > m_yearSpin->minValue()) {
+ QDate d(y, m, day);
+ setDate(d);
+ }
+ emit signalModified();
+}
+
+QDate DateWidget::date() const {
+ // possible for either day, month, or year to be empty
+ // in which case a null date is returned
+ int day = m_daySpin->value();
+ // min value is the empty one
+ if(day == m_daySpin->minValue()) {
+ return QDate();
+ }
+ int month = m_monthCombo->currentItem();
+ if(month == 0) {
+ return QDate();
+ }
+ int year = m_yearSpin->value();
+ if(year == m_yearSpin->minValue()) {
+ return QDate();
+ }
+ return QDate(year, month, day);
+}
+
+QString DateWidget::text() const {
+ // possible for either day, month, or year to be empty
+ // but not all three
+ bool empty = true;
+ // format is "year-month-day"
+ QString s;
+ if(m_yearSpin->value() > m_yearSpin->minValue()) {
+ s += QString::number(m_yearSpin->value());
+ empty = false;
+ }
+ s += '-';
+ // first item is empty
+ if(m_monthCombo->currentItem() > 0) {
+ s += QString::number(m_monthCombo->currentItem());
+ empty = false;
+ }
+ s += '-';
+ if(m_daySpin->value() > m_daySpin->minValue()) {
+ s += QString::number(m_daySpin->value());
+ empty = false;
+ }
+ return empty ? QString() : s;
+}
+
+void DateWidget::setDate(const QDate& date_) {
+ m_daySpin->blockSignals(true);
+ m_monthCombo->blockSignals(true);
+ m_yearSpin->blockSignals(true);
+
+ const KCalendarSystem * calendar = KGlobal::locale()->calendar();
+ m_daySpin->setMaxValue(calendar->daysInMonth(date_));
+ m_daySpin->setValue(calendar->day(date_));
+ m_monthCombo->setCurrentItem(calendar->month(date_)); // don't subtract 1 since there's the blank first item
+ m_yearSpin->setValue(calendar->year(date_));
+
+ m_daySpin->blockSignals(false);
+ m_monthCombo->blockSignals(false);
+ m_yearSpin->blockSignals(false);
+}
+
+void DateWidget::setDate(const QString& date_) {
+ m_daySpin->blockSignals(true);
+ m_monthCombo->blockSignals(true);
+ m_yearSpin->blockSignals(true);
+
+ QStringList s = QStringList::split('-', date_, true);
+ bool ok = true;
+ int y = s.count() > 0 ? s[0].toInt(&ok) : m_yearSpin->minValue();
+ if(!ok) {
+ y = m_yearSpin->minValue();
+ ok = true;
+ }
+ y = QMIN(QMAX(y, m_yearSpin->minValue()), m_yearSpin->maxValue());
+ m_yearSpin->setValue(y);
+
+ int m = s.count() > 1 ? s[1].toInt(&ok) : 0;
+ if(!ok) {
+ m = 0;
+ ok = true;
+ }
+ m = QMIN(QMAX(m, 0), m_monthCombo->count()-1);
+ m_monthCombo->setCurrentItem(m);
+
+ // need to update number of days in month
+ // for now set date to 1
+ QDate date(y, (m == 0 ? 1 : m), 1);
+ m_daySpin->blockSignals(true);
+ m_daySpin->setMaxValue(KGlobal::locale()->calendar()->daysInMonth(date));
+ m_daySpin->blockSignals(false);
+
+ int day = s.count() > 2 ? s[2].toInt(&ok) : m_daySpin->minValue();
+ if(!ok) {
+ day = m_daySpin->minValue();
+ }
+ day = QMIN(QMAX(day, m_daySpin->minValue()), m_daySpin->maxValue());
+ m_daySpin->setValue(day);
+
+ m_daySpin->blockSignals(false);
+ m_monthCombo->blockSignals(false);
+ m_yearSpin->blockSignals(false);
+
+ // if all are valid, set this date
+ if(day > m_daySpin->minValue() && m > 0 && y > m_yearSpin->minValue()) {
+ QDate d(y, m, day);
+ m_picker->blockSignals(true);
+ m_picker->setDate(d);
+ m_picker->blockSignals(false);
+ }
+}
+
+void DateWidget::clear() {
+ m_daySpin->blockSignals(true);
+ m_monthCombo->blockSignals(true);
+ m_yearSpin->blockSignals(true);
+ m_picker->blockSignals(true);
+
+ m_daySpin->setValue(m_daySpin->minValue());
+ m_monthCombo->setCurrentItem(0);
+ m_yearSpin->setValue(m_yearSpin->minValue());
+ m_picker->setDate(QDate::currentDate());
+
+ m_daySpin->blockSignals(false);
+ m_monthCombo->blockSignals(false);
+ m_yearSpin->blockSignals(false);
+ m_picker->blockSignals(false);
+}
+
+void DateWidget::slotShowPicker() {
+ QRect desk = KGlobalSettings::desktopGeometry(this);
+ QPoint popupPoint = mapToGlobal(QPoint(0, 0));
+
+ int dateFrameHeight = m_frame->sizeHint().height();
+ if(popupPoint.y() + height() + dateFrameHeight > desk.bottom()) {
+ popupPoint.setY(popupPoint.y() - dateFrameHeight);
+ } else {
+ popupPoint.setY(popupPoint.y() + height());
+ }
+ int dateFrameWidth = m_frame->sizeHint().width();
+ if(popupPoint.x() + dateFrameWidth > desk.right()) {
+ popupPoint.setX(desk.right() - dateFrameWidth);
+ }
+
+ if(popupPoint.x() < desk.left()) {
+ popupPoint.setX( desk.left());
+ }
+ if(popupPoint.y() < desk.top()) {
+ popupPoint.setY(desk.top());
+ }
+
+ m_frame->move(popupPoint);
+
+ QDate d = date();
+ if(d.isValid()) {
+ m_picker->setDate(d);
+ }
+
+ m_frame->show();
+}
+
+void DateWidget::slotDateSelected(QDate date_) {
+ if(date_.isValid()) {
+ setDate(date_);
+ emit signalModified();
+ m_frame->hide();
+ }
+}
+
+void DateWidget::slotDateEntered(QDate date_) {
+ if(date_.isValid()) {
+ setDate(date_);
+ emit signalModified();
+ }
+}
+
+#include "datewidget.moc"
diff --git a/src/gui/datewidget.h b/src/gui/datewidget.h
new file mode 100644
index 0000000..93d7bcb
--- /dev/null
+++ b/src/gui/datewidget.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ copyright : (C) 2003-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TELLICODATEWIDGET_H
+#define TELLICODATEWIDGET_H
+
+#include <qspinbox.h>
+#include <qdatetime.h>
+
+class KComboBox;
+class KPushButton;
+class KDatePicker;
+
+class QVBox;
+class QString;
+
+namespace Tellico {
+ namespace GUI {
+
+class SpinBox : public QSpinBox {
+Q_OBJECT
+
+public:
+ SpinBox(int min, int max, QWidget *parent);
+};
+
+/**
+ * @author Robby Stephenson
+ */
+class DateWidget : public QWidget {
+Q_OBJECT
+
+public:
+ DateWidget(QWidget* parent, const char* name = 0);
+ ~DateWidget() {}
+
+ QDate date() const;
+ QString text() const;
+ void setDate(const QDate& date);
+ void setDate(const QString& date);
+ void clear();
+
+signals:
+ void signalModified();
+
+private slots:
+ void slotDateChanged();
+ void slotShowPicker();
+ void slotDateSelected(QDate newDate);
+ void slotDateEntered(QDate newDate);
+
+private:
+ SpinBox* m_daySpin;
+ KComboBox* m_monthCombo;
+ SpinBox* m_yearSpin;
+ KPushButton* m_dateButton;
+
+ QVBox* m_frame;
+ KDatePicker* m_picker;
+};
+
+ } // end namespace
+} // end namespace
+#endif
diff --git a/src/gui/fieldwidget.cpp b/src/gui/fieldwidget.cpp
new file mode 100644
index 0000000..6a9fc66
--- /dev/null
+++ b/src/gui/fieldwidget.cpp
@@ -0,0 +1,201 @@
+/***************************************************************************
+ copyright : (C) 2003-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "fieldwidget.h"
+#include "linefieldwidget.h"
+#include "parafieldwidget.h"
+#include "boolfieldwidget.h"
+#include "choicefieldwidget.h"
+#include "numberfieldwidget.h"
+#include "urlfieldwidget.h"
+#include "imagefieldwidget.h"
+#include "datefieldwidget.h"
+#include "tablefieldwidget.h"
+#include "ratingfieldwidget.h"
+#include "../field.h"
+
+#include <kdebug.h>
+#include <kurllabel.h>
+#include <klocale.h>
+
+#include <qlayout.h>
+#include <qwhatsthis.h>
+#include <qregexp.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qstyle.h>
+#include <qtimer.h>
+
+namespace {
+ // if you change this, update numberfieldwidget, too
+ const int FIELD_EDIT_WIDGET_INDEX = 2;
+}
+
+using Tellico::GUI::FieldWidget;
+
+const QRegExp FieldWidget::s_semiColon = QRegExp(QString::fromLatin1("\\s*;\\s*"));
+
+FieldWidget* FieldWidget::create(Data::FieldPtr field_, QWidget* parent_, const char* name_) {
+ switch (field_->type()) {
+ case Data::Field::Line:
+ return new GUI::LineFieldWidget(field_, parent_, name_);
+
+ case Data::Field::Para:
+ return new GUI::ParaFieldWidget(field_, parent_, name_);
+
+ case Data::Field::Bool:
+ return new GUI::BoolFieldWidget(field_, parent_, name_);
+
+ case Data::Field::Number:
+ return new GUI::NumberFieldWidget(field_, parent_, name_);
+
+ case Data::Field::Choice:
+ return new GUI::ChoiceFieldWidget(field_, parent_, name_);
+
+ case Data::Field::Table:
+ case Data::Field::Table2:
+ return new GUI::TableFieldWidget(field_, parent_, name_);
+
+ case Data::Field::Date:
+ return new GUI::DateFieldWidget(field_, parent_, name_);
+
+ case Data::Field::URL:
+ return new GUI::URLFieldWidget(field_, parent_, name_);
+
+ case Data::Field::Image:
+ return new GUI::ImageFieldWidget(field_, parent_, name_);
+
+ case Data::Field::Rating:
+ return new GUI::RatingFieldWidget(field_, parent_, name_);
+
+ case Data::Field::ReadOnly:
+ case Data::Field::Dependent:
+ kdWarning() << "FieldWidget::create() - read-only/dependent field, this shouldn't have been called" << endl;
+ return 0;
+
+ default:
+ kdWarning() << "FieldWidget::create() - unknown field type = " << field_->type() << endl;
+ return 0;
+ }
+}
+
+FieldWidget::FieldWidget(Data::FieldPtr field_, QWidget* parent_, const char* name_/*=0*/)
+ : QWidget(parent_, name_), m_field(field_) {
+ QHBoxLayout* l = new QHBoxLayout(this, 2, 2); // parent, margin, spacing
+ l->addSpacing(4); // add some more space in the columns between widgets
+ if(QCString(style().name()).lower().find("keramik", 0, false) > -1) {
+ l->setMargin(1);
+ }
+
+ Data::Field::Type type = field_->type();
+ QString s = i18n("Edit Label", "%1:").arg(field_->title());
+ if(type == Data::Field::URL) {
+ // set URL to null for now
+ m_label = new KURLLabel(QString::null, s, this);
+ } else {
+ m_label = new QLabel(s, this);
+ }
+ m_label->setFixedWidth(m_label->sizeHint().width());
+ l->addWidget(m_label);
+
+ // expands indicates if the edit widget should expand to full width of widget
+ m_expands = (type == Data::Field::Line
+ || type == Data::Field::Para
+ || type == Data::Field::Number
+ || type == Data::Field::URL
+ || type == Data::Field::Table
+ || type == Data::Field::Table2
+ || type == Data::Field::Image
+ || type == Data::Field::Date);
+
+ m_editMultiple = new QCheckBox(this);
+ m_editMultiple->setChecked(true);
+ m_editMultiple->setFixedWidth(m_editMultiple->sizeHint().width()); // don't let it have any extra space
+ connect(m_editMultiple, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
+ l->addWidget(m_editMultiple);
+
+ QWhatsThis::add(this, field_->description());
+ // after letting the subclass get created, insert default value
+ QTimer::singleShot(0, this, SLOT(insertDefault()));
+}
+
+void FieldWidget::insertDefault() {
+ setText(m_field->defaultValue());
+}
+
+bool FieldWidget::isEnabled() {
+ return widget()->isEnabled();
+}
+
+void FieldWidget::setEnabled(bool enabled_) {
+ if(enabled_ == isEnabled()) {
+ return;
+ }
+
+ widget()->setEnabled(enabled_);
+ m_editMultiple->setChecked(enabled_);
+}
+
+int FieldWidget::labelWidth() const {
+ return m_label->sizeHint().width();
+}
+
+void FieldWidget::setLabelWidth(int width_) {
+ m_label->setFixedWidth(width_);
+}
+
+bool FieldWidget::expands() const {
+ return m_expands;
+}
+
+void FieldWidget::editMultiple(bool show_) {
+ if(show_ == m_editMultiple->isShown()) {
+ return;
+ }
+
+ // FIXME: maybe modified should only be signaled when the button is toggle on
+ if(show_) {
+ m_editMultiple->show();
+ connect(m_editMultiple, SIGNAL(clicked()), this, SIGNAL(modified()));
+ } else {
+ m_editMultiple->hide();
+ disconnect(m_editMultiple, SIGNAL(clicked()), this, SIGNAL(modified()));
+ }
+ // the widget length needs to be updated since it gets shorter
+ widget()->updateGeometry();
+}
+
+void FieldWidget::registerWidget() {
+ QWidget* w = widget();
+ m_label->setBuddy(w);
+ if(w->isFocusEnabled()) {
+ setFocusProxy(w);
+ }
+
+ QHBoxLayout* l = static_cast<QHBoxLayout*>(layout());
+ l->insertWidget(FIELD_EDIT_WIDGET_INDEX, w, m_expands ? 1 : 0 /*stretch*/);
+ if(!m_expands) {
+ l->insertStretch(FIELD_EDIT_WIDGET_INDEX+1, 1 /*stretch*/);
+ }
+ updateGeometry();
+}
+
+void FieldWidget::updateField(Data::FieldPtr oldField_, Data::FieldPtr newField_) {
+ m_field = newField_;
+ m_label->setText(i18n("Edit Label", "%1:").arg(newField_->title()));
+ updateGeometry();
+ QWhatsThis::add(this, newField_->description());
+ updateFieldHook(oldField_, newField_);
+}
+
+#include "fieldwidget.moc"
diff --git a/src/gui/fieldwidget.h b/src/gui/fieldwidget.h
new file mode 100644
index 0000000..dd34ebb
--- /dev/null
+++ b/src/gui/fieldwidget.h
@@ -0,0 +1,91 @@
+/***************************************************************************
+ copyright : (C) 2003-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef FIELDWIDGET_H
+#define FIELDWIDGET_H
+
+#include "../datavectors.h"
+
+#include <qwidget.h>
+#include <qregexp.h>
+
+class QLabel;
+class QCheckBox;
+class QString;
+
+namespace Tellico {
+ namespace Data {
+ class Field;
+ }
+ namespace GUI {
+
+/**
+ * The FieldWidget class is a box that shows a label, then a widget which depends
+ * on the field type, and then a checkbox for multiple editing.
+ *
+ * @author Robby Stephenson
+ */
+class FieldWidget : public QWidget {
+Q_OBJECT
+
+public:
+ FieldWidget(Data::FieldPtr field, QWidget* parent, const char* name=0);
+ virtual ~FieldWidget() {}
+
+ Data::FieldPtr field() const { return m_field; }
+ virtual QString text() const = 0;
+ virtual void setText(const QString& text) = 0;
+
+ int labelWidth() const;
+ void setLabelWidth(int width);
+ bool isEnabled();
+ bool expands() const;
+ void editMultiple(bool show);
+ // calls updateFieldHook()
+ void updateField(Data::FieldPtr oldField, Data::FieldPtr newField);
+
+ // only used by LineFieldWidget, really
+ virtual void addCompletionObjectItem(const QString&) {}
+
+ // factory function
+ static FieldWidget* create(Data::FieldPtr field, QWidget* parent, const char* name=0);
+
+public slots:
+ virtual void insertDefault();
+ virtual void clear() = 0;
+ void setEnabled(bool enabled);
+
+signals:
+ virtual void modified();
+
+protected:
+ QLabel* label() { return m_label; } // needed so the URLField can handle clicks on the label
+ virtual QWidget* widget() = 0;
+ void registerWidget();
+
+ // not all widgets have to be updated when the field changes
+ virtual void updateFieldHook(Data::FieldPtr, Data::FieldPtr) {}
+
+ static const QRegExp s_semiColon;
+
+private:
+ Data::FieldPtr m_field;
+ QLabel* m_label;
+ QCheckBox* m_editMultiple;
+
+ bool m_expands;
+};
+
+ } // end GUI namespace
+} // end namespace
+#endif
diff --git a/src/gui/imagefieldwidget.cpp b/src/gui/imagefieldwidget.cpp
new file mode 100644
index 0000000..2cb9b40
--- /dev/null
+++ b/src/gui/imagefieldwidget.cpp
@@ -0,0 +1,54 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "imagefieldwidget.h"
+#include "imagewidget.h"
+#include "../field.h"
+#include "../latin1literal.h"
+
+using Tellico::GUI::ImageFieldWidget;
+
+ImageFieldWidget::ImageFieldWidget(Data::FieldPtr field_, QWidget* parent_, const char* name_/*=0*/)
+ : FieldWidget(field_, parent_, name_) {
+
+ m_widget = new ImageWidget(this);
+ m_widget->setLinkOnlyChecked(field_->property(QString::fromLatin1("link")) == Latin1Literal("true"));
+ connect(m_widget, SIGNAL(signalModified()), SIGNAL(modified()));
+
+ registerWidget();
+}
+
+QString ImageFieldWidget::text() const {
+ return m_widget->id();
+}
+
+void ImageFieldWidget::setText(const QString& text_) {
+ blockSignals(true);
+ m_widget->blockSignals(true);
+
+ m_widget->setImage(text_);
+
+ m_widget->blockSignals(false);
+ blockSignals(false);
+}
+
+void ImageFieldWidget::clear() {
+ m_widget->slotClear();
+ editMultiple(false);
+}
+
+QWidget* ImageFieldWidget::widget() {
+ return m_widget;
+}
+
+#include "imagefieldwidget.moc"
diff --git a/src/gui/imagefieldwidget.h b/src/gui/imagefieldwidget.h
new file mode 100644
index 0000000..b5ebea5
--- /dev/null
+++ b/src/gui/imagefieldwidget.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef IMAGEFIELDWIDGET_H
+#define IMAGEFIELDWIDGET_H
+
+#include "fieldwidget.h"
+#include "../datavectors.h"
+
+class QString;
+
+namespace Tellico {
+ namespace GUI {
+ class ImageWidget;
+
+/**
+ * @author Robby Stephenson
+ */
+class ImageFieldWidget : public FieldWidget {
+Q_OBJECT
+
+public:
+ ImageFieldWidget(Data::FieldPtr field, QWidget* parent, const char* name=0);
+ virtual ~ImageFieldWidget() {}
+
+ virtual QString text() const;
+ virtual void setText(const QString& text);
+
+public slots:
+ virtual void clear();
+
+protected:
+ virtual QWidget* widget();
+
+private:
+ ImageWidget* m_widget;
+};
+
+ } // end GUI namespace
+} // end namespace
+#endif
diff --git a/src/gui/imagewidget.cpp b/src/gui/imagewidget.cpp
new file mode 100644
index 0000000..92f75c3
--- /dev/null
+++ b/src/gui/imagewidget.cpp
@@ -0,0 +1,257 @@
+/***************************************************************************
+ copyright : (C) 2003-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "imagewidget.h"
+#include "../imagefactory.h"
+#include "../image.h"
+#include "../filehandler.h"
+#include "../tellico_debug.h"
+#include "../tellico_utils.h"
+
+#include <kfiledialog.h>
+#include <klocale.h>
+#include <kbuttonbox.h>
+#include <kurldrag.h>
+#include <kmessagebox.h>
+
+#include <qwmatrix.h>
+#include <qlayout.h>
+#include <qlabel.h>
+#include <qcheckbox.h>
+#include <qdragobject.h>
+#include <qapplication.h> // needed for drag distance
+
+namespace {
+ static const uint IMAGE_WIDGET_BUTTON_MARGIN = 8;
+ static const uint IMAGE_WIDGET_IMAGE_MARGIN = 4;
+ static const uint MAX_UNSCALED_WIDTH = 640;
+ static const uint MAX_UNSCALED_HEIGHT = 640;
+}
+
+using Tellico::GUI::ImageWidget;
+
+ImageWidget::ImageWidget(QWidget* parent_, const char* name_) : QWidget(parent_, name_) {
+ QHBoxLayout* l = new QHBoxLayout(this);
+ l->setMargin(IMAGE_WIDGET_BUTTON_MARGIN);
+ m_label = new QLabel(this);
+ m_label->setSizePolicy(QSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored));
+ m_label->setFrameStyle(QFrame::Panel | QFrame::Sunken);
+ m_label->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
+ l->addWidget(m_label, 1);
+ l->addSpacing(IMAGE_WIDGET_BUTTON_MARGIN);
+
+ QVBoxLayout* boxLayout = new QVBoxLayout(l);
+ boxLayout->addStretch(1);
+
+ KButtonBox* box = new KButtonBox(this, Vertical);
+ box->addButton(i18n("Select Image..."), this, SLOT(slotGetImage()));
+ box->addButton(i18n("Clear"), this, SLOT(slotClear()));
+ box->layout();
+ boxLayout->addWidget(box);
+
+ boxLayout->addSpacing(8);
+ m_cbLinkOnly = new QCheckBox(i18n("Save link only"), this);
+ connect(m_cbLinkOnly, SIGNAL(clicked()), SLOT(slotLinkOnlyClicked()));
+ boxLayout->addWidget(m_cbLinkOnly);
+
+ boxLayout->addStretch(1);
+ slotClear();
+
+ // accept image drops
+ setAcceptDrops(true);
+}
+
+void ImageWidget::setImage(const QString& id_) {
+ if(id_.isEmpty()) {
+ slotClear();
+ return;
+ }
+ m_imageID = id_;
+ m_pixmap = ImageFactory::pixmap(id_, MAX_UNSCALED_WIDTH, MAX_UNSCALED_HEIGHT);
+ const bool link = ImageFactory::imageInfo(id_).linkOnly;
+ m_cbLinkOnly->setChecked(link);
+ m_cbLinkOnly->setEnabled(link);
+ // if we're using a link, then the original URL _is_ the id
+ m_originalURL = link ? id_ : KURL();
+ m_scaled = QPixmap();
+ scale();
+
+ update();
+}
+
+void ImageWidget::setLinkOnlyChecked(bool link_) {
+ m_cbLinkOnly->setChecked(link_);
+}
+
+void ImageWidget::slotClear() {
+// m_image = Data::Image();
+ m_imageID = QString();
+ m_pixmap = QPixmap();
+ m_scaled = m_pixmap;
+ m_originalURL = KURL();
+
+ m_label->setPixmap(m_scaled);
+ m_cbLinkOnly->setChecked(false);
+ m_cbLinkOnly->setEnabled(true);
+ update();
+ emit signalModified();
+}
+
+void ImageWidget::scale() {
+ int ww = m_label->width() - 2*IMAGE_WIDGET_IMAGE_MARGIN;
+ int wh = m_label->height() - 2*IMAGE_WIDGET_IMAGE_MARGIN;
+ int pw = m_pixmap.width();
+ int ph = m_pixmap.height();
+
+ if(ww < pw || wh < ph) {
+ int newWidth, newHeight;
+ if(pw*wh < ph*ww) {
+ newWidth = static_cast<int>(static_cast<double>(pw)*wh/static_cast<double>(ph));
+ newHeight = wh;
+ } else {
+ newWidth = ww;
+ newHeight = static_cast<int>(static_cast<double>(ph)*ww/static_cast<double>(pw));
+ }
+
+ QWMatrix wm;
+ wm.scale(static_cast<double>(newWidth)/pw, static_cast<double>(newHeight)/ph);
+ m_scaled = m_pixmap.xForm(wm);
+ } else {
+ m_scaled = m_pixmap;
+ }
+ m_label->setPixmap(m_scaled);
+}
+
+void ImageWidget::resizeEvent(QResizeEvent *) {
+ if(m_pixmap.isNull()) {
+ return;
+ }
+
+ scale();
+ update();
+}
+
+void ImageWidget::slotGetImage() {
+ KURL url = KFileDialog::getImageOpenURL(QString::null, this);
+ if(url.isEmpty() || !url.isValid()) {
+ return;
+ }
+ loadImage(url);
+}
+
+void ImageWidget::slotLinkOnlyClicked() {
+ if(m_imageID.isEmpty()) {
+ // nothing to do, it has an empty image;
+ return;
+ }
+
+ bool link = m_cbLinkOnly->isChecked();
+ // if the user is trying to link and can't before there's no information about the url
+ // the let him know that
+ if(link && m_originalURL.isEmpty()) {
+ KMessageBox::sorry(this, i18n("Saving a link is only possible for newly added images."));
+ m_cbLinkOnly->setChecked(false);
+ return;
+ }
+ // need to reset image id to be the original url
+ // if we're linking only, then we want the image id to be the same as the url
+ // so it needs to be added to the cache all over again
+ // probably could do this without downloading the image all over again,
+ // but I'm not going to do that right now
+ const QString& id = ImageFactory::addImage(m_originalURL, false, KURL(), link);
+ // same image, so no need to call setImage
+ m_imageID = id;
+ emit signalModified();
+}
+
+void ImageWidget::mousePressEvent(QMouseEvent* event_) {
+ // Only interested in LMB
+ if(event_->button() == Qt::LeftButton) {
+ // Store the position of the mouse press.
+ // check if position is inside the label
+ if(m_label->geometry().contains(event_->pos())) {
+ m_dragStart = event_->pos();
+ } else {
+ m_dragStart = QPoint();
+ }
+ }
+}
+
+void ImageWidget::mouseMoveEvent(QMouseEvent* event_) {
+ int delay = QApplication::startDragDistance();
+ // Only interested in LMB
+ if(event_->state() & Qt::LeftButton) {
+ // only allow drag is the image is non-null, and the drag start point isn't null and the user dragged far enough
+ if(!m_imageID.isEmpty() && !m_dragStart.isNull() && (m_dragStart - event_->pos()).manhattanLength() > delay) {
+ const Data::Image& img = ImageFactory::imageById(m_imageID);
+ if(!img.isNull()) {
+ QImageDrag* drag = new QImageDrag(img, this);
+ drag->dragCopy();
+ }
+ }
+ }
+}
+
+void ImageWidget::dragEnterEvent(QDragEnterEvent* event_) {
+ event_->accept(KURLDrag::canDecode(event_) || QImageDrag::canDecode(event_) || QTextDrag::canDecode(event_));
+}
+
+void ImageWidget::dropEvent(QDropEvent* event_) {
+ QImage image;
+ KURL::List urls;
+ QString text;
+
+ GUI::CursorSaver cs(Qt::busyCursor);
+ if(QImageDrag::decode(event_, image)) {
+ // Qt reads PNG data by default
+ const QString& id = ImageFactory::addImage(image, QString::fromLatin1("PNG"));
+ if(!id.isEmpty() && id != m_imageID) {
+ setImage(id);
+ emit signalModified();
+ }
+ } else if(KURLDrag::decode(event_, urls)) {
+ if(urls.isEmpty()) {
+ return;
+ }
+ // only care about the first one
+ const KURL& url = urls[0];
+ if(url.isEmpty() || !url.isValid()) {
+ return;
+ }
+// kdDebug() << "ImageWidget::dropEvent() - " << url.prettyURL() << endl;
+ loadImage(url);
+ } else if(QTextDrag::decode(event_, text)) {
+ KURL url(text);
+ if(url.isEmpty() || !url.isValid()) {
+ return;
+ }
+ loadImage(url);
+ }
+}
+
+void ImageWidget::loadImage(const KURL& url_) {
+ const bool link = m_cbLinkOnly->isChecked();
+
+ GUI::CursorSaver cs;
+ // if we're linking only, then we want the image id to be the same as the url
+ const QString& id = ImageFactory::addImage(url_, false, KURL(), link);
+ if(id != m_imageID) {
+ setImage(id);
+ emit signalModified();
+ }
+ // at the end, cause setImage() resets it
+ m_originalURL = url_;
+ m_cbLinkOnly->setEnabled(true);
+}
+
+#include "imagewidget.moc"
diff --git a/src/gui/imagewidget.h b/src/gui/imagewidget.h
new file mode 100644
index 0000000..7780be4
--- /dev/null
+++ b/src/gui/imagewidget.h
@@ -0,0 +1,78 @@
+/***************************************************************************
+ copyright : (C) 2003-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TELLICOIMAGEWIDGET_H
+#define TELLICOIMAGEWIDGET_H
+
+#include <kurl.h>
+#include <qwidget.h>
+#include <qpixmap.h>
+#include <qpoint.h>
+
+class QLabel;
+class QResizeEvent;
+class QMouseEvent;
+class QDragEnterEvent;
+class QDropEvent;
+class QCheckBox;
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * @author Robby Stephenson
+ */
+class ImageWidget : public QWidget {
+Q_OBJECT
+
+public:
+ ImageWidget(QWidget* parent, const char* name = 0);
+ virtual ~ImageWidget() {}
+
+ const QString& id() const { return m_imageID; }
+ void setImage(const QString& id);
+ void setLinkOnlyChecked(bool l);
+
+public slots:
+ void slotClear();
+
+signals:
+ void signalModified();
+
+protected:
+ virtual void resizeEvent(QResizeEvent* ev);
+ virtual void mousePressEvent(QMouseEvent* ev);
+ virtual void mouseMoveEvent(QMouseEvent* ev);
+ virtual void dragEnterEvent(QDragEnterEvent* ev);
+ virtual void dropEvent(QDropEvent* ev);
+
+private slots:
+ void slotGetImage();
+ void slotLinkOnlyClicked();
+
+private:
+ void scale();
+ void loadImage(const KURL& url);
+
+ QString m_imageID;
+ QPixmap m_pixmap;
+ QPixmap m_scaled;
+ QLabel* m_label;
+ QCheckBox* m_cbLinkOnly;
+ KURL m_originalURL;
+ QPoint m_dragStart;
+};
+
+ } // end GUI namespace
+} // end namespace
+#endif
diff --git a/src/gui/kwidgetlister.cpp b/src/gui/kwidgetlister.cpp
new file mode 100644
index 0000000..80bf31b
--- /dev/null
+++ b/src/gui/kwidgetlister.cpp
@@ -0,0 +1,178 @@
+/* -*- c++ -*-
+ kwidgetlister.cpp
+
+ This file is part of libkdenetwork.
+ Copyright (c) 2001 Marc Mutz <mutz@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifh Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this library with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#include "kwidgetlister.h"
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kpushbutton.h>
+#include <kiconloader.h>
+
+#include <qlayout.h>
+#include <qhbox.h>
+
+#include <assert.h>
+
+KWidgetLister::KWidgetLister( int minWidgets, int maxWidgets, QWidget *parent, const char* name )
+ : QWidget( parent, name )
+{
+ mWidgetList.setAutoDelete(TRUE);
+
+ mMinWidgets = QMAX( minWidgets, 1 );
+ mMaxWidgets = QMAX( maxWidgets, mMinWidgets + 1 );
+
+ //--------- the button box
+ mLayout = new QVBoxLayout(this, 0, 4);
+ mButtonBox = new QHBox(this);
+ mButtonBox->setSpacing(4);
+ mLayout->addWidget( mButtonBox );
+
+ mBtnMore = new KPushButton( i18n("more widgets","More"), mButtonBox );
+ mBtnMore->setIconSet(SmallIconSet(QString::fromLatin1("down")));
+ mButtonBox->setStretchFactor( mBtnMore, 0 );
+
+ mBtnFewer = new KPushButton( i18n("fewer widgets","Fewer"), mButtonBox );
+ mBtnFewer->setIconSet(SmallIconSet(QString::fromLatin1("up")));
+ mButtonBox->setStretchFactor( mBtnFewer, 0 );
+
+ QWidget *spacer = new QWidget( mButtonBox );
+ mButtonBox->setStretchFactor( spacer, 1 );
+
+ mBtnClear = new KPushButton( i18n("clear widgets","Clear"), mButtonBox );
+ mBtnClear->setIconSet(SmallIconSet(QString::fromLatin1("locationbar_erase")));
+ mButtonBox->setStretchFactor( mBtnClear, 0 );
+
+ //---------- connect everything
+ connect( mBtnMore, SIGNAL(clicked()),
+ this, SLOT(slotMore()) );
+ connect( mBtnFewer, SIGNAL(clicked()),
+ this, SLOT(slotFewer()) );
+ connect( mBtnClear, SIGNAL(clicked()),
+ this, SLOT(slotClear()) );
+
+ enableControls();
+}
+
+KWidgetLister::~KWidgetLister()
+{
+}
+
+void KWidgetLister::slotMore()
+{
+ // the class should make certain that slotMore can't
+ // be called when mMaxWidgets are on screen.
+ assert( (int)mWidgetList.count() < mMaxWidgets );
+
+ addWidgetAtEnd();
+ // adjustSize();
+ enableControls();
+}
+
+void KWidgetLister::slotFewer()
+{
+ // the class should make certain that slotFewer can't
+ // be called when mMinWidgets are on screen.
+ assert( (int)mWidgetList.count() > mMinWidgets );
+
+ removeLastWidget();
+ // adjustSize();
+ enableControls();
+}
+
+void KWidgetLister::slotClear()
+{
+ setNumberOfShownWidgetsTo( mMinWidgets );
+
+ // clear remaining widgets
+ QPtrListIterator<QWidget> it( mWidgetList );
+ for ( it.toFirst() ; it.current() ; ++it )
+ clearWidget( (*it) );
+
+ // adjustSize();
+ enableControls();
+ emit clearWidgets();
+}
+
+void KWidgetLister::addWidgetAtEnd(QWidget *w)
+{
+ if (!w) w = this->createWidget(this);
+
+ mLayout->insertWidget( mLayout->findWidget( mButtonBox ), w );
+ mWidgetList.append( w );
+ w->show();
+ enableControls();
+ emit widgetAdded();
+ emit widgetAdded(w);
+}
+
+void KWidgetLister::removeLastWidget()
+{
+ // The layout will take care that the
+ // widget is removed from screen, too.
+ mWidgetList.removeLast();
+ enableControls();
+ emit widgetRemoved();
+}
+
+void KWidgetLister::clearWidget( QWidget* /*aWidget*/ )
+{
+}
+
+QWidget* KWidgetLister::createWidget( QWidget* parent )
+{
+ return new QWidget( parent );
+}
+
+void KWidgetLister::setNumberOfShownWidgetsTo( int aNum )
+{
+ int superfluousWidgets = QMAX( (int)mWidgetList.count() - aNum, 0 );
+ int missingWidgets = QMAX( aNum - (int)mWidgetList.count(), 0 );
+
+ // remove superfluous widgets
+ for ( ; superfluousWidgets ; superfluousWidgets-- )
+ removeLastWidget();
+
+ // add missing widgets
+ for ( ; missingWidgets ; missingWidgets-- )
+ addWidgetAtEnd();
+}
+
+void KWidgetLister::enableControls()
+{
+ int count = mWidgetList.count();
+ bool isMaxWidgets = ( count >= mMaxWidgets );
+ bool isMinWidgets = ( count <= mMinWidgets );
+
+ mBtnMore->setEnabled( !isMaxWidgets );
+ mBtnFewer->setEnabled( !isMinWidgets );
+}
+
+#include "kwidgetlister.moc"
diff --git a/src/gui/kwidgetlister.h b/src/gui/kwidgetlister.h
new file mode 100644
index 0000000..e02b54c
--- /dev/null
+++ b/src/gui/kwidgetlister.h
@@ -0,0 +1,150 @@
+/* -*- c++ -*-
+ kwidgetlister.h
+
+ This file is part of libkdenetwork.
+ Copyright (c) 2001 Marc Mutz <mutz@kde.org>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License,
+ version 2, as published by the Free Software Foundation.
+
+ 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
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifh Floor, Boston, MA 02110-1301 USA
+
+ In addition, as a special exception, the copyright holders give
+ permission to link the code of this library with any edition of
+ the Qt library by Trolltech AS, Norway (or with modified versions
+ of Qt that use the same license as Qt), and distribute linked
+ combinations including the two. You must obey the GNU General
+ Public License in all respects for all of the code used other than
+ Qt. If you modify this file, you may extend this exception to
+ your version of the file, but you are not obligated to do so. If
+ you do not wish to do so, delete this exception statement from
+ your version.
+*/
+
+#ifndef _KWIDGETLISTER_H_
+#define _KWIDGETLISTER_H_
+
+#include <qwidget.h>
+#include <qptrlist.h>
+
+class KPushButton;
+class QVBoxLayout;
+class QHBox;
+
+/** Simple widget that nonetheless does a lot of the dirty work for
+ the filter edit widgets (@ref KMSearchpatternEdit and @ref
+ KMFilterActionEdit). It provides a growable and shrinkable area
+ where widget may be displayed in rows. Widgets can be added by
+ hitting the provided 'More' button, removed by the 'Fewer' button
+ and cleared (e.g. reset, if an derived class implements that and
+ removed for all but @ref mMinWidgets).
+
+ To use this widget, derive from it with the template changed to
+ the type of widgets this class should list. Then reimplement @ref
+ addWidgetAtEnd, @ref removeLastWidget, calling the original
+ implementation as necessary. Instantate an object of the class and
+ put it in your dialog.
+
+ @short Widget that manages a list of other widgets (incl. 'more', 'fewer' and 'clear' buttons).
+ @author Marc Mutz <Marc@Mutz.com>
+ @see KMSearchPatternEdit::WidgetLister KMFilterActionEdit::WidgetLister
+
+*/
+
+class KWidgetLister : public QWidget
+{
+ Q_OBJECT
+public:
+ KWidgetLister( int minWidgets=1, int maxWidgets=8, QWidget* parent=0, const char* name=0 );
+ virtual ~KWidgetLister();
+
+protected slots:
+ /** Called whenever the user clicks on the 'more' button.
+ Reimplementations should call this method, because this
+ implementation does all the dirty work with adding the widgets
+ to the layout (through @ref addWidgetAtEnd) and enabling/disabling
+ the control buttons. */
+ virtual void slotMore();
+ /** Called whenever the user clicks on the 'fewer' button.
+ Reimplementations should call this method, because this
+ implementation does all the dirty work with removing the widgets
+ from the layout (through @ref removelastWidget) and
+ enabling/disabling the control buttons. */
+ virtual void slotFewer();
+ /** Called whenever the user clicks on the 'clear' button.
+ Reimplementations should call this method, because this
+ implementation does all the dirty work with removing all but
+ @ref mMinWidets widgets from the layout and enabling/disabling
+ the control buttons. */
+ virtual void slotClear();
+
+
+
+protected:
+ /** Adds a single widget. Doesn't care if there are already @ref
+ mMaxWidgets on screen and whether it should enable/disable any
+ controls. It simply does what it is asked to do. You want to
+ reimplement this method if you want to initialize the the widget
+ when showing it on screen. Make sure you call this
+ implementaion, though, since you cannot put the widget on screen
+ from derived classes (@p mLayout is private).
+ Make sure the parent of the QWidget to add is this KWidgetLister. */
+ virtual void addWidgetAtEnd(QWidget *w =0);
+ /** Removes a single (always the last) widget. Doesn't care if there
+ are still only @ref mMinWidgets left on screen and whether it
+ should enable/disable any controls. It simply does what it is
+ asked to do. You want to reimplement this method if you want to
+ save the the widget's state before removing it from screen. Make
+ sure you call this implementaion, though, since you should not
+ remove the widget from screen from derived classes. */
+ virtual void removeLastWidget();
+ /** Called to clear a given widget. The default implementation does
+ nothing. */
+ virtual void clearWidget( QWidget* );
+ /** Because QT 2.x does not support signals/slots in template
+ classes, we are forced to emulate this by forcing the
+ implementers of subclasses of KWidgetLister to reimplement this
+ function which replaces the "@p new @p T" call. */
+ virtual QWidget* createWidget( QWidget *parent );
+ /** Sets the number of widgets on scrren to exactly @p aNum. Doesn't
+ check if @p aNum is inside the range @p
+ [mMinWidgets,mMaxWidgets]. */
+ virtual void setNumberOfShownWidgetsTo( int aNum );
+ /** The list of widgets. Note that this list is set to auto-delete,
+ meaning that widgets that are removed from the screen by either
+ @ref slotFewer or @ref slotClear will be destroyed! */
+ QPtrList<QWidget> mWidgetList;
+ /** The minimum number of widgets that are to stay on screen. */
+ int mMinWidgets;
+ /** The maximum number of widgets that are to be shown on screen. */
+ int mMaxWidgets;
+
+signals:
+ /** This signal is emitted whenever a widget was added */
+ void widgetAdded();
+ /** This signal is emitted whenever a widget was added */
+ void widgetAdded(QWidget *);
+ /** This signal is emitted whenever a widget was removed */
+ void widgetRemoved();
+ /** This signal is emitted whenever the clear button is clicked */
+ void clearWidgets();
+
+private:
+ void enableControls();
+
+ KPushButton *mBtnMore, *mBtnFewer, *mBtnClear;
+ QVBoxLayout *mLayout;
+ QHBox *mButtonBox;
+};
+
+
+
+#endif /* _KWIDGETLISTER_H_ */
diff --git a/src/gui/lineedit.cpp b/src/gui/lineedit.cpp
new file mode 100644
index 0000000..6248880
--- /dev/null
+++ b/src/gui/lineedit.cpp
@@ -0,0 +1,150 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "lineedit.h"
+
+#include <kstdaction.h>
+#include <kactioncollection.h>
+#include <kspell.h>
+
+#include <qapplication.h>
+#include <qpainter.h>
+#include <qpopupmenu.h>
+
+using Tellico::GUI::LineEdit;
+
+LineEdit::LineEdit(QWidget* parent_, const char* name_) : KLineEdit(parent_, name_)
+ , m_drawHint(false)
+ , m_allowSpellCheck(false)
+ , m_enableSpellCheck(true)
+ , m_spell(0) {
+ m_spellAction = KStdAction::spelling(this, SLOT(slotCheckSpelling()), new KActionCollection(this));
+}
+
+void LineEdit::clear() {
+ KLineEdit::clear();
+ m_drawHint = true;
+ repaint();
+}
+
+void LineEdit::setText(const QString& text_) {
+ m_drawHint = text_.isEmpty();
+ repaint();
+ KLineEdit::setText(text_);
+}
+
+void LineEdit::setHint(const QString& hint_) {
+ m_hint = hint_;
+ m_drawHint = text().isEmpty();
+ repaint();
+}
+
+void LineEdit::focusInEvent(QFocusEvent* event_) {
+ if(m_drawHint) {
+ m_drawHint = false;
+ repaint();
+ }
+ KLineEdit::focusInEvent(event_);
+}
+
+void LineEdit::focusOutEvent(QFocusEvent* event_) {
+ if(text().isEmpty()) {
+ m_drawHint = true;
+ repaint();
+ }
+ KLineEdit::focusOutEvent(event_);
+}
+
+void LineEdit::drawContents(QPainter* painter_) {
+ // draw the regular line edit first
+ KLineEdit::drawContents(painter_);
+
+ // no need to draw anything else if in focus or no hint
+ if(hasFocus() || !m_drawHint || m_hint.isEmpty() || !text().isEmpty()) {
+ return;
+ }
+
+ // save current pen
+ QPen oldPen = painter_->pen();
+
+ // follow lead of kdepim and amarok, use disabled text color
+ painter_->setPen(palette().color(QPalette::Disabled, QColorGroup::Text));
+
+ QRect rect = contentsRect();
+ // again, follow kdepim and amarok lead, and pad by 2 pixels
+ rect.rLeft() += 2;
+ painter_->drawText(rect, AlignAuto | AlignVCenter, m_hint);
+
+ // reset pen
+ painter_->setPen(oldPen);
+}
+
+QPopupMenu* LineEdit::createPopupMenu() {
+ QPopupMenu* popup = KLineEdit::createPopupMenu();
+
+ if(!popup) {
+ return popup;
+ }
+
+ if(m_allowSpellCheck && echoMode() == QLineEdit::Normal && !isReadOnly()) {
+ popup->insertSeparator();
+
+ m_spellAction->plug(popup);
+ m_spellAction->setEnabled(m_enableSpellCheck && !text().isEmpty());
+ }
+
+ return popup;
+}
+
+void LineEdit::slotCheckSpelling() {
+ delete m_spell;
+ // re-use the action string to get translations
+ m_spell = new KSpell(this, m_spellAction->text(),
+ this, SLOT(slotSpellCheckReady(KSpell*)), 0, true, true);
+
+ connect(m_spell, SIGNAL(death()),
+ SLOT(spellCheckerFinished()));
+ connect(m_spell, SIGNAL(misspelling( const QString &, const QStringList &, unsigned int)),
+ SLOT(spellCheckerMisspelling( const QString &, const QStringList &, unsigned int)));
+ connect(m_spell, SIGNAL(corrected(const QString &, const QString &, unsigned int)),
+ SLOT(spellCheckerCorrected(const QString &, const QString &, unsigned int)));
+}
+
+void LineEdit::slotSpellCheckReady(KSpell* spell) {
+ spell->check(text());
+ connect(spell, SIGNAL(done(const QString&)), SLOT(slotSpellCheckDone(const QString&)));
+}
+
+void LineEdit::slotSpellCheckDone(const QString& newText) {
+ if(newText != text()) {
+ setText(newText);
+ }
+}
+
+void LineEdit::spellCheckerFinished() {
+ delete m_spell;
+ m_spell = 0;
+}
+
+void LineEdit::spellCheckerMisspelling(const QString &text, const QStringList&, unsigned int pos) {
+ setSelection(pos, pos + text.length());
+}
+
+void LineEdit::spellCheckerCorrected(const QString& oldWord, const QString& newWord, unsigned int pos) {
+ if(oldWord != newWord) {
+ setSelection(pos, pos + oldWord.length());
+ insert(newWord);
+ }
+}
+
+#include "lineedit.moc"
diff --git a/src/gui/lineedit.h b/src/gui/lineedit.h
new file mode 100644
index 0000000..af7d81b
--- /dev/null
+++ b/src/gui/lineedit.h
@@ -0,0 +1,72 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TELLICO_GUILINEEDIT_H
+#define TELLICO_GUILINEEDIT_H
+
+#include <klineedit.h>
+
+#include <qstring.h>
+
+class KAction;
+class KSpell;
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * @author Robby Stephenson
+ */
+class LineEdit : public KLineEdit {
+Q_OBJECT
+
+public:
+ LineEdit(QWidget* parent = 0, const char* name = 0);
+
+ virtual void setText(const QString& text);
+ void setHint(const QString& hint);
+
+ // by default, spell check is not allowed, and no popupmenu item is created
+ void setAllowSpellCheck(bool b) { m_allowSpellCheck = b; }
+ // spell check may be allowed but disabled
+ void setEnableSpellCheck(bool b) { m_enableSpellCheck = b; }
+
+public slots:
+ void clear();
+
+protected:
+ virtual void focusInEvent(QFocusEvent* event);
+ virtual void focusOutEvent(QFocusEvent* event);
+ virtual void drawContents(QPainter* painter);
+ virtual QPopupMenu* createPopupMenu();
+
+private slots:
+ void slotCheckSpelling();
+ void slotSpellCheckReady(KSpell* spell);
+ void slotSpellCheckDone(const QString& text);
+ void spellCheckerMisspelling(const QString& text, const QStringList&, unsigned int pos);
+ void spellCheckerCorrected(const QString& oldText, const QString& newText, unsigned int pos);
+ void spellCheckerFinished();
+
+private:
+ QString m_hint;
+ bool m_drawHint;
+ KAction* m_spellAction;
+ bool m_allowSpellCheck;
+ bool m_enableSpellCheck;
+ KSpell* m_spell;
+};
+
+ } // end namespace
+} // end namespace
+#endif
diff --git a/src/gui/linefieldwidget.cpp b/src/gui/linefieldwidget.cpp
new file mode 100644
index 0000000..1535832
--- /dev/null
+++ b/src/gui/linefieldwidget.cpp
@@ -0,0 +1,90 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "linefieldwidget.h"
+#include "../field.h"
+#include "../isbnvalidator.h"
+#include "../fieldcompletion.h"
+#include "../latin1literal.h"
+#include "../tellico_kernel.h"
+#include "../gui/lineedit.h"
+
+using Tellico::GUI::LineFieldWidget;
+
+LineFieldWidget::LineFieldWidget(Data::FieldPtr field_, QWidget* parent_, const char* name_/*=0*/)
+ : FieldWidget(field_, parent_, name_) {
+
+ m_lineEdit = new GUI::LineEdit(this);
+ m_lineEdit->setAllowSpellCheck(true);
+ m_lineEdit->setEnableSpellCheck(field_->formatFlag() != Data::Field::FormatName);
+ connect(m_lineEdit, SIGNAL(textChanged(const QString&)), SIGNAL(modified()));
+
+ registerWidget();
+
+ if(field_->flags() & Data::Field::AllowCompletion) {
+ FieldCompletion* completion = new FieldCompletion(field_->flags() & Data::Field::AllowMultiple);
+ completion->setItems(Kernel::self()->valuesByFieldName(field_->name()));
+ completion->setIgnoreCase(true);
+ m_lineEdit->setCompletionObject(completion);
+ m_lineEdit->setAutoDeleteCompletionObject(true);
+ }
+
+ if(field_->name() == Latin1Literal("isbn")) {
+ m_lineEdit->setValidator(new ISBNValidator(this));
+ }
+}
+
+QString LineFieldWidget::text() const {
+ QString text = m_lineEdit->text();
+ if(field()->flags() & Data::Field::AllowMultiple) {
+ text.replace(s_semiColon, QString::fromLatin1("; "));
+ }
+ return text.stripWhiteSpace();
+}
+
+void LineFieldWidget::setText(const QString& text_) {
+ blockSignals(true);
+ m_lineEdit->blockSignals(true);
+ m_lineEdit->setText(text_);
+ m_lineEdit->blockSignals(false);
+ blockSignals(false);
+}
+
+void LineFieldWidget::clear() {
+ m_lineEdit->clear();
+ editMultiple(false);
+}
+
+void LineFieldWidget::addCompletionObjectItem(const QString& text_) {
+ m_lineEdit->completionObject()->addItem(text_);
+}
+
+void LineFieldWidget::updateFieldHook(Data::FieldPtr oldField_, Data::FieldPtr newField_) {
+ bool wasComplete = (oldField_->flags() & Data::Field::AllowCompletion);
+ bool isComplete = (newField_->flags() & Data::Field::AllowCompletion);
+ if(!wasComplete && isComplete) {
+ FieldCompletion* completion = new FieldCompletion(isComplete);
+ completion->setItems(Kernel::self()->valuesByFieldName(newField_->name()));
+ completion->setIgnoreCase(true);
+ m_lineEdit->setCompletionObject(completion);
+ m_lineEdit->setAutoDeleteCompletionObject(true);
+ } else if(wasComplete && !isComplete) {
+ m_lineEdit->completionObject()->clear();
+ }
+}
+
+QWidget* LineFieldWidget::widget() {
+ return m_lineEdit;
+}
+
+#include "linefieldwidget.moc"
diff --git a/src/gui/linefieldwidget.h b/src/gui/linefieldwidget.h
new file mode 100644
index 0000000..70dc175
--- /dev/null
+++ b/src/gui/linefieldwidget.h
@@ -0,0 +1,51 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef LINEFIELDWIDGET_H
+#define LINEFIELDWIDGET_H
+
+#include "fieldwidget.h"
+#include "../datavectors.h"
+
+namespace Tellico {
+ namespace GUI {
+ class LineEdit;
+
+/**
+ * @author Robby Stephenson
+ */
+class LineFieldWidget : public FieldWidget {
+Q_OBJECT
+
+public:
+ LineFieldWidget(Data::FieldPtr field, QWidget* parent, const char* name=0);
+ virtual ~LineFieldWidget() {}
+
+ virtual QString text() const;
+ virtual void setText(const QString& text);
+ virtual void addCompletionObjectItem(const QString& text);
+
+public slots:
+ virtual void clear();
+
+protected:
+ virtual QWidget* widget();
+ virtual void updateFieldHook(Data::FieldPtr oldField, Data::FieldPtr newField);
+
+private:
+ GUI::LineEdit* m_lineEdit;
+};
+
+ } // end GUI namespace
+} // end namespace
+#endif
diff --git a/src/gui/listboxtext.cpp b/src/gui/listboxtext.cpp
new file mode 100644
index 0000000..8ec6fa2
--- /dev/null
+++ b/src/gui/listboxtext.cpp
@@ -0,0 +1,74 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : $EMAIL
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "listboxtext.h"
+#include "../tellico_utils.h"
+
+#include <qpainter.h>
+
+using Tellico::GUI::ListBoxText;
+
+ListBoxText::ListBoxText(QListBox* listbox_, const QString& text_)
+ : QListBoxText(listbox_, text_), m_colored(false) {
+}
+
+ListBoxText::ListBoxText(QListBox* listbox_, const QString& text_, QListBoxItem* after_)
+ : QListBoxText(listbox_, text_, after_), m_colored(false) {
+}
+
+int ListBoxText::width(const QListBox* listbox_) const {
+ if(m_colored) {
+ QFont font = listbox_->font();
+ font.setBold(true);
+ font.setItalic(true);
+ QFontMetrics fm(font);
+ return fm.width(text()) + 6;
+ } else {
+ return QListBoxText::width(listbox_);
+ }
+}
+
+// I don't want the height to change when colored
+// so all the items are at the same level for multi-column boxes
+int ListBoxText::height(const QListBox* listbox_) const {
+ return QListBoxText::height(listbox_);
+}
+
+void ListBoxText::setColored(bool colored_) {
+ if(m_colored != colored_) {
+ m_colored = colored_;
+ listBox()->triggerUpdate(false);
+ }
+}
+
+void ListBoxText::setText(const QString& text_) {
+ QListBoxText::setText(text_);
+ listBox()->triggerUpdate(true);
+}
+
+// mostly copied from QListBoxText::paint() in Qt 3.1.1
+void ListBoxText::paint(QPainter* painter_) {
+ if(m_colored) {
+ QFont font = painter_->font();
+ font.setBold(true);
+ font.setItalic(true);
+ painter_->setFont(font);
+ if(!isSelected()) {
+ painter_->setPen(Tellico::contrastColor);
+ }
+ }
+ int itemHeight = height(listBox());
+ QFontMetrics fm = painter_->fontMetrics();
+ int yPos = ((itemHeight - fm.height()) / 2) + fm.ascent();
+ painter_->drawText(3, yPos, text());
+}
diff --git a/src/gui/listboxtext.h b/src/gui/listboxtext.h
new file mode 100644
index 0000000..3cfe2db
--- /dev/null
+++ b/src/gui/listboxtext.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TELLICO_GUI_LISTBOXTEXT_H
+#define TELLICO_GUI_LISTBOXTEXT_H
+
+#include <qlistbox.h>
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * ListBoxText subclasses QListBoxText so that @ref setText() can be made public,
+ * and the font color can be changed
+ *
+ * @author Robby Stephenson
+ */
+class ListBoxText : public QListBoxText {
+public:
+ ListBoxText(QListBox* listbox, const QString& text);
+ ListBoxText(QListBox* listbox, const QString& text, QListBoxItem* after);
+
+ virtual int width(const QListBox* box) const;
+ virtual int height(const QListBox* box) const;
+
+ bool isColored() const { return m_colored; }
+ void setColored(bool colored);
+ void setText(const QString& text);
+
+protected:
+ virtual void paint(QPainter* painter);
+
+private:
+ bool m_colored;
+};
+
+ } // end namespace
+} // end namespace
+
+#endif
diff --git a/src/gui/listview.cpp b/src/gui/listview.cpp
new file mode 100644
index 0000000..d93174c
--- /dev/null
+++ b/src/gui/listview.cpp
@@ -0,0 +1,347 @@
+/***************************************************************************
+ copyright : (C) 2001-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "listview.h"
+#include "../controller.h"
+#include "../tellico_utils.h"
+#include "../tellico_debug.h"
+
+#include <kapplication.h>
+
+#include <qpainter.h>
+#include <qpixmap.h>
+#include <qheader.h>
+
+using Tellico::GUI::ListView;
+using Tellico::GUI::ListViewItem;
+
+ListView::ListView(QWidget* parent_, const char* name_) : KListView(parent_, name_/*=0*/),
+ m_sortStyle(SortByText), m_isClear(true) {
+ setSelectionMode(QListView::Extended);
+ connect(this, SIGNAL(selectionChanged()),
+ SLOT(slotSelectionChanged()));
+ connect(this, SIGNAL(doubleClicked(QListViewItem*)),
+ SLOT(slotDoubleClicked(QListViewItem*)));
+#if !KDE_IS_VERSION(3,3,90)
+ m_shadeSortColumn = false;
+ // call it once to initialize
+ slotUpdateColors();
+#endif
+ connect(kapp, SIGNAL(kdisplayPaletteChanged()), SLOT(slotUpdateColors()));
+ m_comparisons.setAutoDelete(true);
+}
+
+ListView::~ListView() {
+}
+
+void ListView::clearSelection() {
+ if(m_selectedItems.isEmpty()) {
+ // nothing to do;
+ return;
+ }
+ bool b = signalsBlocked();
+ blockSignals(true);
+ selectAll(false);
+ blockSignals(b);
+ emit selectionChanged();
+}
+
+void ListView::updateSelected(ListViewItem* item_, bool selected_) {
+ if(selected_) {
+ m_selectedItems.append(item_);
+ } else {
+ m_selectedItems.removeRef(item_);
+ }
+}
+
+bool ListView::isSelectable(ListViewItem* item_) const {
+ // don't allow hidden items to be selected
+ if(!item_->isVisible()) {
+ return false;
+ }
+
+ // selecting multiple items is ok
+ // only when parent is open. Be careful to check for existence of parent
+ if(item_->parent() && !item_->parent()->isOpen()) {
+ return false;
+ }
+
+ // just selecting a single item is always ok
+ if(m_selectedItems.isEmpty()) {
+ return true;
+ }
+
+ // not allowed is something other than an entry is selected and current is entry
+ if(m_selectedItems.getFirst()->isEntryItem() != item_->isEntryItem()) {
+ return false;
+ }
+
+ return true;
+}
+
+int ListView::firstVisibleColumn() const {
+ int col = 0;
+ while(col < columns() && columnWidth(header()->mapToSection(col)) == 0) {
+ ++col;
+ }
+ if(col == columns()) {
+ return -1;
+ }
+ return header()->mapToSection(col);
+}
+
+int ListView::lastVisibleColumn() const {
+ int col = columns()-1;
+ while(col < columns() && columnWidth(header()->mapToSection(col)) == 0) {
+ --col;
+ }
+ if(col == columns()) {
+ return -1;
+ }
+ return header()->mapToSection(col);
+}
+
+void ListView::setColumnText(int column, const QString& label) {
+ ListViewComparison* comp = m_comparisons.take(columnText(column));
+ KListView::setColumnText(column, label);
+ if(comp) {
+ m_comparisons.insert(columnText(column), comp);
+ }
+}
+
+void ListView::setComparison(int column, ListViewComparison* comp) {
+ if(comp) {
+ m_comparisons.replace(columnText(column), comp);
+ }
+}
+
+void ListView::removeComparison(int column) {
+ m_comparisons.remove(columnText(column));
+}
+
+void ListView::clearComparisons() {
+ m_comparisons.clear();
+}
+
+int ListView::compare(int col, const GUI::ListViewItem* item1, GUI::ListViewItem* item2, bool asc) {
+ if(col >= 0 && col < static_cast<int>(m_comparisons.count())) {
+ ListViewComparison* com = m_comparisons.find(columnText(col));
+ if(com) {
+ return com->compare(col, item1, item2, asc);
+ }
+ }
+ return 0;
+}
+
+#if !KDE_IS_VERSION(3,3,90)
+void ListView::setShadeSortColumn(bool shade_) {
+ if(m_shadeSortColumn != shade_) {
+ m_shadeSortColumn = shade_;
+ repaint();
+ }
+}
+#endif
+
+void ListView::slotUpdateColors() {
+#if !KDE_IS_VERSION(3,3,90)
+ m_backColor2 = viewport()->colorGroup().base();
+ if(m_backColor2 == Qt::black) {
+ m_backColor2 = QColor(50, 50, 50); // dark gray
+ } else {
+ int h,s,v;
+ m_backColor2.hsv(&h, &s, &v);
+ if(v > 175) {
+ m_backColor2 = m_backColor2.dark(105);
+ } else {
+ m_backColor2 = m_backColor2.light(120);
+ }
+ }
+
+ m_altColor2 = alternateBackground();
+ if(m_altColor2 == Qt::black) {
+ m_altColor2 = QColor(50, 50, 50); // dark gray
+ } else {
+ int h,s,v;
+ m_altColor2.hsv(&h, &s, &v);
+ if(v > 175) {
+ m_altColor2 = m_altColor2.dark(105);
+ } else {
+ m_altColor2 = m_altColor2.light(120);
+ }
+ }
+#endif
+ Tellico::updateContrastColor(viewport()->colorGroup());
+ repaint();
+}
+
+void ListView::slotSelectionChanged() {
+ if(m_selectedItems.isEmpty()) {
+ if(m_isClear) {
+ return; // nothing to do
+ }
+ m_isClear = true;
+ Controller::self()->slotClearSelection();
+ return;
+ }
+ m_isClear = false;
+
+ Data::EntryVec entries;
+ // now just find all the children or grandchildren that are entry items
+ for(GUI::ListViewItemListIt it(m_selectedItems); it.current(); ++it) {
+ Data::EntryVec more = it.current()->entries();
+ for(Data::EntryVecIt entry = more.begin(); entry != more.end(); ++entry) {
+ if(!entries.contains(entry)) {
+ entries.append(entry);
+ }
+ }
+ }
+// Controller::self()->slotUpdateCurrent(entries); // just update current, don't change selection
+ Controller::self()->slotUpdateSelection(this, entries);
+}
+
+void ListView::slotDoubleClicked(QListViewItem* item_) {
+ if(!item_) {
+ return;
+ }
+
+ // if it has children, just open it
+ // but some items delay children creation
+ if(static_cast<ListViewItem*>(item_)->realChildCount() > 0) {
+ item_->setOpen(!item_->isOpen());
+ }
+
+ GUI::ListViewItem* item = static_cast<GUI::ListViewItem*>(item_);
+ item->doubleClicked();
+}
+
+void ListView::drawContentsOffset(QPainter* p, int ox, int oy, int cx, int cy, int cw, int ch) {
+ bool oldUpdatesEnabled = isUpdatesEnabled();
+ setUpdatesEnabled(false);
+ KListView::drawContentsOffset(p, ox, oy, cx, cy, cw, ch);
+ setUpdatesEnabled(oldUpdatesEnabled);
+}
+
+/* ****************** ListViewItem ********************* */
+
+ListViewItem::~ListViewItem() {
+ // I think there's a bug in qt where the children of this item are deleted after the item itself
+ // as a result, there is no listView() pointer for the children, that obvious causes
+ // a problem with updating the selection. So we MUST call clear() here ourselves!
+ clear();
+ // be sure to remove from selected list when it's deleted
+ ListView* lv = listView();
+ if(lv) {
+ lv->updateSelected(this, false);
+ }
+}
+
+void ListViewItem::clear() {
+ QListViewItem* item = firstChild();
+ while(item) {
+ delete item;
+ item = firstChild();
+ }
+}
+
+int ListViewItem::compare(QListViewItem* item_, int col_, bool asc_) const {
+ int res = compareWeight(item_, col_, asc_);
+ if(res != 0) {
+ return res;
+ }
+ res = listView()->compare(col_, this, static_cast<GUI::ListViewItem*>(item_), asc_);
+ return res == 0 ? KListViewItem::compare(item_, col_, asc_) : res;
+}
+
+int ListViewItem::compareWeight(QListViewItem* item_, int col_, bool asc_) const {
+ Q_UNUSED(col_);
+ // I want the sorting to be independent of sort order
+ GUI::ListViewItem* i = static_cast<GUI::ListViewItem*>(item_);
+ int res = 0;
+ if(m_sortWeight < i->sortWeight()) {
+ res = -1;
+ } else if(m_sortWeight > i->sortWeight()) {
+ res = 1;
+ }
+ if(asc_) {
+ res *= -1; // reverse, heavier weights will come first always
+ }
+ return res;
+}
+
+void ListViewItem::setSelected(bool s_) {
+ ListView* lv = listView();
+ if(!lv) {
+ return;
+ }
+ if(s_ && !lv->isSelectable(this)) {
+ return;
+ }
+ if(s_ != isSelected()) {
+ lv->updateSelected(this, s_);
+ KListViewItem::setSelected(s_);
+ }
+}
+
+QColor ListViewItem::backgroundColor(int column_) {
+#if KDE_IS_VERSION(3,3,90)
+ return KListViewItem::backgroundColor(column_);
+#else
+ ListView* view = listView();
+ if(view->columns() > 1 && view->shadeSortColumn() && column_ == view->sortColumn()) {
+ return isAlternate() ? view->alternateBackground2() : view->background2();
+ }
+ return isAlternate() ? view->alternateBackground() : view->viewport()->colorGroup().base();
+#endif
+}
+
+void ListViewItem::paintCell(QPainter* p_, const QColorGroup& cg_,
+ int column_, int width_, int align_) {
+ // taken from klistview.cpp
+ // I can't call KListViewItem::paintCell since KListViewItem::backgroundCOlor(int) is
+ // not virtual. I need to be sure to call ListViewItem::backgroundColor(int);
+ QColorGroup cg = cg_;
+ const QPixmap* pm = listView()->viewport()->backgroundPixmap();
+ if(pm && !pm->isNull()) {
+ cg.setBrush(QColorGroup::Base, QBrush(backgroundColor(column_), *pm));
+ QPoint o = p_->brushOrigin();
+ p_->setBrushOrigin(o.x()-listView()->contentsX(), o.y()-listView()->contentsY());
+ } else {
+ cg.setColor(listView()->viewport()->backgroundMode() == Qt::FixedColor ?
+ QColorGroup::Background : QColorGroup::Base,
+ backgroundColor(column_));
+ }
+
+ // don't call KListViewItem::paintCell() since that also does alternate painting, etc...
+ QListViewItem::paintCell(p_, cg, column_, width_, align_);
+
+ // borrowed from amarok, draw line to left of cell
+ if(!isSelected()) {
+ p_->setPen(QPen(listView()->alternateBackground(), 0, Qt::SolidLine));
+ p_->drawLine(width_-1, 0, width_-1, height()-1);
+ }
+}
+
+Tellico::Data::EntryVec ListViewItem::entries() const {
+ Data::EntryVec entries;
+ for(QListViewItem* child = firstChild(); child; child = child->nextSibling()) {
+ Data::EntryVec more = static_cast<GUI::ListViewItem*>(child)->entries();
+ for(Data::EntryVecIt entry = more.begin(); entry != more.end(); ++entry) {
+ if(!entries.contains(entry)) {
+ entries.append(entry);
+ }
+ }
+ }
+ return entries;
+}
+
+#include "listview.moc"
diff --git a/src/gui/listview.h b/src/gui/listview.h
new file mode 100644
index 0000000..4c5ade7
--- /dev/null
+++ b/src/gui/listview.h
@@ -0,0 +1,180 @@
+/***************************************************************************
+ copyright : (C) 2001-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TELLICO_LISTVIEW_H
+#define TELLICO_LISTVIEW_H
+
+#include "../datavectors.h"
+#include "../listviewcomparison.h"
+
+#include <klistview.h>
+#include <kdeversion.h>
+
+#include <qdict.h>
+
+namespace Tellico {
+ class ListViewComparison;
+ namespace GUI {
+
+class ListViewItem;
+typedef QPtrList<ListViewItem> ListViewItemList;
+typedef QPtrListIterator<ListViewItem> ListViewItemListIt;
+
+/**
+ * A ListView keeps track of the selected items and allows subclasses to determine
+ * whether child items may be selected or not. In addition, it provides alternating
+ * background colors and shaded sort columns.
+ *
+ * @see GroupView
+ * @see DetailedListView
+ *
+ * @author Robby Stephenson
+ */
+class ListView : public KListView {
+Q_OBJECT
+
+friend class ListViewItem; // needed so the ListViewItem d'tor can update selection list
+
+public:
+ enum SortStyle {
+ SortByText = 0, // don't change these values, they're saved as ints in the config
+ SortByCount = 1
+ };
+
+ ListView(QWidget* parent, const char* name = 0);
+ virtual ~ListView();
+
+ void clearSelection();
+ /**
+ * Returns a list of the currently selected items;
+ *
+ * @return The list of selected items
+ */
+ const ListViewItemList& selectedItems() const { return m_selectedItems; }
+ /**
+ * Used to determine whether an item may be selected without having to setSelectable on
+ * every child item.
+ *
+ * @return Whether the item may be selected
+ */
+ virtual bool isSelectable(ListViewItem*) const;
+ SortStyle sortStyle() const { return m_sortStyle; }
+ void setSortStyle(SortStyle style) { m_sortStyle = style; }
+
+ int firstVisibleColumn() const;
+ int lastVisibleColumn() const;
+
+ virtual void setColumnText(int column, const QString& label);
+
+ void setComparison(int column, ListViewComparison* comp);
+ void removeComparison(int column);
+ void clearComparisons();
+ virtual int compare(int col, const GUI::ListViewItem* item1, GUI::ListViewItem* item2, bool asc);
+
+#if !KDE_IS_VERSION(3,3,90)
+ // taken from KDE bug 59791
+ void setShadeSortColumn(bool shade_);
+ bool shadeSortColumn() const { return m_shadeSortColumn; }
+ const QColor& background2() const { return m_backColor2; }
+ const QColor& alternateBackground2() const { return m_altColor2; }
+#endif
+
+protected slots:
+ /**
+ * Handles everything when an item is selected. The proper signal is emitted, depending
+ * on whether the item refers to a collection, a group, or a entry.
+ */
+ virtual void slotSelectionChanged();
+
+protected:
+ virtual void drawContentsOffset(QPainter* p, int ox, int oy, int cx, int cy, int cw, int ch);
+
+private slots:
+ void slotUpdateColors();
+ void slotDoubleClicked(QListViewItem* item);
+
+private:
+ /**
+ * Updates the pointer list.
+ *
+ * @param item The item being selected or deselected
+ * @param s Selected or not
+ */
+ void updateSelected(ListViewItem* item, bool s);
+
+ SortStyle m_sortStyle;
+ bool m_isClear;
+ ListViewItemList m_selectedItems;
+ QDict<ListViewComparison> m_comparisons;
+#if !KDE_IS_VERSION(3,3,90)
+ bool m_shadeSortColumn;
+ QColor m_backColor2;
+ QColor m_altColor2;
+#endif
+};
+
+/**
+ * The ListViewItem keeps track of what kind of specialized listview item it is, as
+ * well as taking care of the selection tracking.
+ *
+ * @author Robby Stephenson
+ */
+class ListViewItem : public KListViewItem {
+public:
+ ListViewItem(ListView* parent) : KListViewItem(parent), m_sortWeight(-1) {}
+ ListViewItem(ListView* parent, QListViewItem* after) : KListViewItem(parent, after), m_sortWeight(-1) {}
+ ListViewItem(ListViewItem* parent) : KListViewItem(parent), m_sortWeight(-1) {}
+ ListViewItem(ListView* parent, const QString& text) : KListViewItem(parent, text), m_sortWeight(-1) {}
+ ListViewItem(ListViewItem* parent, const QString& text) : KListViewItem(parent, text), m_sortWeight(-1) {}
+ virtual ~ListViewItem();
+
+ virtual int realChildCount() const { return childCount(); }
+ virtual void clear();
+
+ virtual bool isEntryGroupItem() const { return false; }
+ virtual bool isEntryItem() const { return false; }
+ virtual bool isFilterItem() const { return false; }
+ virtual bool isBorrowerItem() const { return false; }
+ virtual bool isLoanItem() const { return false; }
+
+ int sortWeight() const { return m_sortWeight; }
+ void setSortWeight(int w) { m_sortWeight = w; }
+ virtual int compare(QListViewItem* item, int col, bool ascending) const;
+
+ virtual void setSelected(bool selected);
+ /**
+ * Returns the background color for the column, which depends on whether the item
+ * is an alternate row and whether the column is selected.
+ *
+ * @param column The column number
+ * @param alternate The alternate row color can be forced
+ */
+ virtual QColor backgroundColor(int column); // not virtual in KListViewItem!!!
+ virtual void paintCell(QPainter* painter, const QColorGroup& colorGroup,
+ int column, int width, int alignment);
+
+ ListView* listView () const { return static_cast<ListView*>(KListViewItem::listView()); }
+
+ virtual void doubleClicked() {}
+ virtual Data::EntryVec entries() const;
+
+private:
+ int compareWeight(QListViewItem* item, int col, bool ascending) const;
+
+ int m_sortWeight;
+};
+
+ } // end namespace
+} // end namespace
+
+#endif
diff --git a/src/gui/numberfieldwidget.cpp b/src/gui/numberfieldwidget.cpp
new file mode 100644
index 0000000..027b1e9
--- /dev/null
+++ b/src/gui/numberfieldwidget.cpp
@@ -0,0 +1,143 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "numberfieldwidget.h"
+#include "datewidget.h"
+#include "../field.h"
+
+#include <klineedit.h>
+
+#include <qlayout.h>
+#include <qvalidator.h>
+
+using Tellico::GUI::NumberFieldWidget;
+
+NumberFieldWidget::NumberFieldWidget(Data::FieldPtr field_, QWidget* parent_, const char* name_/*=0*/)
+ : FieldWidget(field_, parent_, name_), m_lineEdit(0), m_spinBox(0) {
+
+ if(field_->flags() & Data::Field::AllowMultiple) {
+ initLineEdit();
+ } else {
+ initSpinBox();
+ }
+
+ registerWidget();
+}
+
+void NumberFieldWidget::initLineEdit() {
+ m_lineEdit = new KLineEdit(this);
+ connect(m_lineEdit, SIGNAL(textChanged(const QString&)), SIGNAL(modified()));
+ // connect(kl, SIGNAL(returnPressed(const QString&)), this, SLOT(slotHandleReturn()));
+
+ // regexp is any number of digits followed optionally by any number of
+ // groups of a semi-colon followed optionally by a space, followed by digits
+ QRegExp rx(QString::fromLatin1("-?\\d*(; ?-?\\d*)*"));
+ m_lineEdit->setValidator(new QRegExpValidator(rx, this));
+}
+
+void NumberFieldWidget::initSpinBox() {
+ // intentionally allow only positive numbers
+ m_spinBox = new GUI::SpinBox(-1, INT_MAX, this);
+ connect(m_spinBox, SIGNAL(valueChanged(int)), SIGNAL(modified()));
+ // QSpinBox doesn't emit valueChanged if you edit the value with
+ // the lineEdit until you change the keyboard focus
+ connect(m_spinBox->child("qt_spinbox_edit"), SIGNAL(textChanged(const QString&)), SIGNAL(modified()));
+ // I want to allow no value, so set space as special text. Empty text is ignored
+ m_spinBox->setSpecialValueText(QChar(' '));
+}
+
+QString NumberFieldWidget::text() const {
+ if(isSpinBox()) {
+ // minValue = special empty text
+ if(m_spinBox->value() > m_spinBox->minValue()) {
+ return QString::number(m_spinBox->value());
+ }
+ return QString();
+ }
+
+ QString text = m_lineEdit->text();
+ if(field()->flags() & Data::Field::AllowMultiple) {
+ text.replace(s_semiColon, QString::fromLatin1("; "));
+ }
+ return text.simplifyWhiteSpace();
+}
+
+void NumberFieldWidget::setText(const QString& text_) {
+ blockSignals(true);
+
+ if(isSpinBox()) {
+ bool ok;
+ int n = text_.toInt(&ok);
+ if(ok) {
+ // did just allow positive
+ if(n < 0) {
+ m_spinBox->setMinValue(INT_MIN+1);
+ }
+ m_spinBox->blockSignals(true);
+ m_spinBox->setValue(n);
+ m_spinBox->blockSignals(false);
+ }
+ } else {
+ m_lineEdit->blockSignals(true);
+ m_lineEdit->setText(text_);
+ m_lineEdit->blockSignals(false);
+ }
+
+ blockSignals(false);
+}
+
+void NumberFieldWidget::clear() {
+ if(isSpinBox()) {
+ // show empty special value text
+ m_spinBox->setValue(m_spinBox->minValue());
+ } else {
+ m_lineEdit->clear();
+ }
+ editMultiple(false);
+}
+
+void NumberFieldWidget::updateFieldHook(Data::FieldPtr, Data::FieldPtr newField_) {
+ bool wasLineEdit = !isSpinBox();
+ bool nowLineEdit = newField_->flags() & Data::Field::AllowMultiple;
+
+ if(wasLineEdit == nowLineEdit) {
+ return;
+ }
+
+ QString value = text();
+ if(wasLineEdit && !nowLineEdit) {
+ layout()->remove(m_lineEdit);
+ delete m_lineEdit;
+ m_lineEdit = 0;
+ initSpinBox();
+ } else if(!wasLineEdit && nowLineEdit) {
+ layout()->remove(m_spinBox);
+ delete m_spinBox;
+ m_spinBox = 0;
+ initLineEdit();
+ }
+
+ // should really be FIELD_EDIT_WIDGET_INDEX from fieldwidget.cpp
+ static_cast<QBoxLayout*>(layout())->insertWidget(2, widget(), 1 /*stretch*/);
+ widget()->show();
+ setText(value);
+}
+
+QWidget* NumberFieldWidget::widget() {
+ if(isSpinBox()) {
+ return m_spinBox;
+ }
+ return m_lineEdit;
+}
+
+#include "numberfieldwidget.moc"
diff --git a/src/gui/numberfieldwidget.h b/src/gui/numberfieldwidget.h
new file mode 100644
index 0000000..c0fed9d
--- /dev/null
+++ b/src/gui/numberfieldwidget.h
@@ -0,0 +1,57 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef NUMBERFIELDWIDGET_H
+#define NUMBERFIELDWIDGET_H
+
+class KLineEdit;
+
+#include "fieldwidget.h"
+#include "../datavectors.h"
+
+namespace Tellico {
+ namespace GUI {
+ class SpinBox;
+
+/**
+ * @author Robby Stephenson
+ */
+class NumberFieldWidget : public FieldWidget {
+Q_OBJECT
+
+public:
+ NumberFieldWidget(Data::FieldPtr field, QWidget* parent, const char* name=0);
+ virtual ~NumberFieldWidget() {}
+
+ virtual QString text() const;
+ virtual void setText(const QString& text);
+
+public slots:
+ virtual void clear();
+
+protected:
+ virtual QWidget* widget();
+ virtual void updateFieldHook(Data::FieldPtr oldField, Data::FieldPtr newField);
+
+private:
+ bool isSpinBox() const { return (m_spinBox != 0); }
+ void initLineEdit();
+ void initSpinBox();
+
+ KLineEdit* m_lineEdit;
+ SpinBox* m_spinBox;
+};
+
+ } // end GUI namespace
+} // end namespace
+#endif
diff --git a/src/gui/overlaywidget.cpp b/src/gui/overlaywidget.cpp
new file mode 100644
index 0000000..6214ca8
--- /dev/null
+++ b/src/gui/overlaywidget.cpp
@@ -0,0 +1,104 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "overlaywidget.h"
+
+#include <qlayout.h>
+
+using Tellico::GUI::OverlayWidget;
+
+OverlayWidget::OverlayWidget(QWidget* parent, QWidget* anchor) : QFrame(parent)
+ , m_anchor(anchor)
+ , m_corner(TopRight) {
+ m_anchor->installEventFilter(this);
+ reposition();
+ hide();
+}
+
+void OverlayWidget::setCorner(Corner corner_) {
+ if(corner_ == m_corner) {
+ return;
+ }
+ m_corner = corner_;
+ reposition();
+}
+
+void OverlayWidget::addWidget(QWidget* widget_) {
+ layout()->add(widget_);
+ adjustSize();
+}
+
+void OverlayWidget::reposition() {
+ if(!m_anchor) {
+ return;
+ }
+
+ setMaximumSize(parentWidget()->size());
+ adjustSize();
+
+ QPoint p;
+
+ switch(m_corner) {
+ case BottomLeft:
+ p.setX(0);
+ p.setY(m_anchor->height());
+ break;
+
+ case BottomRight:
+ p.setX(m_anchor->width() - width());
+ p.setY(m_anchor->height());
+ break;
+
+ case TopLeft:
+ p.setX(0);
+ p.setY(-1 * height());
+ break;
+
+ case TopRight:
+ p.setX(m_anchor->width() - width());
+ p.setY(-1 * height());
+ }
+
+ // Position in the toplevelwidget's coordinates
+ QPoint pTopLevel = m_anchor->mapTo(topLevelWidget(), p);
+ // Position in the widget's parentWidget coordinates
+ QPoint pParent = parentWidget()->mapFrom(topLevelWidget(), pTopLevel);
+ // keep it on the screen
+ if(pParent.x() < 0) {
+ pParent.rx() = 0;
+ }
+ move(pParent);
+}
+
+bool OverlayWidget::eventFilter(QObject* object_, QEvent* event_) {
+ if(object_ == m_anchor && (event_->type() == QEvent::Move || event_->type() == QEvent::Resize)) {
+ reposition();
+ }
+
+ return QFrame::eventFilter(object_, event_);
+}
+
+void OverlayWidget::resizeEvent(QResizeEvent* event_) {
+ reposition();
+ QFrame::resizeEvent(event_);
+}
+
+bool OverlayWidget::event(QEvent* event_) {
+ if(event_->type() == QEvent::ChildInserted) {
+ adjustSize();
+ }
+
+ return QFrame::event(event_);
+}
+
+#include "overlaywidget.moc"
diff --git a/src/gui/overlaywidget.h b/src/gui/overlaywidget.h
new file mode 100644
index 0000000..7b4453e
--- /dev/null
+++ b/src/gui/overlaywidget.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+// much of this code is adapted from libkdepim
+// which is GPL licensed, Copyright (c) 2004 David Faure
+
+#ifndef TELLICO_GUI_OVERLAYWIDGET_H
+#define TELLICO_GUI_OVERLAYWIDGET_H
+
+#include <qframe.h>
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * @author Robby Stephenson
+ */
+class OverlayWidget : public QFrame {
+Q_OBJECT
+
+public:
+ OverlayWidget(QWidget* parent, QWidget* anchor);
+
+ void setCorner(Corner corner);
+ Corner corner() const { return m_corner; }
+
+ void addWidget(QWidget* widget);
+
+protected:
+ void resizeEvent(QResizeEvent* event);
+ bool eventFilter(QObject* object, QEvent* event);
+ bool event(QEvent* event);
+
+private:
+ void reposition();
+
+ QWidget* m_anchor;
+ Corner m_corner;
+};
+
+ } // end namespace
+} // end namespace
+
+#endif
diff --git a/src/gui/parafieldwidget.cpp b/src/gui/parafieldwidget.cpp
new file mode 100644
index 0000000..9941e34
--- /dev/null
+++ b/src/gui/parafieldwidget.cpp
@@ -0,0 +1,63 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "parafieldwidget.h"
+#include "../field.h"
+#include "../latin1literal.h"
+
+#include <ktextedit.h>
+
+using Tellico::GUI::ParaFieldWidget;
+
+ParaFieldWidget::ParaFieldWidget(Data::FieldPtr field_, QWidget* parent_, const char* name_/*=0*/)
+ : FieldWidget(field_, parent_, name_) {
+
+ m_textEdit = new KTextEdit(this);
+ m_textEdit->setTextFormat(Qt::PlainText);
+ if(field_->property(QString::fromLatin1("spellcheck")) != Latin1Literal("false")) {
+ m_textEdit->setCheckSpellingEnabled(true);
+ }
+ connect(m_textEdit, SIGNAL(textChanged()), SIGNAL(modified()));
+
+ registerWidget();
+}
+
+QString ParaFieldWidget::text() const {
+ QString text = m_textEdit->text();
+ text.replace('\n', QString::fromLatin1("<br/>"));
+ return text;
+}
+
+void ParaFieldWidget::setText(const QString& text_) {
+ blockSignals(true);
+ m_textEdit->blockSignals(true);
+
+ QRegExp rx(QString::fromLatin1("<br/?>"), false /*case-sensitive*/);
+ QString s = text_;
+ s.replace(rx, QChar('\n'));
+ m_textEdit->setText(s);
+
+ m_textEdit->blockSignals(false);
+ blockSignals(false);
+}
+
+void ParaFieldWidget::clear() {
+ m_textEdit->clear();
+ editMultiple(false);
+}
+
+QWidget* ParaFieldWidget::widget() {
+ return m_textEdit;
+}
+
+#include "parafieldwidget.moc"
diff --git a/src/gui/parafieldwidget.h b/src/gui/parafieldwidget.h
new file mode 100644
index 0000000..ac9801f
--- /dev/null
+++ b/src/gui/parafieldwidget.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef PARAFIELDWIDGET_H
+#define PARAFIELDWIDGET_H
+
+#include "fieldwidget.h"
+#include "../datavectors.h"
+
+class KTextEdit;
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * @author Robby Stephenson
+ */
+class ParaFieldWidget : public FieldWidget {
+Q_OBJECT
+
+public:
+ ParaFieldWidget(Data::FieldPtr field, QWidget* parent, const char* name=0);
+ virtual ~ParaFieldWidget() {}
+
+ virtual QString text() const;
+ virtual void setText(const QString& text);
+
+public slots:
+ virtual void clear();
+
+protected:
+ virtual QWidget* widget();
+
+private:
+ KTextEdit* m_textEdit;
+};
+
+ } // end GUI namespace
+} // end namespace
+#endif
diff --git a/src/gui/previewdialog.cpp b/src/gui/previewdialog.cpp
new file mode 100644
index 0000000..4c0d8e1
--- /dev/null
+++ b/src/gui/previewdialog.cpp
@@ -0,0 +1,56 @@
+/***************************************************************************
+ copyright : (C) 2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "previewdialog.h"
+#include "../entryview.h"
+#include "../entry.h"
+#include "../imagefactory.h" // for StyleOptions
+
+#include <klocale.h>
+#include <ktempdir.h>
+#include <khtmlview.h>
+
+using Tellico::GUI::PreviewDialog;
+
+PreviewDialog::PreviewDialog(QWidget* parent_)
+ : KDialogBase(parent_, "template preview dialog", false /* modal */,
+ i18n("Template Preview"), KDialogBase::Ok)
+ , m_tempDir(new KTempDir()) {
+ m_tempDir->setAutoDelete(true);
+ connect(this, SIGNAL(finished()), SLOT(delayedDestruct()));
+
+ m_view = new EntryView(this);
+ setMainWidget(m_view->view());
+ setInitialSize(QSize(600, 500));
+}
+
+PreviewDialog::~PreviewDialog() {
+ delete m_tempDir;
+ m_tempDir = 0;
+}
+
+void PreviewDialog::setXSLTFile(const QString& file_) {
+ m_view->setXSLTFile(file_);
+}
+
+void PreviewDialog::setXSLTOptions(StyleOptions options_) {
+ options_.imgDir = m_tempDir->name(); // images always get written to temp dir
+ ImageFactory::createStyleImages(options_);
+ m_view->setXSLTOptions(options_);
+}
+
+void PreviewDialog::showEntry(Data::EntryPtr entry_) {
+ m_view->showEntry(entry_);
+}
+
+#include "previewdialog.moc"
diff --git a/src/gui/previewdialog.h b/src/gui/previewdialog.h
new file mode 100644
index 0000000..a386a94
--- /dev/null
+++ b/src/gui/previewdialog.h
@@ -0,0 +1,47 @@
+/***************************************************************************
+ copyright : (C) 2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TELLICO_GUI_PREVIEWDIALOG_H
+#define TELLICO_GUI_PREVIEWDIALOG_H
+
+#include <kdialogbase.h>
+
+#include "../datavectors.h"
+
+class KTempDir;
+
+namespace Tellico {
+ class EntryView;
+ class StyleOptions;
+
+ namespace GUI {
+
+class PreviewDialog : public KDialogBase {
+Q_OBJECT
+
+public:
+ PreviewDialog(QWidget* parent);
+ ~PreviewDialog();
+
+ void setXSLTFile(const QString& file);
+ void setXSLTOptions(StyleOptions options);
+ void showEntry(Data::EntryPtr entry);
+
+private:
+ KTempDir* m_tempDir;
+ EntryView* m_view;
+};
+
+ }
+}
+#endif
diff --git a/src/gui/progress.cpp b/src/gui/progress.cpp
new file mode 100644
index 0000000..36baaf1
--- /dev/null
+++ b/src/gui/progress.cpp
@@ -0,0 +1,33 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "progress.h"
+#include "../tellico_debug.h"
+
+using Tellico::GUI::Progress;
+
+Progress::Progress(QWidget* parent_) : KProgress(parent_) {
+}
+
+Progress::Progress(int totalSteps_, QWidget* parent_) : KProgress(totalSteps_, parent_) {
+}
+
+bool Progress::isDone() const {
+ return progress() == totalSteps();
+}
+
+void Progress::setDone() {
+ setProgress(totalSteps());
+}
+
+#include "progress.moc"
diff --git a/src/gui/progress.h b/src/gui/progress.h
new file mode 100644
index 0000000..b58de2f
--- /dev/null
+++ b/src/gui/progress.h
@@ -0,0 +1,39 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TELLICO_GUI_PROGRESS_H
+#define TELLICO_GUI_PROGRESS_H
+
+#include <kprogress.h>
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * @author Robby Stephenson
+ */
+class Progress : public KProgress {
+Q_OBJECT
+
+public:
+ Progress(QWidget* parent);
+ Progress(int totalSteps, QWidget* parent);
+
+ bool isDone() const;
+ void setDone();
+};
+
+ } // end namespace
+} // end namespace
+
+#endif
diff --git a/src/gui/ratingfieldwidget.cpp b/src/gui/ratingfieldwidget.cpp
new file mode 100644
index 0000000..4b0de71
--- /dev/null
+++ b/src/gui/ratingfieldwidget.cpp
@@ -0,0 +1,59 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "ratingfieldwidget.h"
+#include "ratingwidget.h"
+#include "../field.h"
+
+using Tellico::GUI::RatingFieldWidget;
+
+RatingFieldWidget::RatingFieldWidget(Data::FieldPtr field_, QWidget* parent_, const char* name_/*=0*/)
+ : FieldWidget(field_, parent_, name_) {
+ m_rating = new RatingWidget(field_, this);
+ connect(m_rating, SIGNAL(modified()), SIGNAL(modified()));
+
+ registerWidget();
+}
+
+QString RatingFieldWidget::text() const {
+ return m_rating->text();
+}
+
+void RatingFieldWidget::setText(const QString& text_) {
+ blockSignals(true);
+
+ m_rating->blockSignals(true);
+ m_rating->setText(text_);
+ m_rating->blockSignals(false);
+
+ blockSignals(false);
+
+ if(m_rating->text() != text_) {
+ emit modified();
+ }
+}
+
+void RatingFieldWidget::clear() {
+ m_rating->clear();
+ editMultiple(false);
+}
+
+void RatingFieldWidget::updateFieldHook(Data::FieldPtr, Data::FieldPtr newField_) {
+ m_rating->updateField(newField_);
+}
+
+QWidget* RatingFieldWidget::widget() {
+ return m_rating;
+}
+
+#include "ratingfieldwidget.moc"
diff --git a/src/gui/ratingfieldwidget.h b/src/gui/ratingfieldwidget.h
new file mode 100644
index 0000000..369dbec
--- /dev/null
+++ b/src/gui/ratingfieldwidget.h
@@ -0,0 +1,50 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef RATINGFIELDWIDGET_H
+#define RATINGFIELDWIDGET_H
+
+#include "fieldwidget.h"
+#include "../datavectors.h"
+
+namespace Tellico {
+ namespace GUI {
+ class RatingWidget;
+
+/**
+ * @author Robby Stephenson
+ */
+class RatingFieldWidget : public FieldWidget {
+Q_OBJECT
+
+public:
+ RatingFieldWidget(Data::FieldPtr field, QWidget* parent, const char* name=0);
+ virtual ~RatingFieldWidget() {}
+
+ virtual QString text() const;
+ virtual void setText(const QString& text);
+
+public slots:
+ virtual void clear();
+
+protected:
+ virtual QWidget* widget();
+ virtual void updateFieldHook(Data::FieldPtr oldField, Data::FieldPtr newField);
+
+private:
+ RatingWidget* m_rating;
+};
+
+ } // end GUI namespace
+} // end namespace
+#endif
diff --git a/src/gui/ratingwidget.cpp b/src/gui/ratingwidget.cpp
new file mode 100644
index 0000000..4921f21
--- /dev/null
+++ b/src/gui/ratingwidget.cpp
@@ -0,0 +1,170 @@
+/***************************************************************************
+ copyright : (C) 2003-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "ratingwidget.h"
+#include "../field.h"
+#include "../latin1literal.h"
+#include "../tellico_utils.h"
+#include "../tellico_debug.h"
+
+#include <kiconloader.h>
+
+#include <qintdict.h>
+#include <qlayout.h>
+
+namespace {
+ static const int RATING_WIDGET_MAX_ICONS = 10; // same as in Field::ratingValues()
+ static const int RATING_WIDGET_MAX_STAR_SIZE = 24;
+}
+
+using Tellico::GUI::RatingWidget;
+
+const QPixmap& RatingWidget::pixmap(const QString& value_) {
+ static QIntDict<QPixmap> pixmaps;
+ if(pixmaps.isEmpty()) {
+ pixmaps.insert(-1, new QPixmap());
+ }
+ bool ok;
+ int n = Tellico::toUInt(value_, &ok);
+ if(!ok || n < 1 || n > 10) {
+ return *pixmaps[-1];
+ }
+ if(pixmaps[n]) {
+ return *pixmaps[n];
+ }
+
+ QString picName = QString::fromLatin1("stars%1").arg(n);
+ QPixmap* pix = new QPixmap(UserIcon(picName));
+ pixmaps.insert(n, pix);
+ return *pix;
+}
+
+RatingWidget::RatingWidget(Data::FieldPtr field_, QWidget* parent_, const char* name_/*=0*/)
+ : QHBox(parent_, name_), m_field(field_), m_currIndex(-1) {
+ m_pixOn = UserIcon(QString::fromLatin1("star_on"));
+ m_pixOff = UserIcon(QString::fromLatin1("star_off"));
+ setSpacing(0);
+
+ // find maximum width and height
+ int w = QMAX(RATING_WIDGET_MAX_STAR_SIZE, QMAX(m_pixOn.width(), m_pixOff.width()));
+ int h = QMAX(RATING_WIDGET_MAX_STAR_SIZE, QMAX(m_pixOn.height(), m_pixOff.height()));
+ for(int i = 0; i < RATING_WIDGET_MAX_ICONS; ++i) {
+ QLabel* l = new QLabel(this);
+ l->setFixedSize(w, h);
+ m_widgets.append(l);
+ }
+ init();
+
+ QBoxLayout* l = dynamic_cast<QBoxLayout*>(layout());
+ if(l) {
+ l->addStretch(1);
+ }
+}
+
+void RatingWidget::init() {
+ updateBounds();
+ m_total = QMIN(m_max, static_cast<int>(m_widgets.count()));
+ uint i = 0;
+ for( ; static_cast<int>(i) < m_total; ++i) {
+ m_widgets.at(i)->setPixmap(m_pixOff);
+ }
+ for( ; i < m_widgets.count(); ++i) {
+ m_widgets.at(i)->setPixmap(QPixmap());
+ }
+ update();
+}
+
+void RatingWidget::updateBounds() {
+ bool ok; // not used;
+ m_min = Tellico::toUInt(m_field->property(QString::fromLatin1("minimum")), &ok);
+ m_max = Tellico::toUInt(m_field->property(QString::fromLatin1("maximum")), &ok);
+ if(m_max > RATING_WIDGET_MAX_ICONS) {
+ myDebug() << "RatingWidget::updateBounds() - max is too high: " << m_max << endl;
+ m_max = RATING_WIDGET_MAX_ICONS;
+ }
+ if(m_min < 1) {
+ m_min = 1;
+ }
+}
+
+void RatingWidget::update() {
+ int i = 0;
+ for( ; i <= m_currIndex; ++i) {
+ m_widgets.at(i)->setPixmap(m_pixOn);
+ }
+ for( ; i < m_total; ++i) {
+ m_widgets.at(i)->setPixmap(m_pixOff);
+ }
+
+ QHBox::update();
+}
+
+void RatingWidget::mousePressEvent(QMouseEvent* event_) {
+ // only react to left button
+ if(event_->button() != Qt::LeftButton) {
+ return;
+ }
+
+ int idx;
+ QWidget* child = childAt(event_->pos());
+ if(child) {
+ idx = m_widgets.findRef(static_cast<QLabel*>(child));
+ // if the widget is clicked beyond the maximum value, clear it
+ // remember total and min are values, but index is zero-based!
+ if(idx > m_total-1) {
+ idx = -1;
+ } else if(idx < m_min-1) {
+ idx = m_min-1; // limit to minimum, remember index is zero-based
+ }
+ } else {
+ idx = -1;
+ }
+ if(m_currIndex != idx) {
+ m_currIndex = idx;
+ update();
+ emit modified();
+ }
+}
+
+void RatingWidget::clear() {
+ m_currIndex = -1;
+ update();
+}
+
+QString RatingWidget::text() const {
+ // index is index of the list, which is zero-based. Add 1!
+ return m_currIndex == -1 ? QString::null : QString::number(m_currIndex+1);
+}
+
+void RatingWidget::setText(const QString& text_) {
+ bool ok;
+ // text is value, subtract one to get index
+ m_currIndex = Tellico::toUInt(text_, &ok)-1;
+ if(ok) {
+ if(m_currIndex > m_total-1) {
+ m_currIndex = -1;
+ } else if(m_currIndex < m_min-1) {
+ m_currIndex = m_min-1; // limit to minimum, remember index is zero-based
+ }
+ } else {
+ m_currIndex = -1;
+ }
+ update();
+}
+
+void RatingWidget::updateField(Data::FieldPtr field_) {
+ m_field = field_;
+ init();
+}
+
+#include "ratingwidget.moc"
diff --git a/src/gui/ratingwidget.h b/src/gui/ratingwidget.h
new file mode 100644
index 0000000..99665b3
--- /dev/null
+++ b/src/gui/ratingwidget.h
@@ -0,0 +1,75 @@
+/***************************************************************************
+ copyright : (C) 2003-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef RATINGWIDGET_H
+#define RATINGWIDGET_H
+
+#include "../datavectors.h"
+
+#include <qhbox.h>
+#include <qptrlist.h>
+#include <qlabel.h>
+#include <qpixmap.h>
+
+namespace Tellico {
+ namespace Data {
+ class Field;
+ }
+ namespace GUI {
+
+/**
+ * @author Robby Stephenson
+ */
+class RatingWidget : public QHBox {
+Q_OBJECT
+
+typedef QPtrList<QLabel> LabelList;
+
+public:
+ RatingWidget(Data::FieldPtr field, QWidget* parent, const char* name = 0);
+
+ void clear();
+ QString text() const;
+ void setText(const QString& text);
+ void updateField(Data::FieldPtr field);
+
+ static const QPixmap& pixmap(const QString& value);
+
+public slots:
+ void update();
+
+signals:
+ void modified();
+
+protected:
+ virtual void mousePressEvent(QMouseEvent* e);
+
+private:
+ void init();
+ void updateBounds();
+
+ Data::ConstFieldPtr m_field;
+ LabelList m_widgets;
+
+ int m_currIndex;
+ int m_total;
+ int m_min;
+ int m_max;
+
+ QPixmap m_pixOn;
+ QPixmap m_pixOff;
+};
+
+ } // end GUI namespace
+} // end namespace
+#endif
diff --git a/src/gui/richtextlabel.cpp b/src/gui/richtextlabel.cpp
new file mode 100644
index 0000000..a4cdde4
--- /dev/null
+++ b/src/gui/richtextlabel.cpp
@@ -0,0 +1,47 @@
+/***************************************************************************
+ copyright : (C) 2001-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "richtextlabel.h"
+
+#include <kdebug.h>
+
+#include <qlayout.h>
+
+using Tellico::GUI::RichTextLabel;
+
+RichTextLabel::RichTextLabel(QWidget* parent) : QTextEdit(parent) {
+ init();
+}
+
+RichTextLabel::RichTextLabel(const QString& text, QWidget* parent) : QTextEdit(text, QString::null, parent) {
+ init();
+}
+
+QSize RichTextLabel::sizeHint() const {
+ return minimumSizeHint();
+}
+
+void RichTextLabel::init() {
+ setReadOnly(true);
+ setTextFormat(Qt::RichText);
+
+ setFrameShape(QFrame::NoFrame);
+ viewport()->setMouseTracking(false);
+
+ setPaper(colorGroup().background());
+
+ setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding));
+ viewport()->setSizePolicy(QSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding));
+}
+
+#include "richtextlabel.moc"
diff --git a/src/gui/richtextlabel.h b/src/gui/richtextlabel.h
new file mode 100644
index 0000000..f45a328
--- /dev/null
+++ b/src/gui/richtextlabel.h
@@ -0,0 +1,46 @@
+/***************************************************************************
+ copyright : (C) 2001-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TELLICO_GUI_RICHTEXTLABEL_H
+#define TELLICO_GUI_RICHTEXTLABEL_H
+
+#include <qtextedit.h>
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * @author Robby Stephenson
+ */
+class RichTextLabel : public QTextEdit {
+Q_OBJECT
+
+public:
+ RichTextLabel(QWidget* parent);
+ RichTextLabel(const QString& text, QWidget* parent);
+
+ virtual QSize sizeHint() const;
+
+private:
+ void init();
+ // redefine these to disable selection
+ void contentsMousePressEvent(QMouseEvent*) {}
+ void contentsMouseMoveEvent(QMouseEvent*) {}
+ void contentsMouseReleaseEvent(QMouseEvent*) {}
+ void contentsMouseDoubleClickEvent(QMouseEvent*) {}
+};
+
+ } // end namespace
+} // end namespace
+
+#endif
diff --git a/src/gui/stringmapdialog.cpp b/src/gui/stringmapdialog.cpp
new file mode 100644
index 0000000..4a5374f
--- /dev/null
+++ b/src/gui/stringmapdialog.cpp
@@ -0,0 +1,125 @@
+/***************************************************************************
+ copyright : (C) 2003-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "stringmapdialog.h"
+
+#include <klistview.h>
+#include <klocale.h>
+#include <klineedit.h>
+#include <kbuttonbox.h>
+#include <kiconloader.h>
+
+#include <qlayout.h>
+#include <qheader.h>
+#include <qhbox.h>
+#include <qwhatsthis.h>
+#include <qpushbutton.h>
+
+using Tellico::StringMapDialog;
+
+StringMapDialog::StringMapDialog(const QMap<QString, QString>& map_, QWidget* parent_, const char* name_/*=0*/, bool modal_/*=false*/)
+ : KDialogBase(parent_, name_, modal_, QString::null, Ok|Cancel) {
+ QWidget* page = new QWidget(this);
+ QVBoxLayout* l = new QVBoxLayout(page, 0, KDialog::spacingHint());
+
+ m_listView = new KListView(page);
+ m_listView->setAllColumnsShowFocus(true);
+ m_listView->setShowSortIndicator(true);
+ m_listView->addColumn(QString::null);
+ m_listView->addColumn(QString::null);
+ m_listView->header()->hide(); // hide header since neither column has a label initially
+ m_listView->setColumnWidthMode(0, QListView::Maximum);
+ m_listView->setColumnWidthMode(1, QListView::Maximum);
+ m_listView->setResizeMode(QListView::AllColumns);
+ connect(m_listView, SIGNAL(currentChanged(QListViewItem*)), SLOT(slotUpdate(QListViewItem*)));
+ connect(m_listView, SIGNAL(clicked(QListViewItem*)), SLOT(slotUpdate(QListViewItem*)));
+ l->addWidget(m_listView);
+
+ QHBox* box = new QHBox(page);
+ box->setMargin(4);
+ box->setSpacing(KDialog::spacingHint());
+
+ m_edit1 = new KLineEdit(box);
+ m_edit1->setFocus();
+ m_edit2 = new KLineEdit(box);
+ KButtonBox* bb = new KButtonBox(box);
+ bb->addStretch();
+ QPushButton* btn = bb->addButton(i18n("&Set"), this, SLOT(slotAdd()));
+ btn->setIconSet(BarIcon(QString::fromLatin1("filenew"), KIcon::SizeSmall));
+ btn = bb->addButton(i18n("&Delete"), this, SLOT(slotDelete()));
+ btn->setIconSet(BarIcon(QString::fromLatin1("editdelete"), KIcon::SizeSmall));
+
+ l->addWidget(box);
+ l->addStretch(1);
+ setMainWidget(page);
+
+ for(QMap<QString, QString>::ConstIterator it = map_.begin(); it != map_.end(); ++it) {
+ if(!it.data().isEmpty()) {
+ (void) new KListViewItem(m_listView, it.key(), it.data());
+ }
+ }
+
+ setMinimumWidth(400);
+ enableButtonSeparator(true);
+}
+
+void StringMapDialog::slotAdd() {
+ QString s1 = m_edit1->text();
+ QString s2 = m_edit2->text();
+ if(s1.isEmpty() && s2.isEmpty()) {
+ return;
+ }
+ QListViewItem* item = m_listView->currentItem();
+ if(item && s1 == item->text(0)) { // only update values if same key
+ item->setText(1, s2);
+ } else {
+ item = new KListViewItem(m_listView, s1, s2);
+ }
+ m_listView->ensureItemVisible(item);
+ m_listView->setSelected(item, true);
+ m_listView->setCurrentItem(item);
+}
+
+void StringMapDialog::slotDelete() {
+ delete m_listView->currentItem();
+ m_edit1->clear();
+ m_edit2->clear();
+ m_listView->setSelected(m_listView->currentItem(), true);
+}
+
+void StringMapDialog::slotUpdate(QListViewItem* item_) {
+ if(item_) {
+ m_edit1->setText(item_->text(0));
+ m_edit2->setText(item_->text(1));
+ m_listView->header()->adjustHeaderSize();
+ } else {
+ m_edit1->clear();
+ m_edit2->clear();
+ }
+}
+
+void StringMapDialog::setLabels(const QString& label1_, const QString& label2_) {
+ m_listView->header()->setLabel(0, label1_);
+ m_listView->header()->setLabel(1, label2_);
+ m_listView->header()->show();
+}
+
+QMap<QString, QString> StringMapDialog::stringMap() {
+ QMap<QString, QString> map;
+ for(QListViewItem* item = m_listView->firstChild(); item; item = item->nextSibling()) {
+ map.insert(item->text(0), item->text(1));
+ }
+ return map;
+}
+
+#include "stringmapdialog.moc"
diff --git a/src/gui/stringmapdialog.h b/src/gui/stringmapdialog.h
new file mode 100644
index 0000000..311df70
--- /dev/null
+++ b/src/gui/stringmapdialog.h
@@ -0,0 +1,71 @@
+/***************************************************************************
+ copyright : (C) 2003-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef STRINGMAPDIALOG_H
+#define STRINGMAPDIALOG_H
+
+class KLineEdit;
+class KListView;
+class QListViewItem;
+
+#include <kdialogbase.h>
+
+template <typename T1, typename T2>
+class QMap;
+
+namespace Tellico {
+
+/**
+ * @short A simple dialog for editing a map between two strings.
+ *
+ * A \ref KListView is used with the map keys in the first column and
+ * the map values in the second. Two edit boxes are below the list view.
+ * When an item is selected, the key-value is pair is placed in the edit
+ * boxes. Add and Delete buttons are used to add a new pair, or to remove
+ * an existing one.
+ *
+ * @author Robby Stephenson
+ */
+class StringMapDialog : public KDialogBase {
+Q_OBJECT
+
+public:
+ StringMapDialog(const QMap<QString, QString>& stringMap, QWidget* parent, const char* name=0, bool modal=false);
+
+ /**
+ * Sets the titles for the key and value columns.
+ *
+ * @param label1 The name of the key string
+ * @param label2 The name of the value string
+ */
+ void setLabels(const QString& label1, const QString& label2);
+ /**
+ * Returns the modified string map.
+ *
+ * @return The modified string map
+ */
+ QMap<QString, QString> stringMap();
+
+private slots:
+ void slotAdd();
+ void slotDelete();
+ void slotUpdate(QListViewItem* item);
+
+protected:
+ KListView* m_listView;
+ KLineEdit* m_edit1;
+ KLineEdit* m_edit2;
+};
+
+} // end namespace
+#endif
diff --git a/src/gui/tabcontrol.cpp b/src/gui/tabcontrol.cpp
new file mode 100644
index 0000000..145f632
--- /dev/null
+++ b/src/gui/tabcontrol.cpp
@@ -0,0 +1,77 @@
+/***************************************************************************
+ copyright : (C) 2002-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "tabcontrol.h"
+
+#include <qtabbar.h>
+#include <qobjectlist.h>
+
+using Tellico::GUI::TabControl;
+
+TabControl::TabControl(QWidget* parent_, const char* name_/*=0*/)
+ : QTabWidget(parent_, name_) {
+}
+
+QTabBar* TabControl::tabBar() const {
+ return QTabWidget::tabBar();
+}
+
+void TabControl::setFocusToFirstChild() {
+ QWidget* page = currentPage();
+ Q_ASSERT(page);
+ QObjectList* list = page->queryList("QWidget");
+ for(QObjectListIt it(*list); it.current(); ++it) {
+ QWidget* w = static_cast<QWidget*>(it.current());
+ if(w->isFocusEnabled()) {
+ w->setFocus();
+ break;
+ }
+ }
+ delete list;
+}
+
+// have to loop backwards since count() gets decremented on delete
+void TabControl::clear() {
+ for(int i = count(); i > 0; --i) {
+ QWidget* w = page(i-1);
+ if(w) {
+ removePage(w);
+ delete w;
+ }
+ }
+}
+
+void TabControl::setTabBarHidden(bool hide_) {
+ QWidget* rightcorner = cornerWidget(TopRight);
+ QWidget* leftcorner = cornerWidget(TopLeft);
+
+ if(hide_) {
+ if(leftcorner) {
+ leftcorner->hide();
+ }
+ if(rightcorner) {
+ rightcorner->hide();
+ }
+ tabBar()->hide();
+ } else {
+ tabBar()->show();
+ if(leftcorner) {
+ leftcorner->show();
+ }
+ if(rightcorner) {
+ rightcorner->show();
+ }
+ }
+}
+
+#include "tabcontrol.moc"
diff --git a/src/gui/tabcontrol.h b/src/gui/tabcontrol.h
new file mode 100644
index 0000000..20d22f5
--- /dev/null
+++ b/src/gui/tabcontrol.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+ copyright : (C) 2002-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TABCONTROL_H
+#define TABCONTROL_H
+
+#include <qtabwidget.h>
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * @author Robby Stephenson
+ */
+class TabControl : public QTabWidget {
+Q_OBJECT
+
+public:
+ /**
+ * Constructor
+ */
+ TabControl(QWidget* parent, const char* name=0);
+
+ QTabBar* tabBar() const;
+ void setTabBarHidden(bool hide);
+
+ /**
+ * Sets the focus to the first focusable widget on the current page.
+ */
+ void setFocusToFirstChild();
+
+public slots:
+ void clear();
+};
+
+ } // end namespace
+} // end namespace
+#endif
diff --git a/src/gui/tablefieldwidget.cpp b/src/gui/tablefieldwidget.cpp
new file mode 100644
index 0000000..30f89b4
--- /dev/null
+++ b/src/gui/tablefieldwidget.cpp
@@ -0,0 +1,330 @@
+/***************************************************************************
+ copyright : (C) 2003-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "tablefieldwidget.h"
+#include "../field.h"
+#include "../tellico_utils.h"
+#include "../tellico_kernel.h"
+
+#include <klocale.h>
+#include <kpopupmenu.h>
+#include <kiconloader.h>
+#include <kinputdialog.h>
+
+#include <qtable.h>
+
+namespace {
+ static const int MIN_TABLE_ROWS = 5;
+ static const int MAX_TABLE_COLS = 10;
+}
+
+using Tellico::GUI::TableFieldWidget;
+
+TableFieldWidget::TableFieldWidget(Data::FieldPtr field_, QWidget* parent_, const char* name_/*=0*/)
+ : FieldWidget(field_, parent_, name_), m_field(field_), m_row(-1), m_col(-1) {
+
+ bool ok;
+ m_columns = Tellico::toUInt(field_->property(QString::fromLatin1("columns")), &ok);
+ if(!ok) {
+ m_columns = 1;
+ } else {
+ m_columns = QMIN(m_columns, MAX_TABLE_COLS); // max of 5 columns
+ }
+
+ m_table = new QTable(MIN_TABLE_ROWS, m_columns, this);
+ labelColumns(m_field);
+ // allow renaming of column titles
+ m_table->horizontalHeader()->setClickEnabled(true);
+ m_table->horizontalHeader()->installEventFilter(this);
+
+ m_table->verticalHeader()->setClickEnabled(true);
+ m_table->verticalHeader()->installEventFilter(this);
+ connect(m_table->verticalHeader(), SIGNAL(indexChange(int, int, int)), SIGNAL(modified()));
+
+ m_table->setDragEnabled(false);
+ m_table->setFocusStyle(QTable::FollowStyle);
+ m_table->setRowMovingEnabled(true); // rows can be moved
+ m_table->setColumnMovingEnabled(false); // columns remain fixed
+
+ m_table->setColumnStretchable(m_columns-1, true);
+ m_table->adjustColumn(m_columns-1);
+ m_table->setSelectionMode(QTable::NoSelection);
+ m_table->setHScrollBarMode(QScrollView::AlwaysOff);
+
+ connect(m_table, SIGNAL(valueChanged(int, int)), SIGNAL(modified()));
+ connect(m_table, SIGNAL(currentChanged(int, int)), SLOT(slotCheckRows(int, int)));
+ connect(m_table, SIGNAL(valueChanged(int, int)), SLOT(slotResizeColumn(int, int)));
+ connect(m_table, SIGNAL(contextMenuRequested(int, int, const QPoint&)), SLOT(contextMenu(int, int, const QPoint&)));
+
+ registerWidget();
+}
+
+QString TableFieldWidget::text() const {
+ QString text, str, rstack, cstack, rowStr;
+ for(int row = 0; row < m_table->numRows(); ++row) {
+ rowStr.truncate(0);
+ cstack.truncate(0);
+ for(int col = 0; col < m_table->numCols(); ++col) {
+ str = m_table->text(row, col).simplifyWhiteSpace();
+ if(str.isEmpty()) {
+ cstack += QString::fromLatin1("::");
+ } else {
+ rowStr += cstack + str + QString::fromLatin1("::");
+ cstack.truncate(0);
+ }
+ }
+ if(rowStr.isEmpty()) {
+ rstack += QString::fromLatin1("; ");
+ } else {
+ rowStr.truncate(rowStr.length()-2); // remove last semi-colon and space
+ text += rstack + rowStr + QString::fromLatin1("; ");
+ rstack.truncate(0);
+ }
+ }
+ if(!text.isEmpty()) {
+ text.truncate(text.length()-2); // remove last semi-colon and space
+ }
+
+ // now reduce number of rows if necessary
+ bool loop = true;
+ for(int row = m_table->numRows()-1; loop && row > MIN_TABLE_ROWS; --row) {
+ bool empty = true;
+ for(int col = 0; col < m_table->numCols(); ++col) {
+ if(!m_table->text(row, col).isEmpty()) {
+ empty = false;
+ break;
+ }
+ }
+ if(empty) {
+ m_table->removeRow(row);
+ } else {
+ loop = false;
+ }
+ }
+ return text;
+}
+
+void TableFieldWidget::setText(const QString& text_) {
+ QStringList list = Data::Field::split(text_, true);
+ // add additional rows if needed
+ if(static_cast<int>(list.count()) > m_table->numRows()) {
+ m_table->insertRows(m_table->numRows(), list.count()-m_table->numRows());
+ }
+ int row;
+ for(row = 0; row < static_cast<int>(list.count()); ++row) {
+ for(int col = 0; col < m_table->numCols(); ++col) {
+ m_table->setText(row, col, list[row].section(QString::fromLatin1("::"), col, col));
+ }
+ m_table->showRow(row);
+ }
+ // remove any un-needed rows
+ int minRow = QMAX(row, MIN_TABLE_ROWS);
+ for(row = m_table->numRows()-1; row >= minRow; --row) {
+ m_table->removeRow(row);
+ }
+ // adjust all columns
+ for(int col = 0; col < m_table->numCols()-1; ++col) {
+ m_table->adjustColumn(col);
+ }
+}
+
+void TableFieldWidget::clear() {
+ bool wasEmpty = true;
+ for(int row = 0; row < m_table->numRows(); ++row) {
+ if(!emptyRow(row)) {
+ wasEmpty = false;
+ }
+ for(int col = 0; col < m_table->numCols(); ++col) {
+ m_table->setText(row, col, QString::null);
+ }
+ if(row >= MIN_TABLE_ROWS) {
+ m_table->removeRow(row);
+ --row;
+ }
+ }
+ editMultiple(false);
+ if(!wasEmpty) {
+ emit modified();
+ }
+}
+
+QWidget* TableFieldWidget::widget() {
+ return m_table;
+}
+
+void TableFieldWidget::slotCheckRows(int row_, int) {
+ if(row_ == m_table->numRows()-1 && !emptyRow(row_)) { // if is last row and row above is not empty
+ m_table->insertRows(m_table->numRows());
+ }
+}
+
+void TableFieldWidget::slotResizeColumn(int, int col_) {
+ m_table->adjustColumn(col_);
+}
+
+void TableFieldWidget::slotRenameColumn() {
+ if(m_col < 0 || m_col >= m_columns) {
+ return;
+ }
+ QString name = m_table->horizontalHeader()->label(m_col);
+ bool ok;
+ QString newName = KInputDialog::getText(i18n("Rename Column"), i18n("New column name:"),
+ name, &ok, this);
+ if(ok && !newName.isEmpty()) {
+ Data::FieldPtr newField = new Data::Field(*m_field);
+ newField->setProperty(QString::fromLatin1("column%1").arg(m_col+1), newName);
+ if(Kernel::self()->modifyField(newField)) {
+ m_field = newField;
+ labelColumns(m_field);
+ }
+ }
+}
+
+bool TableFieldWidget::emptyRow(int row_) const {
+ for(int col = 0; col < m_table->numCols(); ++col) {
+ if(!m_table->text(row_, col).isEmpty()) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void TableFieldWidget::labelColumns(Data::FieldPtr field_) {
+ for(int i = 0; i < m_columns; ++i) {
+ QString s = field_->property(QString::fromLatin1("column%1").arg(i+1));
+ if(s.isEmpty()) {
+ s = i18n("Column %1").arg(i+1);
+ }
+ m_table->horizontalHeader()->setLabel(i, s);
+ }
+}
+
+void TableFieldWidget::updateFieldHook(Data::FieldPtr, Data::FieldPtr newField_) {
+ bool ok;
+ m_columns = Tellico::toUInt(newField_->property(QString::fromLatin1("columns")), &ok);
+ if(!ok) {
+ m_columns = 1;
+ } else {
+ m_columns = QMIN(m_columns, MAX_TABLE_COLS); // max of 5 columns
+ }
+ if(m_columns != m_table->numCols()) {
+ m_table->setNumCols(m_columns);
+ }
+ m_table->horizontalHeader()->adjustHeaderSize();
+ labelColumns(newField_);
+}
+
+bool TableFieldWidget::eventFilter(QObject* obj_, QEvent* ev_) {
+ if(ev_->type() == QEvent::MouseButtonPress
+ && static_cast<QMouseEvent*>(ev_)->button() == Qt::RightButton) {
+ if(obj_ == m_table->horizontalHeader()) {
+ QMouseEvent* ev = static_cast<QMouseEvent*>(ev_);
+ // might be scrolled
+ int pos = ev->x() + m_table->horizontalHeader()->offset();
+ int col = m_table->horizontalHeader()->sectionAt(pos);
+ if(col >= m_columns) {
+ return false;
+ }
+ m_row = -1;
+ m_col = col;
+ KPopupMenu menu(this);
+ menu.insertItem(SmallIconSet(QString::fromLatin1("edit")), i18n("Rename Column..."),
+ this, SLOT(slotRenameColumn()));
+ menu.exec(ev->globalPos());
+ return true;
+ } else if(obj_ == m_table->verticalHeader()) {
+ QMouseEvent* ev = static_cast<QMouseEvent*>(ev_);
+ // might be scrolled
+ int pos = ev->y() + m_table->verticalHeader()->offset();
+ int row = m_table->verticalHeader()->sectionAt(pos);
+ if(row < 0 || row > m_table->numRows()-1) {
+ return false;
+ }
+ m_row = row;
+ m_col = -1;
+ // show regular right-click menu
+ contextMenu(m_row, m_col, ev->globalPos());
+ return true;
+ }
+ }
+ return FieldWidget::eventFilter(obj_, ev_);
+}
+
+void TableFieldWidget::contextMenu(int row_, int col_, const QPoint& p_) {
+ // might get called with col == -1 for clicking on vertical header
+ // but a negative row means clicking outside bounds of table
+ if(row_ < 0) {
+ return;
+ }
+ m_row = row_;
+ m_col = col_;
+
+ int id;
+ KPopupMenu menu(this);
+ menu.insertItem(SmallIconSet(QString::fromLatin1("insrow")), i18n("Insert Row"),
+ this, SLOT(slotInsertRow()));
+ menu.insertItem(SmallIconSet(QString::fromLatin1("remrow")), i18n("Remove Row"),
+ this, SLOT(slotRemoveRow()));
+ id = menu.insertItem(SmallIconSet(QString::fromLatin1("1uparrow")), i18n("Move Row Up"),
+ this, SLOT(slotMoveRowUp()));
+ if(m_row == 0) {
+ menu.setItemEnabled(id, false);
+ }
+ id = menu.insertItem(SmallIconSet(QString::fromLatin1("1downarrow")), i18n("Move Row Down"),
+ this, SLOT(slotMoveRowDown()));
+ if(m_row == m_table->numRows()-1) {
+ menu.setItemEnabled(id, false);
+ }
+ menu.insertSeparator();
+ id = menu.insertItem(SmallIconSet(QString::fromLatin1("edit")), i18n("Rename Column..."),
+ this, SLOT(slotRenameColumn()));
+ if(m_col < 0 || m_col > m_columns-1) {
+ menu.setItemEnabled(id, false);
+ }
+ menu.insertSeparator();
+ menu.insertItem(SmallIconSet(QString::fromLatin1("locationbar_erase")), i18n("Clear Table"),
+ this, SLOT(clear()));
+ menu.exec(p_);
+}
+
+void TableFieldWidget::slotInsertRow() {
+ if(m_row > -1) {
+ m_table->insertRows(m_row);
+ emit modified();
+ }
+}
+
+void TableFieldWidget::slotRemoveRow() {
+ if(m_row > -1) {
+ m_table->removeRow(m_row);
+ emit modified();
+ }
+}
+
+void TableFieldWidget::slotMoveRowUp() {
+ if(m_row > 0) {
+ m_table->swapRows(m_row, m_row-1, true);
+ m_table->updateContents();
+ emit modified();
+ }
+}
+
+void TableFieldWidget::slotMoveRowDown() {
+ if(m_row < m_table->numRows()-1) {
+ m_table->swapRows(m_row, m_row+1, true);
+ m_table->updateContents();
+ emit modified();
+ }
+}
+
+#include "tablefieldwidget.moc"
diff --git a/src/gui/tablefieldwidget.h b/src/gui/tablefieldwidget.h
new file mode 100644
index 0000000..da9157d
--- /dev/null
+++ b/src/gui/tablefieldwidget.h
@@ -0,0 +1,74 @@
+/***************************************************************************
+ copyright : (C) 2003-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef TABLEFIELDWIDGET_H
+#define TABLEFIELDWIDGET_H
+
+class QTable;
+class QEvent;
+
+#include "fieldwidget.h"
+#include "../datavectors.h"
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * @author Robby Stephenson
+ */
+class TableFieldWidget : public FieldWidget {
+Q_OBJECT
+
+public:
+ TableFieldWidget(Data::FieldPtr field, QWidget* parent, const char* name=0);
+ virtual ~TableFieldWidget() {}
+
+ virtual QString text() const;
+ virtual void setText(const QString& text);
+
+ /**
+ * Event filter used to popup the menu
+ */
+ bool eventFilter(QObject* obj, QEvent* ev);
+
+public slots:
+ virtual void clear();
+
+protected:
+ virtual QWidget* widget();
+ virtual void updateFieldHook(Data::FieldPtr oldField, Data::FieldPtr newField);
+
+private slots:
+ void contextMenu(int row, int col, const QPoint& p);
+ void slotCheckRows(int row, int col);
+ void slotResizeColumn(int row, int col);
+ void slotRenameColumn();
+ void slotInsertRow();
+ void slotRemoveRow();
+ void slotMoveRowUp();
+ void slotMoveRowDown();
+
+private:
+ bool emptyRow(int row) const;
+ void labelColumns(Data::FieldPtr field);
+
+ QTable* m_table;
+ int m_columns;
+ Data::FieldPtr m_field;
+ int m_row;
+ int m_col;
+};
+
+ } // end GUI namespace
+} // end namespace
+#endif
diff --git a/src/gui/urlfieldwidget.cpp b/src/gui/urlfieldwidget.cpp
new file mode 100644
index 0000000..f3c2afd
--- /dev/null
+++ b/src/gui/urlfieldwidget.cpp
@@ -0,0 +1,98 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#include "urlfieldwidget.h"
+#include "../field.h"
+#include "../latin1literal.h"
+#include "../tellico_kernel.h"
+
+#include <klineedit.h>
+#include <kurlrequester.h>
+#include <kurllabel.h>
+
+using Tellico::GUI::URLFieldWidget;
+
+// subclass of KURLCompletion is needed so the KURLLabel
+// can open relative links. I don't want to have to have to update
+// the base directory of the completion every time a new document is opened
+QString URLFieldWidget::URLCompletion::makeCompletion(const QString& text_) {
+ // KURLCompletion::makeCompletion() uses an internal variable instead
+ // of calling KURLCompletion::dir() so need to set the base dir before completing
+ setDir(Kernel::self()->URL().directory());
+ return KURLCompletion::makeCompletion(text_);
+}
+
+URLFieldWidget::URLFieldWidget(Data::FieldPtr field_, QWidget* parent_, const char* name_/*=0*/)
+ : FieldWidget(field_, parent_, name_), m_run(0) {
+
+ m_requester = new KURLRequester(this);
+ m_requester->lineEdit()->setCompletionObject(new URLCompletion());
+ m_requester->lineEdit()->setAutoDeleteCompletionObject(true);
+ connect(m_requester, SIGNAL(textChanged(const QString&)), SIGNAL(modified()));
+ connect(m_requester, SIGNAL(textChanged(const QString&)), label(), SLOT(setURL(const QString&)));
+ connect(label(), SIGNAL(leftClickedURL(const QString&)), SLOT(slotOpenURL(const QString&)));
+ registerWidget();
+
+ // special case, remember if it's a relative url
+ m_isRelative = field_->property(QString::fromLatin1("relative")) == Latin1Literal("true");
+}
+
+URLFieldWidget::~URLFieldWidget() {
+ if(m_run) {
+ m_run->abort();
+ }
+}
+
+QString URLFieldWidget::text() const {
+ if(m_isRelative) {
+ return KURL::relativeURL(Kernel::self()->URL(), m_requester->url());
+ }
+ // for comparison purposes and to be consistent with the file listing importer
+ // I want the full url here, including the protocol
+ // the requester only returns the path, so create a KURL
+ return KURL(m_requester->url()).url();
+}
+
+void URLFieldWidget::setText(const QString& text_) {
+ blockSignals(true);
+
+ m_requester->blockSignals(true);
+ m_requester->setURL(text_);
+ m_requester->blockSignals(false);
+ static_cast<KURLLabel*>(label())->setURL(text_);
+
+ blockSignals(false);
+}
+
+void URLFieldWidget::clear() {
+ m_requester->clear();
+ editMultiple(false);
+}
+
+void URLFieldWidget::updateFieldHook(Data::FieldPtr, Data::FieldPtr newField_) {
+ m_isRelative = newField_->property(QString::fromLatin1("relative")) == Latin1Literal("true");
+}
+
+void URLFieldWidget::slotOpenURL(const QString& url_) {
+ if(url_.isEmpty()) {
+ return;
+ }
+ // just in case, interpret string relative to document url
+ m_run = new KRun(KURL(Kernel::self()->URL(), url_));
+}
+
+QWidget* URLFieldWidget::widget() {
+ return m_requester;
+}
+
+#include "urlfieldwidget.moc"
diff --git a/src/gui/urlfieldwidget.h b/src/gui/urlfieldwidget.h
new file mode 100644
index 0000000..70e9505
--- /dev/null
+++ b/src/gui/urlfieldwidget.h
@@ -0,0 +1,66 @@
+/***************************************************************************
+ copyright : (C) 2005-2006 by Robby Stephenson
+ email : robby@periapsis.org
+ ***************************************************************************/
+
+/***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of version 2 of the GNU General Public License as *
+ * published by the Free Software Foundation; *
+ * *
+ ***************************************************************************/
+
+#ifndef URLFIELDWIDGET_H
+#define URLFIELDWIDGET_H
+
+class KURLRequester;
+
+#include "fieldwidget.h"
+
+#include <krun.h>
+#include <kurlcompletion.h>
+
+#include <qguardedptr.h>
+
+namespace Tellico {
+ namespace GUI {
+
+/**
+ * @author Robby Stephenson
+ */
+class URLFieldWidget : public FieldWidget {
+Q_OBJECT
+
+public:
+ URLFieldWidget(Data::FieldPtr field, QWidget* parent, const char* name=0);
+ virtual ~URLFieldWidget();
+
+ virtual QString text() const;
+ virtual void setText(const QString& text);
+
+public slots:
+ virtual void clear();
+
+protected:
+ virtual QWidget* widget();
+ virtual void updateFieldHook(Data::FieldPtr oldField, Data::FieldPtr newField);
+
+protected slots:
+ void slotOpenURL(const QString& url);
+
+private:
+ class URLCompletion : public KURLCompletion {
+ public:
+ URLCompletion() : KURLCompletion() {}
+ virtual QString makeCompletion(const QString& text);
+ };
+
+ KURLRequester* m_requester;
+ bool m_isRelative : 1;
+ QGuardedPtr<KRun> m_run;
+};
+
+ } // end GUI namespace
+} // end namespace
+#endif