Add collapsible properties drawer

- PropertiesRole returns QVariantMap of key->value
- loadProperties() parses KEY=value lines from /properties file
- QML drawer shows ':PROPERTIES:' header with ▶/▼ toggle
- Properties shown as monospace :KEY: value pairs when expanded
- Drawer starts collapsed by default
This commit is contained in:
Levi Neely 2026-10-01 10:00:20 +02:00
parent eb3b174b12
commit 429c896f5a
3 changed files with 95 additions and 0 deletions

View File

@ -51,6 +51,8 @@ ListView {
required property int index
required property var model
property bool drawerOpen: false
readonly property string sectionBody: (model.body ?? "").trim()
readonly property int sectionLevel: model.level ?? 1
readonly property int indent: (sectionLevel - 1) * outline.indentWidth
@ -167,6 +169,67 @@ ListView {
}
}
// Properties drawer (collapsible)
RowLayout {
visible: Object.keys(del.model.properties ?? {}).length > 0
Layout.fillWidth: true
spacing: 4
Label {
id: drawerToggle
text: del.drawerOpen ? "▼" : "▶"
color: theme.placeholderTextColor
font.pointSize: outline.baseFontSize - 2
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: del.drawerOpen = !del.drawerOpen
}
}
Label {
text: ":PROPERTIES:"
color: theme.placeholderTextColor
font.pointSize: outline.baseFontSize - 1
font.family: "monospace"
MouseArea {
anchors.fill: parent
cursorShape: Qt.PointingHandCursor
onClicked: del.drawerOpen = !del.drawerOpen
}
}
}
// Properties content (when expanded)
ColumnLayout {
visible: del.drawerOpen && Object.keys(del.model.properties ?? {}).length > 0
Layout.fillWidth: true
Layout.leftMargin: 16
spacing: 2
Repeater {
model: Object.keys(del.model.properties ?? {})
delegate: RowLayout {
required property string modelData
spacing: 8
Label {
text: ":" + modelData + ":"
color: theme.linkColor
font.pointSize: outline.baseFontSize - 1
font.family: "monospace"
}
Label {
text: del.model.properties[modelData] ?? ""
color: theme.textColor
font.pointSize: outline.baseFontSize - 1
font.family: "monospace"
}
}
}
}
// Body text with left rule
RowLayout {
visible: del.sectionBody !== ""

View File

@ -74,6 +74,10 @@ QVariant DocumentModel::data(const QModelIndex &index, int role) const
if (!sec.bodyLoaded)
loadBody(sec);
return sec.body;
case PropertiesRole:
if (!sec.propertiesLoaded)
loadProperties(sec);
return sec.properties;
case HasChildrenRole:
return !sec.childIds.isEmpty();
case ExpandedRole:
@ -98,6 +102,7 @@ QHash<int, QByteArray> DocumentModel::roleNames() const
{IsTodoRole, "isTodo"},
{IsDoneRole, "isDone"},
{BodyRole, "body"},
{PropertiesRole, "properties"},
{HasChildrenRole, "hasChildren"},
{ExpandedRole, "expanded"},
};
@ -224,6 +229,25 @@ void DocumentModel::loadBody(Section &sec) const
sec.bodyLoaded = true;
}
void DocumentModel::loadProperties(Section &sec) const
{
if (!m_client || sec.propertiesLoaded)
return;
QString propsStr = m_client->read(sec.path + "/properties").trimmed();
if (!propsStr.isEmpty()) {
for (const QString &line : propsStr.split('\n')) {
int eq = line.indexOf('=');
if (eq > 0) {
QString key = line.left(eq).trimmed();
QString value = line.mid(eq + 1).trimmed();
sec.properties[key] = value;
}
}
}
sec.propertiesLoaded = true;
}
void DocumentModel::rebuildVisibleRows()
{
QStringList oldRows = m_visibleRows;

View File

@ -35,6 +35,7 @@ public:
IsTodoRole, // keyword is non-empty
IsDoneRole, // keyword is a "done" state (DONE/CANCELLED)
BodyRole, // section content beneath the headline (lazy)
PropertiesRole, // QVariantMap of property key -> value
HasChildrenRole, // true if section has children
ExpandedRole, // true if section is expanded (children visible)
};
@ -81,6 +82,10 @@ private:
// Section body (lazy)
QString body;
bool bodyLoaded = false;
// Properties drawer (lazy)
QVariantMap properties;
bool propertiesLoaded = false;
};
// Load all sections for the current document
@ -95,6 +100,9 @@ private:
// Load body for a section
void loadBody(Section &sec) const;
// Load properties for a section
void loadProperties(Section &sec) const;
// Rebuild the visible row list based on expansion state
void rebuildVisibleRows();