[rkward/work/optionset_experiments] rkward: Accordion control is starting to look usable (but still unfinished and with many quirks).

Thomas Friedrichsmeier thomas.friedrichsmeier at ruhr-uni-bochum.de
Mon Oct 26 19:14:18 UTC 2015


Git commit 41eaaa05b9c48292528d01170eddad5f5b41c5ca by Thomas Friedrichsmeier.
Committed on 26/10/2015 at 19:13.
Pushed by tfry into branch 'work/optionset_experiments'.

Accordion control is starting to look usable (but still unfinished and with many quirks).

M  +84   -20   rkward/misc/rkaccordiontable.cpp
M  +10   -1    rkward/misc/rkaccordiontable.h
M  +12   -3    rkward/plugin/rkoptionset.cpp
M  +1    -0    rkward/plugin/rkoptionset.h

http://commits.kde.org/rkward/41eaaa05b9c48292528d01170eddad5f5b41c5ca

diff --git a/rkward/misc/rkaccordiontable.cpp b/rkward/misc/rkaccordiontable.cpp
index daa8f73..3506fb4 100644
--- a/rkward/misc/rkaccordiontable.cpp
+++ b/rkward/misc/rkaccordiontable.cpp
@@ -20,7 +20,14 @@
 #include <QPointer>
 #include <QVBoxLayout>
 #include <QAbstractProxyModel>
+#include <QToolButton>
+#include <QHBoxLayout>
+
 #include <kvbox.h>
+#include <klocale.h>
+
+#include "rkcommonfunctions.h"
+#include "rkstandardicons.h"
 
 #include "../debug.h"
 
@@ -86,9 +93,10 @@ public:
 
 	void setSourceModel (QAbstractItemModel* source_model) {
 		/* More than these would be needed for a proper proxy of any model, but in our case, we only have to support the RKOptionsetDisplayModel */
-		connect (source_model, SIGNAL (rowsInserted(const QModelIndex&,int,int)), this, SLOT (rowsInserted(QModelIndex,int,int)));
-		connect (source_model, SIGNAL (rowsRemoved(const QModelIndex&,int,int)), this, SLOT (rowsRemoved(QModelIndex,int,int)));
-		connect (source_model, SIGNAL (layoutChanged()), this, SLOT (relayLayoutChange()));
+		connect (source_model, SIGNAL (rowsInserted(const QModelIndex&,int,int)), this, SLOT (r_rowsInserted(QModelIndex,int,int)));
+		connect (source_model, SIGNAL (rowsRemoved(const QModelIndex&,int,int)), this, SLOT (r_rowsRemoved(QModelIndex,int,int)));
+		connect (source_model, SIGNAL (dataChanged(QModelIndex,QModelIndex)), this, SLOT (r_dataChanged(QModelIndex,QModelIndex)));
+		connect (source_model, SIGNAL (layoutChanged()), this, SLOT (r_layoutChanged()));
 		QAbstractProxyModel::setSourceModel (source_model);
 	}
 
@@ -98,27 +106,29 @@ public:
 
 	static const quint32 real_item_id = 0xFFFFFFFF;
 public slots:
-	void rowsInserted (const QModelIndex& parent, int start, int end) {
+	void r_rowsInserted (const QModelIndex& parent, int start, int end) {
 		RK_TRACE (MISC);
 		RK_ASSERT (!parent.isValid ());
 
 		beginInsertRows (mapFromSource (parent), start, end);
 		endInsertRows ();
 	}
-	void rowsRemoved (const QModelIndex& parent, int start, int end) {
+	void r_rowsRemoved (const QModelIndex& parent, int start, int end) {
 		RK_TRACE (MISC);
 		RK_ASSERT (!parent.isValid ());
 
 		beginRemoveRows (mapFromSource (parent), start, end);
 		endRemoveRows ();
 	}
-	void relayLayoutChange () {
+	void r_dataChanged (const QModelIndex& from, const QModelIndex& to) {
+		emit (dataChanged (mapFromSource (from), mapFromSource (to)));
+	}
+	void r_layoutChanged () {
  		RK_DEBUG (MISC, DL_ERROR, "reset");
 		emit (layoutChanged());
 	}
 };
 
-
 /** Protects the given child widget from deletion */
 class RKWidgetGuard : public QWidget {
 public:
@@ -145,16 +155,21 @@ private:
 	QWidget *fallback_parent;
 };
 
-#include <QLabel>
+#include <QScrollBar>
+#include <QHeaderView>
 RKAccordionTable::RKAccordionTable (QWidget* parent) : QTreeView (parent) {
 	RK_TRACE (MISC);
 
+	show_add_remove_buttons = false;
 	default_widget = new KVBox;
-	new QLabel ("This is the content\nExcept it's just a dummy!!!!!!!!!!!!!!!", default_widget);
-	setSelectionBehavior (SelectRows);
-	setSelectionMode (SingleSelection);
+	setSelectionMode (NoSelection);
+	setIndentation (0);
+	setExpandsOnDoubleClick (false);   // we expand on single click, instead
+	setSizePolicy (QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
+	setViewportMargins (20, 0, 0, 0);
 	pmodel = new RKAccordionDummyModel (this);
 	connect (this, SIGNAL (expanded(QModelIndex)), this, SLOT (rowExpanded(QModelIndex)));
+	connect (this, SIGNAL (clicked(QModelIndex)), this, SLOT (rowClicked(QModelIndex)));
 }
 
 RKAccordionTable::~RKAccordionTable () {
@@ -163,14 +178,21 @@ RKAccordionTable::~RKAccordionTable () {
 	delete default_widget;
 }
 
-void RKAccordionTable::currentChanged (const QModelIndex& current, const QModelIndex& previous) {
+QSize RKAccordionTable::minimumSizeHint () const {
+	RK_TRACE (MISC);
+
+	QSize min = default_widget->minimumSize ();
+	min.setHeight (min.height () + horizontalScrollBar ()->minimumSizeHint ().height () + sizeHintForRow (0) * 4);
+	min.setWidth (qMax (min.width (), QTreeView::minimumSizeHint ().width ()));
+	return min;
+}
+
+void RKAccordionTable::rowClicked (QModelIndex row) {
 	RK_TRACE (MISC);
-	RK_ASSERT (current.isValid ());
-	Q_UNUSED (previous);
-// TODO: needed?
-	return;
-	if (!isExpanded (current)) {
-		expand (current);
+
+	row = model ()->index (row.row (), 0, row.parent ());   // Fix up index to point to column 0, or isExpanded() will always return false
+	if (!row.parent ().isValid ()) {
+		setExpanded (row, !isExpanded (row));
 	}
 }
 
@@ -178,10 +200,46 @@ void RKAccordionTable::rowExpanded (QModelIndex row) {
 	RK_TRACE (MISC);
 
 	for (int i = 0; i < model ()->rowCount (); ++i) {
-		if (i != row.row ()) setExpanded (model ()->index (i, 0), false);
+		if (i != row.row ()) {
+			setIndexWidget (model ()->index (0, 0, model ()->index (i, 0)), 0);
+			setExpanded (model ()->index (i, 0), false);
+		}
 	}
 	setFirstColumnSpanned (0, row, true);
 	setIndexWidget (model ()->index (0, 0, row), new RKWidgetGuard (0, default_widget, this));
+	setCurrentIndex (row);
+	emit (activated (row.row ()));
+}
+
+void RKAccordionTable::updateWidget () {
+	RK_TRACE (MISC);
+
+	bool seen_expanded = false;
+	for (int i = 0; i < model ()->rowCount (); ++i) {
+		QModelIndex row = model ()->index (i, 0);
+		if (isExpanded (row) && !seen_expanded) {
+			rowExpanded (row);
+			seen_expanded = true;
+		}
+
+		if (show_add_remove_buttons && (indexWidget (row) == 0)) {
+			QWidget *display_buttons = new QWidget;
+			QHBoxLayout *layout = new QHBoxLayout (display_buttons);
+			layout->setContentsMargins (0, 0, 0, 0);
+			layout->setSpacing (0);
+			QToolButton *add_button = new QToolButton (display_buttons);
+			add_button->setIcon (RKStandardIcons::getIcon (RKStandardIcons::ActionInsertRow));
+			RKCommonFunctions::setTips (i18n ("Add a row / element"), add_button);
+			QToolButton *remove_button = new QToolButton (display_buttons);
+			remove_button->setIcon (RKStandardIcons::getIcon (RKStandardIcons::ActionDeleteRow));
+			RKCommonFunctions::setTips (i18n ("Remove a row / element"), remove_button);
+			layout->addWidget (add_button);
+			layout->addWidget (remove_button);
+			setIndexWidget (row, display_buttons);
+		}
+	}
+
+	if (show_add_remove_buttons) header ()->setResizeMode (0, QHeaderView::ResizeToContents);
 }
 
 void RKAccordionTable::setModel (QAbstractItemModel* model) {
@@ -189,6 +247,9 @@ void RKAccordionTable::setModel (QAbstractItemModel* model) {
 
 	pmodel->setSourceModel (model);
 	QTreeView::setModel (pmodel);
+	connect (pmodel, SIGNAL (layoutChanged()), this, SLOT (updateWidget()));
+	connect (pmodel, SIGNAL (rowsInserted(const QModelIndex&,int,int)), this, SLOT (updateWidget()));
+	connect (pmodel, SIGNAL (rowsRemoved(const QModelIndex&,int,int)), this, SLOT (updateWidget()));
 
 	if (pmodel->rowCount () > 0) expand (pmodel->index (0, 0));
 }
@@ -199,8 +260,11 @@ void RKAccordionTable::resizeEvent (QResizeEvent* event) {
 }
 
 // TODO
-// - add buttons to each row
+// - add buttons to each row (in correct size)
 // - handle resize
+// - fix initial size
+// - margins
+// - handle row insertions / removals correctly
 // KF5 TODO: remove:
 #include "rkaccordiontable.moc"
 #include "rkaccordiontablemodel_moc.cpp"
diff --git a/rkward/misc/rkaccordiontable.h b/rkward/misc/rkaccordiontable.h
index 7fc5530..5e68f54 100644
--- a/rkward/misc/rkaccordiontable.h
+++ b/rkward/misc/rkaccordiontable.h
@@ -33,12 +33,21 @@ public:
 	QWidget *defaultWidget () const { return default_widget; };
 
 	void setModel (QAbstractItemModel *model);
+	void setShowAddRemoveButtons (bool show) {
+		show_add_remove_buttons = show;
+	}
+
+	QSize minimumSizeHint () const;                                                  // reimplemented to assure a proper size for the content
 public slots:
 	void rowExpanded (QModelIndex row);
+	void rowClicked (QModelIndex row);
+	void updateWidget ();
+signals:
+	void activated (int row);
 protected:
-	void currentChanged (const QModelIndex& current, const QModelIndex& previous);   // reimplemented to adjust selection / activate correct row
 	void resizeEvent (QResizeEvent* event);                                          // reimplemented to make the current content widget stretch / shrink
 private:
+	bool show_add_remove_buttons;
 	QWidget *default_widget;
 	QAbstractProxyModel *pmodel;
 };
diff --git a/rkward/plugin/rkoptionset.cpp b/rkward/plugin/rkoptionset.cpp
index 6b12b95..13d4737 100644
--- a/rkward/plugin/rkoptionset.cpp
+++ b/rkward/plugin/rkoptionset.cpp
@@ -56,7 +56,10 @@ RKOptionSet::RKOptionSet (const QDomElement &element, RKComponent *parent_compon
 	if (exp_mode != Detached) layout->addWidget (switcher);
 	user_area = new KVBox (this);
 	switcher->addWidget (user_area);
-	if (exp_mode == Accordion) accordion = new RKAccordionTable (user_area);
+	if (exp_mode == Accordion) {
+		accordion = new RKAccordionTable (user_area);
+		connect (accordion, SIGNAL(activated(int)), this, SLOT(currentRowChanged(int)));
+	}
 	updating_notice = new QLabel (i18n ("Updating status, please wait"), this);
 	switcher->addWidget (updating_notice);
 	update_timer.setInterval (0);
@@ -188,6 +191,7 @@ RKOptionSet::RKOptionSet (const QDomElement &element, RKComponent *parent_compon
 			connect (remove_button, SIGNAL (clicked()), this, SLOT (removeRow()));
 		}
 	}
+	if (!keycolumn && (exp_mode == Accordion)) accordion->setShowAddRemoveButtons (true);
 }
 
 RKOptionSet::~RKOptionSet () {
@@ -759,8 +763,13 @@ void RKOptionSet::currentRowChanged () {
 	RK_TRACE (PLUGIN);
 
 	RK_ASSERT (display);
-	int r = getCurrentRowFromDisplay (display);
-	if (active_row != r) current_row->setIntValue (r);
+	currentRowChanged (getCurrentRowFromDisplay (display));
+}
+
+void RKOptionSet::currentRowChanged (int row) {
+	RK_TRACE (PLUGIN);
+
+	if (active_row != row) current_row->setIntValue (row);
 	// --> currentRowPropertyChanged ()
 }
 
diff --git a/rkward/plugin/rkoptionset.h b/rkward/plugin/rkoptionset.h
index aa2e949..095190f 100644
--- a/rkward/plugin/rkoptionset.h
+++ b/rkward/plugin/rkoptionset.h
@@ -55,6 +55,7 @@ private slots:
 	void addRow ();
 	void removeRow ();
 	void currentRowChanged ();
+	void currentRowChanged (int row);
 	void fetchDefaults ();
 	void slotUpdateUnfinishedRows ();
 /** When keys in the key column change, all other columns have to be updated, accordingly. */



More information about the rkward-tracker mailing list