Commit 2dd44d09 authored by André Hoarau's avatar André Hoarau
Browse files

Merge branch '72-parcellaire-afficher-masquer-par-niveau' into 'master'

Resolve "Parcellaire: afficher/masquer par niveau"

Closes #72

See merge request !33
parents 3a8d1fd1 b9322e9a
......@@ -16,7 +16,7 @@ stages:
lint:
stage: lint
script:
script:
- qmllint desktop/qml/*.qml
build:
......
......@@ -5,6 +5,7 @@ All notable changes to this project will be documented in this file.
## Unreleased
### Added
- *Field map* − Add button, menu and shortcuts to expand/collapse location level.
- Keyboard shortcuts for the most common actions (see user guide in the wiki
for more details).
- *Settings* − Add restart snackbar.
......@@ -19,6 +20,7 @@ All notable changes to this project will be documented in this file.
version. Each script will applied successively to reach the latest version.
### Changed
- *Field map* − Attach show/hide button to the plantings pane.
- Update French translation.
### Fixed
......
......@@ -224,6 +224,7 @@ bool LocationModel::addLocations(const QString &baseName, int length, double wid
}
}
QSqlDatabase::database().commit();
depthChanged();
return true;
}
......@@ -299,25 +300,72 @@ bool LocationModel::removeIndexes(const QModelIndexList &indexList)
}
location->removeList(idList);
depthChanged();
return tmodel->removeIndexes(sourceIndexList);
}
/** Return a list of all QModelIndex of location tree. */
QModelIndexList LocationModel::treeIndexes() const
/*!
* Return a list of all QModelIndex of location tree.
*
* If \a depth is greater or equal to 0, only indexes of this depth
* will be return, including their parents if \a includeParent is true.
*/
QModelIndexList LocationModel::treeIndexes(int depth, bool includeParent) const
{
QModelIndex root;
QModelIndexList treeList;
QModelIndexList tmpList;
QModelIndexList indexList;
QMap<QModelIndex, int> indexDepth;
for (int row = 0; row < rowCount(root); row++) {
QModelIndex idx = index(row, 0, root);
tmpList.push_back(idx);
indexDepth[idx] = 0;
if (depth < 0 || indexDepth[idx] == depth || (indexDepth[idx] < depth && includeParent))
indexList.push_back(idx);
}
for (int row = 0; row < rowCount(root); row++)
treeList.push_back(index(row, 0, root));
for (int i = 0; i < tmpList.length(); i++) {
QModelIndex parent = tmpList[i];
for (int row = 0; row < rowCount(parent); row++) {
QModelIndex idx = index(row, 0, parent);
indexDepth[idx] = indexDepth.value(parent) + 1;
if (indexDepth[idx] < depth)
tmpList.push_back(idx);
if (depth < 0 || indexDepth[idx] == depth || (indexDepth[idx] < depth && includeParent))
indexList.push_back(idx);
}
}
for (int i = 0; i < treeList.length(); i++) {
QModelIndex parent = treeList[i];
for (int row = 0; row < rowCount(parent); row++)
treeList.push_back(index(row, 0, parent));
return indexList;
}
int LocationModel::depth() const
{
QModelIndex root;
QModelIndexList tmpList;
QMap<QModelIndex, int> indexDepth;
int d = 0;
for (int row = 0; row < rowCount(root); row++) {
QModelIndex idx = index(row, 0, root);
tmpList.push_back(idx);
indexDepth[idx] = 0;
}
for (int i = 0; i < tmpList.length(); i++) {
QModelIndex parent = tmpList[i];
for (int row = 0; row < rowCount(parent); row++) {
QModelIndex idx = index(row, 0, parent);
indexDepth[idx] = indexDepth.value(parent) + 1;
tmpList.push_back(idx);
if (indexDepth[idx] > d)
d = indexDepth[idx];
}
}
return treeList;
return d;
}
/** Return a list of all QModelIndex of location tree. */
......
......@@ -33,6 +33,7 @@ class CORESHARED_EXPORT LocationModel : public SortFilterProxyModel
Q_PROPERTY(bool showOnlyEmptyLocations READ showOnlyEmptyLocations WRITE
setShowOnlyEmptyLocations NOTIFY showOnlyEmptyLocationsChanged)
Q_PROPERTY(int depth READ depth NOTIFY depthChanged)
public:
LocationModel(QObject *parent = nullptr, const QString &tableName = "location");
......@@ -56,7 +57,8 @@ public:
Q_INVOKABLE bool duplicateLocations(const QModelIndexList &indexList);
Q_INVOKABLE bool updateIndexes(const QVariantMap &map, const QModelIndexList &indexList);
Q_INVOKABLE bool removeIndexes(const QModelIndexList &indexList);
Q_INVOKABLE QModelIndexList treeIndexes() const;
Q_INVOKABLE QModelIndexList treeIndexes(int depth = -1, bool includeParent = true) const;
Q_INVOKABLE int depth() const;
Q_INVOKABLE QItemSelection treeSelection() const;
Q_INVOKABLE QModelIndexList treeHasIds(const QVariantList &idList) const;
Q_INVOKABLE virtual void refresh() override;
......@@ -69,6 +71,7 @@ protected:
signals:
void showOnlyEmptyLocationsChanged();
void depthChanged();
private:
bool m_showOnlyEmptyLocations;
......
......@@ -41,6 +41,7 @@ Item {
property alias draggedPlantingId: treeView.draggedPlantingId
property LocationModel locationModel
property alias treeDepth: locationModel.depth
property int treeViewHeight: treeView.flickableItem.contentHeight
property int treeViewWidth: treeView.implicitWidth
property bool alwaysShowCheckbox: false
......@@ -99,8 +100,16 @@ Item {
}
}
function collapseAll() {
var indexList = locationModel.treeIndexes();
function expandAll(depth) {
var indexList = locationModel.treeIndexes(depth);
for (var i = 0; i < indexList.length; i++) {
var index = indexList[i];
treeView.expand(index);
}
}
function collapseAll(depth) {
var indexList = locationModel.treeIndexes(depth, false);
for (var i = 0; i < indexList.length; i++) {
var index = indexList[i];
treeView.collapse(index);
......@@ -289,29 +298,35 @@ Item {
ThinDivider { anchors { bottom: parent.bottom; left: parent.left; right: parent.right } }
}
ScrollView {
id: scrollView
anchors {
top: headerRectangle.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
// ScrollView {
// id: scrollView
// anchors {
// top: headerRectangle.bottom
// left: parent.left
// right: parent.right
// bottom: parent.bottom
// }
clip: true
// clip: true
Flickable {
id: flickable
// Flickable {
// id: flickable
boundsBehavior: Flickable.StopAtBounds
contentHeight: treeView.flickableItem.contentHeight
contentWidth: width
// boundsBehavior: Flickable.StopAtBounds
// contentHeight: treeView.flickableItem.contentHeight
// contentWidth: width
ScrollBar.vertical: ScrollBar { id: verticalScrollBar }
// ScrollBar.vertical: ScrollBar { id: verticalScrollBar }
Controls1.TreeView {
id: treeView
anchors.fill: parent
// anchors.fill: parent
anchors {
top: headerRectangle.bottom
left: parent.left
right: parent.right
bottom: parent.bottom
}
property int draggedPlantingId: -1
property date plantingDate: Planting.plantingDate(draggedPlantingId)
......@@ -336,7 +351,7 @@ Item {
frameVisible: false
horizontalScrollBarPolicy: Qt.ScrollBarAlwaysOff
verticalScrollBarPolicy: Qt.ScrollBarAlwaysOff
verticalScrollBarPolicy: Qt.ScrollBarAsNeeded
implicitWidth: headerRectangle.implicitWidth + 80
Controls1.TableViewColumn {
......@@ -684,5 +699,5 @@ Item {
}
}
}
}
}
// }
//}
......@@ -31,6 +31,7 @@ Page {
property alias season: seasonSpinBox.season
property alias hasSelection: locationView.hasSelection
property alias rowCount: locationView.rowCount
property bool showPlantingsPane: true
function refresh() {
locationView.refresh();
......@@ -57,6 +58,14 @@ Page {
onActivated: filterField.forceActiveFocus();
}
Shortcut {
sequence: "Ctrl+P"
enabled: navigationIndex === 2 && filterField.visible && !addDialog.activeFocus && !editDialog.activeFocus
context: Qt.ApplicationShortcut
onActivated: showPlantingPaneButton.clicked()
}
Shortcut {
sequence: "Ctrl+Right"
enabled: navigationIndex === 2 && filterField.visible && !addDialog.activeFocus && !editDialog.activeFocus
......@@ -97,6 +106,41 @@ Page {
onActivated: seasonSpinBox.previousYear();
}
Shortcut {
sequence: "Shift+A"
enabled: navigationIndex === 2 && filterField.visible && !addDialog.activeFocus && !editDialog.activeFocus
context: Qt.ApplicationShortcut
onActivated: expandButton.expandLevel(0)
}
Shortcut {
sequence: "Shift+B"
enabled: navigationIndex === 2 && filterField.visible && !addDialog.activeFocus && !editDialog.activeFocus
context: Qt.ApplicationShortcut
onActivated: expandButton.expandLevel(1)
}
Shortcut {
sequence: "Shift+C"
enabled: navigationIndex === 2 && filterField.visible && !addDialog.activeFocus && !editDialog.activeFocus
context: Qt.ApplicationShortcut
onActivated: expandButton.expandLevel(2)
}
Shortcut {
sequence: "Shift+D"
enabled: navigationIndex === 2 && filterField.visible && !addDialog.activeFocus && !editDialog.activeFocus
context: Qt.ApplicationShortcut
onActivated: expandButton.expandLevel(3)
}
Shortcut {
sequence: "Shift+E"
enabled: navigationIndex === 2 && filterField.visible && !addDialog.activeFocus && !editDialog.activeFocus
context: Qt.ApplicationShortcut
onActivated: expandButton.expandLevel(4)
}
onEditModeChanged: {
if (!editMode) {
locationView.clearSelection();
......@@ -225,6 +269,56 @@ Page {
}
}
RoundButton {
id: expandButton
flat: true
text: "\ue313"
font.family: "Material Icons"
font.pixelSize: 24
onClicked: expandMenu.open();
property int depth: locationView.treeDepth
property var expandBoolList: ({})
function expandLevel(level) {
if (expandBoolList[level]) {
locationView.collapseAll(level, false)
} else {
locationView.expandAll(level)
for (var i = 0; i < level; i++)
expandBoolList[i] = true
}
expandBoolList[level] = !expandBoolList[level]
expandBoolListChanged();
}
Component.onCompleted: {
for (var i; i < depth; i++)
expandBoolList[i+1] = false
}
ToolTip.text: qsTr("Expand and collapse location levels")
ToolTip.delay: Units.shortDuration
ToolTip.visible: hovered
Menu {
id: expandMenu
y: expandButton.height
Repeater {
model: expandButton.depth
MenuItem {
text: index + 1
checkable: true
checked: expandButton.expandBoolList[index]
? expandButton.expandBoolList[index]
: false
onTriggered: expandButton.expandLevel(index)
}
}
}
}
Button {
id: duplicateButton
flat: true
......@@ -261,13 +355,13 @@ Page {
}
}
CheckBox {
id: unassignedPlantingsCheckbox
text: qsTr("Show unassigned plantings")
Layout.leftMargin: 16
visible: !editMode
checked: true
}
// CheckBox {
// id: unassignedPlantingsCheckbox
// text: qsTr("Show unassigned plantings")
// Layout.leftMargin: 16
// visible: !editMode
// checked: true
// }
CheckBox {
id: emptyLocationsCheckbox
......@@ -313,7 +407,7 @@ Page {
top: topDivider.bottom
bottom: parent.bottom
horizontalCenter: parent.horizontalCenter
margins: Units.smallSpacing
margins: 0
}
spacing: Units.smallSpacing
width: plantingsView.implicitWidth
......@@ -375,19 +469,65 @@ Page {
Pane {
id: plantingsPane
visible: unassignedPlantingsCheckbox.checked & !editMode
// visible: unassignedPlantingsCheckbox.checked & !editMode
visible: !editMode
padding: 0
Layout.fillWidth: true
// Layout.fillHeight: true
Layout.minimumHeight: page.height / 4
Layout.minimumHeight: showPlantingsPane ? page.height / 4 : 0
// Layout.minimumHeight: unassignedPlantingsCheckbox.checked ? page.height / 4 : 10
Material.elevation: 2
Material.background: "white"
Behavior on Layout.minimumHeight {
NumberAnimation { duration: Units.shortDuration }
}
MouseArea {
id: plantingPaneMouseArea
anchors.fill: parent
hoverEnabled: true
RoundButton {
id: showPlantingPaneButton
z: -1
Material.background: "white"
width: 60
height: width
anchors.top: parent.top
anchors.topMargin: visible ? -width/2 : 0
anchors.horizontalCenter: parent.horizontalCenter
onClicked: showPlantingsPane =!showPlantingsPane
contentItem: Text {
text: showPlantingsPane ? "\ue313" : "\ue316"
font.family: "Material Icons"
font.pixelSize: 24
// color: parent.down ? "#17a81a" : "#21be2b"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.Top
elide: Text.ElideRight
}
ToolTip.visible: hovered
ToolTip.text: showPlantingsPane ? qsTr("Hide the plantings pane") : qsTr("Show the planting pane")
ToolTip.delay: Units.shortDuration
Behavior on anchors.topMargin {
NumberAnimation { duration: Units.shortDuration }
}
}
Rectangle {
color: "white"
anchors.fill: parent
}
Column {
id: emptyPlantingStateColumn
z: 1
spacing: Units.smallSpacing
visible: !plantingsView.rowsNumber
visible: !plantingsView.rowsNumber && showPlantingsPane
z:2
anchors {
centerIn: parent
}
......@@ -484,3 +624,4 @@ Page {
}
}
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment