[rkward/work/optionset_experiments] rkward: More progress on the accordion table:
Thomas Friedrichsmeier
thomas.friedrichsmeier at ruhr-uni-bochum.de
Tue Oct 27 09:36:46 UTC 2015
Git commit 80047a0dba538e93a6caee235d50be74e178f5a9 by Thomas Friedrichsmeier.
Committed on 27/10/2015 at 09:35.
Pushed by tfry into branch 'work/optionset_experiments'.
More progress on the accordion table:
- Sane intial size and resizing.
- Add-/Remove buttons connected
M +112 -17 rkward/misc/rkaccordiontable.cpp
M +11 -3 rkward/misc/rkaccordiontable.h
M +28 -8 rkward/plugin/rkoptionset.cpp
M +2 -0 rkward/plugin/rkoptionset.h
http://commits.kde.org/rkward/80047a0dba538e93a6caee235d50be74e178f5a9
diff --git a/rkward/misc/rkaccordiontable.cpp b/rkward/misc/rkaccordiontable.cpp
index 3506fb4..7383919 100644
--- a/rkward/misc/rkaccordiontable.cpp
+++ b/rkward/misc/rkaccordiontable.cpp
@@ -140,6 +140,7 @@ public:
RKWidgetGuard::fallback_parent = fallback_parent;
QVBoxLayout *layout = new QVBoxLayout (this);
+ layout->setContentsMargins (0, 0, 0, 0);
guarded->setParent (this);
layout->addWidget (guarded);
}
@@ -161,7 +162,15 @@ RKAccordionTable::RKAccordionTable (QWidget* parent) : QTreeView (parent) {
RK_TRACE (MISC);
show_add_remove_buttons = false;
- default_widget = new KVBox;
+
+ // This may seem like excessive wrapping. The point is to be able to manipulate the editor_widget_container's sizeHint(), while
+ // keeping the editor_widget's sizeHint() intact.
+ editor_widget_container = new QWidget ();
+ QHBoxLayout *layout = new QHBoxLayout (editor_widget_container);
+ layout->setContentsMargins (0, 0, 0, 0);
+ editor_widget = new KVBox (editor_widget_container);
+ layout->addWidget (editor_widget);
+
setSelectionMode (NoSelection);
setIndentation (0);
setExpandsOnDoubleClick (false); // we expand on single click, instead
@@ -175,18 +184,59 @@ RKAccordionTable::RKAccordionTable (QWidget* parent) : QTreeView (parent) {
RKAccordionTable::~RKAccordionTable () {
RK_TRACE (MISC);
- delete default_widget;
+ delete editor_widget;
}
-QSize RKAccordionTable::minimumSizeHint () const {
+QSize RKAccordionTable::sizeHintWithoutEditor () 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 (QSize (minimumSizeHint ().width (), horizontalScrollBar ()->minimumSizeHint ().height () + sizeHintForRow (0) * 4));
+}
+
+QSize RKAccordionTable::sizeHint () const {
+ RK_TRACE (MISC);
+
+ QSize swoe = sizeHintWithoutEditor ();
+ QSize min = editor_widget->sizeHint ();
+ min.setHeight (min.height () + swoe.height ());
+ min.setWidth (qMax (min.width (), swoe.width ()));
return min;
}
+void RKAccordionTable::resizeEvent (QResizeEvent* event) {
+ RK_TRACE (MISC);
+
+ QSize esh = editor_widget->sizeHint ();
+ int available_height = height () - sizeHintWithoutEditor ().height ();
+ int extra_height = available_height - esh.height ();
+ editor_widget_container->setMinimumHeight (esh.height () + qMax (0, 2 * (extra_height / 3)));
+ editor_widget_container->setMaximumWidth (width ());
+
+ QTreeView::resizeEvent (event);
+
+ // NOTE: For Qt 4.8.6, an expanded editor row will _not_ be updated, automatically.
+ // We have to force this by hiding / unhiding it.
+ QModelIndex expanded;
+ for (int i = 0; i < model ()->rowCount (); ++i) {
+ if (isExpanded (model ()->index (i, 0))) {
+ expanded = model ()->index (i, 0);
+ break;
+ }
+ }
+ if (expanded.isValid ()) {
+ setUpdatesEnabled (false);
+ setRowHidden (0, expanded, true);
+ setRowHidden (0, expanded, false);
+ setUpdatesEnabled (true);
+ }
+}
+
+void RKAccordionTable::activateRow (int row) {
+ RK_TRACE (MISC);
+
+ setExpanded (model ()->index (row, 0), true);
+}
+
void RKAccordionTable::rowClicked (QModelIndex row) {
RK_TRACE (MISC);
@@ -206,8 +256,10 @@ void RKAccordionTable::rowExpanded (QModelIndex row) {
}
}
setFirstColumnSpanned (0, row, true);
- setIndexWidget (model ()->index (0, 0, row), new RKWidgetGuard (0, default_widget, this));
+ setIndexWidget (model ()->index (0, 0, row), new RKWidgetGuard (0, editor_widget_container, this));
setCurrentIndex (row);
+ scrollTo (row, EnsureVisible); // yes, we want both scrolls: We want the header row above the widget, if possible at all,
+ scrollTo (model ()->index (0, 0, row), EnsureVisible); // but of course, having the header row visible without the widget is not enough...
emit (activated (row.row ()));
}
@@ -227,14 +279,19 @@ void RKAccordionTable::updateWidget () {
QHBoxLayout *layout = new QHBoxLayout (display_buttons);
layout->setContentsMargins (0, 0, 0, 0);
layout->setSpacing (0);
+
QToolButton *add_button = new QToolButton (display_buttons);
+ connect (add_button, SIGNAL (clicked(bool)), this, SLOT (addClicked()));
add_button->setIcon (RKStandardIcons::getIcon (RKStandardIcons::ActionInsertRow));
RKCommonFunctions::setTips (i18n ("Add a row / element"), add_button);
+ layout->addWidget (add_button);
+
QToolButton *remove_button = new QToolButton (display_buttons);
+ connect (remove_button, SIGNAL (clicked(bool)), this, SLOT (removeClicked()));
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);
}
}
@@ -242,6 +299,46 @@ void RKAccordionTable::updateWidget () {
if (show_add_remove_buttons) header ()->setResizeMode (0, QHeaderView::ResizeToContents);
}
+int RKAccordionTable::rowOfButton (QObject* button) const {
+ RK_TRACE (MISC);
+
+ if (!button) return -1;
+
+ // we rely on the fact that the buttons in use, here, are encapsulaped in a parent widget, which is set as indexWidget()
+ QObject* button_parent = button->parent ();
+ for (int i = model ()->rowCount () - 1; i >= 0; --i) {
+ QModelIndex row = model ()->index (i, 0);
+ if (button_parent == indexWidget (row)) {
+ return i;
+ }
+ }
+ RK_ASSERT (false);
+ return -1;
+}
+
+
+void RKAccordionTable::addClicked () {
+ RK_TRACE (MISC);
+
+ int row = rowOfButton (sender ());
+ if (row < 0) {
+ RK_ASSERT (row >= 0);
+ return;
+ }
+ emit (addRow (row));
+}
+
+void RKAccordionTable::removeClicked () {
+ RK_TRACE (MISC);
+
+ int row = rowOfButton (sender ());
+ if (row < 0) {
+ RK_ASSERT (row >= 0);
+ return;
+ }
+ emit (removeRow (row));
+}
+
void RKAccordionTable::setModel (QAbstractItemModel* model) {
RK_TRACE (MISC);
@@ -252,19 +349,17 @@ void RKAccordionTable::setModel (QAbstractItemModel* model) {
connect (pmodel, SIGNAL (rowsRemoved(const QModelIndex&,int,int)), this, SLOT (updateWidget()));
if (pmodel->rowCount () > 0) expand (pmodel->index (0, 0));
-}
-void RKAccordionTable::resizeEvent (QResizeEvent* event) {
- // TODO
- QTreeView::resizeEvent (event);
+ updateGeometry (); // TODO: Not so clean to call this, here. But at this point we know the display_widget has been constructed, too
}
+
// TODO
-// - add buttons to each row (in correct size)
-// - handle resize
-// - fix initial size
-// - margins
-// - handle row insertions / removals correctly
+// - insertion when now row is available, yet
+// - expand / collapse indicator?
+// - drag-reordering?
+// - will this make per-item add buttons obsolete?
+
// KF5 TODO: remove:
#include "rkaccordiontable.moc"
#include "rkaccordiontablemodel_moc.cpp"
diff --git a/rkward/misc/rkaccordiontable.h b/rkward/misc/rkaccordiontable.h
index 5e68f54..b4af29c 100644
--- a/rkward/misc/rkaccordiontable.h
+++ b/rkward/misc/rkaccordiontable.h
@@ -30,25 +30,33 @@ public:
RKAccordionTable (QWidget *parent);
~RKAccordionTable ();
- QWidget *defaultWidget () const { return default_widget; };
+ QWidget *editorWidget () const { return editor_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
+ QSize sizeHint () const; // reimplemented to assure a proper size for the content
public slots:
void rowExpanded (QModelIndex row);
void rowClicked (QModelIndex row);
void updateWidget ();
+ void addClicked ();
+ void removeClicked ();
+ void activateRow (int row);
signals:
void activated (int row);
+ void addRow (int where);
+ void removeRow (int which);
protected:
void resizeEvent (QResizeEvent* event); // reimplemented to make the current content widget stretch / shrink
private:
+ QSize sizeHintWithoutEditor () const;
+ int rowOfButton (QObject *button) const;
bool show_add_remove_buttons;
- QWidget *default_widget;
+ QWidget *editor_widget;
+ QWidget *editor_widget_container;
QAbstractProxyModel *pmodel;
};
diff --git a/rkward/plugin/rkoptionset.cpp b/rkward/plugin/rkoptionset.cpp
index 13d4737..00fa92e 100644
--- a/rkward/plugin/rkoptionset.cpp
+++ b/rkward/plugin/rkoptionset.cpp
@@ -58,7 +58,9 @@ RKOptionSet::RKOptionSet (const QDomElement &element, RKComponent *parent_compon
switcher->addWidget (user_area);
if (exp_mode == Accordion) {
accordion = new RKAccordionTable (user_area);
- connect (accordion, SIGNAL(activated(int)), this, SLOT(currentRowChanged(int)));
+ connect (accordion, SIGNAL (activated(int)), this, SLOT(currentRowChanged(int)));
+ connect (accordion, SIGNAL (addRow(int)), this, SLOT(addRow(int)));
+ connect (accordion, SIGNAL (removeRow(int)), this, SLOT(removeRow(int)));
}
updating_notice = new QLabel (i18n ("Updating status, please wait"), this);
switcher->addWidget (updating_notice);
@@ -83,10 +85,10 @@ RKOptionSet::RKOptionSet (const QDomElement &element, RKComponent *parent_compon
// first build the contents, as we will need to refer to the elements inside, later
model = 0;
display = 0; // will be created from the builder, on demand -> createDisplay ()
- contents_container = new RKComponent (this, exp_mode == RKOptionSet::Accordion ? accordion->defaultWidget () : user_area);
+ contents_container = new RKComponent (this, exp_mode == RKOptionSet::Accordion ? accordion->editorWidget () : user_area);
QDomElement content_element = xml->getChildElement (element, "content", DL_ERROR);
RKComponentBuilder *builder = new RKComponentBuilder (contents_container, content_element);
- builder->buildElement (content_element, *xml, exp_mode == Accordion ? accordion->defaultWidget () : user_area, false); // NOTE that parent widget != parent component, here, by intention. The point is that the display should not be disabled along with the contents
+ builder->buildElement (content_element, *xml, exp_mode == Accordion ? accordion->editorWidget () : user_area, false); // NOTE that parent widget != parent component, here, by intention. The point is that the display should not be disabled along with the contents
builder->parseLogic (xml->getChildElement (element, "logic", DL_INFO), *xml, false);
builder->makeConnections ();
addChild ("contents", contents_container);
@@ -180,7 +182,6 @@ RKOptionSet::RKOptionSet (const QDomElement &element, RKComponent *parent_compon
else display->setColumnHidden (0, true);
display->setModel (model);
if (exp_mode == Detached) display->setItemDelegate (new RKOptionSetDelegate (this));
- if (exp_mode == Accordion) accordion->setModel (model);
display->setSelectionBehavior (QAbstractItemView::SelectRows);
display->setSelectionMode (QAbstractItemView::SingleSelection);
connect (display->selectionModel (), SIGNAL (selectionChanged(QItemSelection,QItemSelection)), this, SLOT (currentRowChanged()));
@@ -192,6 +193,10 @@ RKOptionSet::RKOptionSet (const QDomElement &element, RKComponent *parent_compon
}
}
if (!keycolumn && (exp_mode == Accordion)) accordion->setShowAddRemoveButtons (true);
+ if (exp_mode == Accordion) {
+ accordion->setModel (model);
+ if (display) display->hide ();
+ }
}
RKOptionSet::~RKOptionSet () {
@@ -202,7 +207,7 @@ void RKOptionSet::fetchDefaults () {
RK_TRACE (PLUGIN);
RK_ASSERT (default_row_state.isEmpty ());
contents_container->fetchPropertyValuesRecursive (&default_row_state, false, QString (), true);
- if (min_rows && !keycolumn && (rowCount () <= 0)) addRow ();
+ if (min_rows && !keycolumn && (rowCount () <= 0)) addRow (rowCount ());
contents_container->enablednessProperty ()->setBoolValue (rowCount () > 0); // no current row; Do this *after* fetching default values, however. Otherwise most values will *not* be read, as the element is disabled
}
@@ -416,14 +421,19 @@ void RKOptionSet::updateUnfinishedRows () {
RK_ASSERT (false); // This would mean, we did not find any unfinished row, even though we tested for n_unfinished_rows, above.
}
+// TODO: removeMe
void RKOptionSet::addRow () {
RK_TRACE (PLUGIN);
+ addRow (active_row >= 0 ? active_row + 1 : rowCount ()); // append feels more natural than insert, here
+}
+
+void RKOptionSet::addRow (int row) {
+ RK_TRACE (PLUGIN);
storeRowSerialization (active_row);
- int row = active_row + 1; // append feels more natural than insert, here
int nrows = rowCount ();
- if (row <= 0) row = nrows;
+ if (row < 0) row = nrows;
RK_ASSERT (!keycolumn);
if (display) model->beginInsertRows (QModelIndex (), row, row);
@@ -455,10 +465,15 @@ void RKOptionSet::addRow () {
changed ();
}
+// TODO: removeMe
void RKOptionSet::removeRow () {
RK_TRACE (PLUGIN);
+ removeRow (active_row);
+}
+
+void RKOptionSet::removeRow (int row) {
+ RK_TRACE (PLUGIN);
- int row = active_row;
int nrows = rowCount ();
if (row < 0) {
RK_ASSERT (false);
@@ -757,6 +772,11 @@ void RKOptionSet::updateCurrentRowInDisplay () {
else {
display->selectionModel ()->select (display->model ()->index (active_row, 0), QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
}
+
+ if (exp_mode == Accordion) {
+ if (active_row < 0) accordion->collapseAll ();
+ else accordion->activateRow (active_row);
+ }
}
void RKOptionSet::currentRowChanged () {
diff --git a/rkward/plugin/rkoptionset.h b/rkward/plugin/rkoptionset.h
index 095190f..ad52247 100644
--- a/rkward/plugin/rkoptionset.h
+++ b/rkward/plugin/rkoptionset.h
@@ -52,7 +52,9 @@ private slots:
void columnPropertyChanged (RKComponentPropertyBase *property);
void currentRowPropertyChanged (RKComponentPropertyBase *property);
void serializationPropertyChanged (RKComponentPropertyBase *property);
+ void addRow (int where);
void addRow ();
+ void removeRow (int which);
void removeRow ();
void currentRowChanged ();
void currentRowChanged (int row);
More information about the rkward-tracker
mailing list