[rkward-cvs] SF.net SVN: rkward-code:[4503] trunk/rkward/rkward/misc

tfry at users.sf.net tfry at users.sf.net
Fri Jan 25 16:32:56 UTC 2013


Revision: 4503
          http://sourceforge.net/p/rkward/code/4503
Author:   tfry
Date:     2013-01-25 16:32:55 +0000 (Fri, 25 Jan 2013)
Log Message:
-----------
Add a new more flexible variant of the MultiStringSelector. Implement the old version on top of the new one.

Modified Paths:
--------------
    trunk/rkward/rkward/misc/multistringselector.cpp
    trunk/rkward/rkward/misc/multistringselector.h

Modified: trunk/rkward/rkward/misc/multistringselector.cpp
===================================================================
--- trunk/rkward/rkward/misc/multistringselector.cpp	2013-01-23 18:43:50 UTC (rev 4502)
+++ trunk/rkward/rkward/misc/multistringselector.cpp	2013-01-25 16:32:55 UTC (rev 4503)
@@ -2,7 +2,7 @@
                           multistringselector  -  description
                              -------------------
     begin                : Fri Sep 10 2005
-    copyright            : (C) 2005 by Thomas Friedrichsmeier
+    copyright            : (C) 2005, 2013 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -17,20 +17,78 @@
 
 #include "multistringselector.h"
 
-#include <QTreeWidget>
-#include <qpushbutton.h>
-#include <qlabel.h>
+#include <QTreeView>
+#include <QPushButton>
+#include <QLabel>
 #include <QHBoxLayout>
 #include <QVBoxLayout>
+#include <QStringListModel>
 
 #include <klocale.h>
 
 #include "rkstandardicons.h"
 #include "../debug.h"
 
-MultiStringSelector::MultiStringSelector (const QString& label, QWidget* parent) : QWidget (parent) {
+class RKStringListModelWithColumnLabel : public QStringListModel {
+public:
+	RKStringListModelWithColumnLabel (QObject *parent, const QString& _label) : QStringListModel (parent), label (_label) {};
+	~RKStringListModelWithColumnLabel () {};
+	QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const {
+		if ((section == 0) && (orientation == Qt::Horizontal) && (role == Qt::DisplayRole)) return label;
+		return QVariant ();
+	};
+	QString label;
+};
+
+MultiStringSelector::MultiStringSelector (const QString& label, QWidget* parent) : RKMultiStringSelectorV2 (label, parent) {
 	RK_TRACE (MISC);
 
+	model = new RKStringListModelWithColumnLabel (this, i18n ("Filename"));
+	connect (this, SIGNAL (swapRows(int,int)), this, SLOT (swapRowsImpl(int,int)));
+	connect (this, SIGNAL (insertNewStrings(int)), this, SLOT (insertNewStringsImpl(int)));
+	setModel (model);
+}
+
+MultiStringSelector::~MultiStringSelector () {
+	RK_TRACE (MISC);
+
+	// child widgets deleted by qt
+}
+
+QStringList MultiStringSelector::getValues () {
+	RK_TRACE (MISC);
+
+	return model->stringList ();
+}
+
+void MultiStringSelector::setValues (const QStringList& values) {
+	RK_TRACE (MISC);
+
+	model->setStringList (values);
+}
+
+void MultiStringSelector::insertNewStringsImpl (int above_row) {
+	RK_TRACE (MISC);
+
+	QStringList new_strings;
+	emit (getNewStrings (&new_strings));
+	model->insertRows (above_row, new_strings.size ());
+	for (int i = new_strings.size () - 1; i >= 0; --i) {
+		model->setData (model->index (above_row + i, 0), new_strings[i]);
+	}
+}
+
+void MultiStringSelector::swapRowsImpl (int rowa, int rowb) {
+	RK_TRACE (MISC);
+
+	QVariant dummy = model->data (model->index (rowa, 0), Qt::DisplayRole);
+	model->setData (model->index (rowa, 0), model->data (model->index (rowb, 0), Qt::DisplayRole), Qt::DisplayRole);
+	model->setData (model->index (rowb, 0), dummy, Qt::DisplayRole);
+}
+
+RKMultiStringSelectorV2::RKMultiStringSelectorV2 (const QString& label, QWidget* parent) : QWidget (parent) {
+	RK_TRACE (MISC);
+
 	QHBoxLayout *hbox = new QHBoxLayout (this);
 	hbox->setContentsMargins (0, 0, 0, 0);
 
@@ -44,143 +102,114 @@
 	QLabel *label_widget = new QLabel (label, this);
 	main_box->addWidget (label_widget);
 
-	tree_view = new QTreeWidget (this);
-	tree_view->setHeaderLabel (i18n ("Filename"));
+	tree_view = new QTreeView (this);
 	tree_view->setSelectionMode (QAbstractItemView::SingleSelection);
+	tree_view->setSelectionBehavior (QAbstractItemView::SelectRows);
 	tree_view->setSortingEnabled (false);
-	connect (tree_view, SIGNAL (itemSelectionChanged ()), this, SLOT (listSelectionChanged ()));
 	main_box->addWidget (tree_view);
 
 	add_button = new QPushButton (i18n ("Add"), this);
-	connect (add_button, SIGNAL (clicked ()), this, SLOT (addButtonClicked ()));
+	connect (add_button, SIGNAL (clicked ()), this, SLOT (buttonClicked()));
 	button_box->addWidget (add_button);
 
 	remove_button = new QPushButton (i18n ("Remove"), this);
-	connect (remove_button, SIGNAL (clicked ()), this, SLOT (removeButtonClicked ()));
+	connect (remove_button, SIGNAL (clicked ()), this, SLOT (buttonClicked()));
 	button_box->addWidget (remove_button);
 
 	button_box->addSpacing (10);
 
 	up_button = new QPushButton (RKStandardIcons::getIcon (RKStandardIcons::ActionMoveUp), i18n ("Up"), this);
-	connect (up_button, SIGNAL (clicked ()), this, SLOT (upButtonClicked ()));
+	connect (up_button, SIGNAL (clicked ()), this, SLOT (buttonClicked()));
 	button_box->addWidget (up_button);
 
 	down_button = new QPushButton (RKStandardIcons::getIcon (RKStandardIcons::ActionMoveDown), i18n ("Down"), this);
-	connect (down_button, SIGNAL (clicked ()), this, SLOT (downButtonClicked ()));
+	connect (down_button, SIGNAL (clicked ()), this, SLOT (buttonClicked()));
 	button_box->addWidget (down_button);
-
-	listSelectionChanged ();		// causes remove, up, and down buttons to be disabled (since no item is selected)
 }
 
-MultiStringSelector::~MultiStringSelector () {
+RKMultiStringSelectorV2::~RKMultiStringSelectorV2 () {
 	RK_TRACE (MISC);
-
-	// child widgets and listviewitems deleted by qt
 }
 
-QStringList MultiStringSelector::getValues () {
+void RKMultiStringSelectorV2::setModel (QAbstractItemModel* model, int main_column) {
 	RK_TRACE (MISC);
 
-	QStringList list;
-	for (int i = 0; i < tree_view->topLevelItemCount (); ++i) {
-		QTreeWidgetItem* item = tree_view->topLevelItem (i);
-		RK_ASSERT (item);
-		list.append (item->text (0));
+	if (model == tree_view->model ()) return;
 
+	if (tree_view->selectionModel ()) {
+		disconnect (tree_view->selectionModel (), SIGNAL (currentChanged(QModelIndex,QModelIndex)), this, SLOT (updateButtons()));
 	}
-
-	return list;
-}
-
-void MultiStringSelector::setValues (const QStringList& values) {
-	RK_TRACE (MISC);
-
-	tree_view->clear ();
-	for (QStringList::const_iterator it = values.begin (); it != values.end (); ++it) {
-		QTreeWidgetItem* item = new QTreeWidgetItem (tree_view);
-		item->setText (0, (*it));
+	if (tree_view->model ()) {
+		disconnect (tree_view->model (), 0, this, 0);
+		anyModelDataChange ();
 	}
-	listSelectionChanged ();
-	emit (listChanged ());
-}
+	tree_view->setModel (model);
+	connect (tree_view->selectionModel (), SIGNAL (currentChanged(QModelIndex,QModelIndex)), this, SLOT (updateButtons()));
+	connect (model, SIGNAL (dataChanged(QModelIndex,QModelIndex)), this, SLOT (anyModelDataChange()));
+	connect (model, SIGNAL (layoutChanged()), this, SLOT (anyModelDataChange()));
+	connect (model, SIGNAL (rowsInserted(const QModelIndex&,int,int)), this, SLOT (anyModelDataChange()));
+	connect (model, SIGNAL (rowsRemoved(const QModelIndex&,int,int)), this, SLOT (anyModelDataChange()));
+	connect (model, SIGNAL (reset()), this, SLOT (anyModelDataChange()));
 
-void MultiStringSelector::addButtonClicked () {
-	RK_TRACE (MISC);
-
-	tree_view->setFocus ();
-	QStringList new_strings;
-	emit (getNewStrings (&new_strings));
-	for (QStringList::const_iterator it = new_strings.begin (); it != new_strings.end (); ++it) {
-		QTreeWidgetItem* item = new QTreeWidgetItem (tree_view);
-		item->setText (0, (*it));
-	}
-	emit (listChanged ());
-	listSelectionChanged ();		// update button states
+	if (main_column >= 0) tree_view->resizeColumnToContents (main_column);
+	
+	updateButtons ();
 }
 
-QTreeWidgetItem* MultiStringSelector::treeSelectedItem () const {
+void RKMultiStringSelectorV2::buttonClicked () {
 	RK_TRACE (MISC);
 
-	QList<QTreeWidgetItem *> sel = tree_view->selectedItems ();
-	if (sel.isEmpty ()) return 0;
-	RK_ASSERT (sel.count () == 1);
-	return sel[0];
-}
-
-void MultiStringSelector::removeButtonClicked () {
-	RK_TRACE (MISC);
-
 	tree_view->setFocus ();
-	delete (treeSelectedItem ());
-	emit (listChanged ());
-}
-
-void MultiStringSelector::upButtonClicked () {
-	RK_TRACE (MISC);
-
-	tree_view->setFocus ();
-	QTreeWidgetItem* sel = treeSelectedItem ();
-	if (!sel) {
+	if (!tree_view->model ()) {
 		RK_ASSERT (false);
 		return;
 	}
-	int pos = tree_view->indexOfTopLevelItem (sel);
-	if (pos <= 0) return;	// already at top
 
-	tree_view->insertTopLevelItem (pos - 1, tree_view->takeTopLevelItem (pos));
-	tree_view->setCurrentItem (sel);
-	emit (listChanged ());
-}
+	int row = -1;
+	QModelIndex index = tree_view->currentIndex ();
+	if (index.isValid ()) row = index.row ();
 
-void MultiStringSelector::downButtonClicked () {
-	RK_TRACE (MISC);
-
-	tree_view->setFocus ();
-	QTreeWidgetItem* sel = treeSelectedItem ();
-	if (!sel) {
+	if (sender () == add_button) {
+		if (row < 0) row = tree_view->model ()->rowCount ();
+		emit (insertNewStrings (row));
+	} else if (row < 0) {	// all actions below need a valid row
 		RK_ASSERT (false);
-		return;
+	} else if (sender () == remove_button) {
+		tree_view->model ()->removeRow (row);
+	} else {
+		int rowb;
+		if (sender () == up_button) {
+			RK_ASSERT (row >= 0);
+			rowb = qMax (row - 1, 0);
+		} else {
+			RK_ASSERT (sender () == down_button);
+			RK_ASSERT (row < tree_view->model ()->rowCount ());
+			rowb = qMin (row + 1, tree_view->model ()->rowCount () - 1);
+		}
+		emit (swapRows (row, rowb));
+		tree_view->setCurrentIndex (tree_view->model ()->index (rowb, 0));
 	}
-	int pos = tree_view->indexOfTopLevelItem (sel);
-	if (pos >= (tree_view->topLevelItemCount () - 1)) return;	// already at bottom
-
-	tree_view->insertTopLevelItem (pos + 1, tree_view->takeTopLevelItem (pos));
-	tree_view->setCurrentItem (sel);
-	emit (listChanged ());
+	anyModelDataChange ();
 }
 
-void MultiStringSelector::listSelectionChanged () {
+void RKMultiStringSelectorV2::updateButtons () {
 	RK_TRACE (MISC);
 
-	if (treeSelectedItem ()) {
-		remove_button->setEnabled (true);
-		up_button->setEnabled (true);
-		down_button->setEnabled (true);
-	} else {
+	QModelIndex index = tree_view->currentIndex ();
+	if (!index.isValid ()) {
 		remove_button->setEnabled (false);
 		up_button->setEnabled (false);
 		down_button->setEnabled (false);
+	} else {
+		remove_button->setEnabled (true);
+		up_button->setEnabled (index.row () > 0);
+		down_button->setEnabled (index.row () < tree_view->model ()->rowCount () - 1);
 	}
 }
 
+void RKMultiStringSelectorV2::anyModelDataChange () {
+	RK_TRACE (MISC);
+	emit (listChanged ());
+}
+
 #include "multistringselector.moc"

Modified: trunk/rkward/rkward/misc/multistringselector.h
===================================================================
--- trunk/rkward/rkward/misc/multistringselector.h	2013-01-23 18:43:50 UTC (rev 4502)
+++ trunk/rkward/rkward/misc/multistringselector.h	2013-01-25 16:32:55 UTC (rev 4503)
@@ -2,7 +2,7 @@
                           multistringselector  -  description
                              -------------------
     begin                : Fri Sep 10 2005
-    copyright            : (C) 2005 by Thomas Friedrichsmeier
+    copyright            : (C) 2005, 2013 by Thomas Friedrichsmeier
     email                : tfry at users.sourceforge.net
  ***************************************************************************/
 
@@ -22,45 +22,63 @@
 #include <qstringlist.h>
 #include <qstring.h>
 
-class QTreeWidget;
-class QTreeWidgetItem;
+class RKMultiStringSelectorV2;
+class QAbstractItemModel;
 class QPushButton;
+class QStringListModel;
+class QTreeView;
 
+/** A more modern variant of the MultiStringSelector. This operates on a (flat!) QAbstractItemModel.
+ * The model (or a buddy of the model) must connect to insertNewStrings(), and swapRows() for handling Add, Up, and Down buttons.
+ * Further, the model must provide an implementation of removeRows() to make the remove button work.
+
+ at author Thomas Friedrichsmeier
+*/
+class RKMultiStringSelectorV2 : public QWidget {
+	Q_OBJECT
+public:
+	explicit RKMultiStringSelectorV2 (const QString& label, QWidget* parent = 0);
+	virtual ~RKMultiStringSelectorV2 ();
+	void setModel (QAbstractItemModel *model, int main_column=-1);
+public slots:
+	void buttonClicked ();
+	void updateButtons ();
+	void anyModelDataChange ();
+protected:
+	QTreeView* tree_view;
+	QPushButton* add_button;
+	QPushButton* remove_button;
+	QPushButton* up_button;
+	QPushButton* down_button;
+signals:
+	void insertNewStrings (int above_row);
+	void swapRows (int rowa, int rowb);
+/** emitted whenever there is a change in the data selection */
+	void listChanged ();
+};
+
 /** This convenience widget allows to select one or more strings (e.g. filenames) and sort them in any order. The function to acutally select new strings to add to the selection is not implemented in this class for more flexibility. Rather, connect to the getNewStrings () signal and assign the desired QString(s) in a custom slot.
 
 @author Thomas Friedrichsmeier
 */
-class MultiStringSelector : public QWidget {
+class MultiStringSelector : public RKMultiStringSelectorV2 {
 Q_OBJECT
 public:
 	explicit MultiStringSelector (const QString& label, QWidget* parent = 0);
-
 	~MultiStringSelector ();
 
 /** get list of current strings (in the correct order, of course) */
 	QStringList getValues ();
 /** set list of strings. Any strings previously selected are discarded */
 	void setValues (const QStringList& values);
-public slots:
-	void addButtonClicked ();
-	void removeButtonClicked ();
-	void upButtonClicked ();
-	void downButtonClicked ();
-	void listSelectionChanged ();
 private:
-/** convenience function to get the (single) selected item of the tree_view, or 0 if no item is selected */
-	QTreeWidgetItem* treeSelectedItem () const;
-
-	QTreeWidget* tree_view;
-	QPushButton* add_button;
-	QPushButton* remove_button;
-	QPushButton* up_button;
-	QPushButton* down_button;
+	QStringListModel *model;
+private slots:
+	void insertNewStringsImpl (int above_row);
+	void swapRowsImpl (int rowa, int rowb);
 signals:
 /** This signal is triggered, when the "Add"-button is pressed. Connect to this to your custom slot, and add strings to the (empty) string_list. If you don't touch the string_list or set it to empty, nothing will be added to the list. */
 	void getNewStrings (QStringList *string_list);
-/** emitted whenever there is a change in the user selection */
-	void listChanged ();
 };
 
 #endif





More information about the rkward-tracker mailing list