Line data Source code
1 : #pragma once
2 :
3 : #include <QAbstractItemModel>
4 : #include <functional>
5 : #include <QListWidget>
6 : #include <QTextEdit>
7 : #include <QSet>
8 : #include <QSplitter>
9 : #include <QStackedWidget>
10 : #include <QStyledItemDelegate>
11 : #include <QTextBrowser>
12 : #include <QTreeView>
13 :
14 : #include "data/CalendarModels.h"
15 :
16 : class MarkdownHighlighter;
17 :
18 : class CalendarStore;
19 : class QToolButton;
20 :
21 : // ═══════════════════════════════════════════════════════
22 : // TaskListWidget — 3-Pane task view (Sprint 37 – T-453)
23 : // Layout: Sidebar (Calendars) | Task List | Task Detail
24 : // Vim-style keyboard: j/k/x/Space/F/Enter/Esc/f///
25 : // ═══════════════════════════════════════════════════════
26 :
27 : // --- Model ---
28 :
29 : class TaskListModel : public QAbstractItemModel {
30 : Q_OBJECT
31 : public:
32 : explicit TaskListModel(QObject *parent = nullptr);
33 :
34 : void setTasks(const QList<CalendarTask> &tasks);
35 562 : const CalendarTask &taskAt(int row) const { return m_tasks[row]; }
36 :
37 : enum Columns {
38 : ColStatus = 0, ///< ○/✓/▶/✗ + ★ starred
39 : ColSummary, ///< Task title
40 : ColProgress, ///< Progress circle (custom delegate)
41 : ColDue, ///< Due date
42 : ColPriority, ///< !/!!/!!!
43 : ColCalendar, ///< Color dot + calendar name
44 : ColCount
45 : };
46 :
47 : QModelIndex index(int row, int col,
48 : const QModelIndex &parent = {}) const override;
49 : QModelIndex parent(const QModelIndex &index) const override;
50 : int rowCount(const QModelIndex &parent = {}) const override;
51 : int columnCount(const QModelIndex &parent = {}) const override;
52 : QVariant data(const QModelIndex &index,
53 : int role = Qt::DisplayRole) const override;
54 : QVariant headerData(int section, Qt::Orientation orientation,
55 : int role = Qt::DisplayRole) const override;
56 :
57 : private:
58 : QList<CalendarTask> m_tasks;
59 : };
60 :
61 : // --- Progress Circle Delegate (T-455) ---
62 :
63 : class TaskProgressDelegate : public QStyledItemDelegate {
64 : Q_OBJECT
65 : public:
66 : using QStyledItemDelegate::QStyledItemDelegate;
67 : void paint(QPainter *painter, const QStyleOptionViewItem &option,
68 : const QModelIndex &index) const override;
69 : QSize sizeHint(const QStyleOptionViewItem &option,
70 : const QModelIndex &index) const override;
71 : };
72 :
73 : // --- Widget ---
74 :
75 : class TaskListWidget : public QWidget {
76 302 : Q_OBJECT
77 : #ifdef MAILJD_UNIT_TEST
78 : friend class TestSprint62Coverage;
79 : #endif
80 : public:
81 : explicit TaskListWidget(QWidget *parent = nullptr);
82 :
83 : void setCalendarStore(CalendarStore *store);
84 : void reload();
85 : void setShowCompleted(bool show);
86 4 : bool showCompleted() const { return m_showCompleted; }
87 :
88 : void setFilterText(const QString &text);
89 : void setSearchResults(const QList<CalendarTask> &results);
90 :
91 : /// Sprint 56: Public API for MainWindow Esc guard
92 11 : bool isEditing() const { return m_editing; }
93 : void finishDescriptionEdit(bool save = true);
94 :
95 : signals:
96 : void taskToggled(const CalendarTask &task);
97 : void taskSelected(const CalendarTask &task);
98 : // T-535: Inline editing signals
99 : void taskUpdated(const CalendarTask &task); // → opens edit dialog
100 : void taskSaveRequested(const CalendarTask &task); // → saves inline changes
101 : void taskCreateRequested();
102 : void taskDeleteRequested(const CalendarTask &task);
103 : void closeRequested();
104 :
105 : protected:
106 : void keyPressEvent(QKeyEvent *event) override;
107 : bool eventFilter(QObject *obj, QEvent *event) override;
108 : void changeEvent(QEvent *event) override;
109 : void retranslateUi();
110 :
111 : private:
112 : void setupSidebar();
113 : void setupTaskList();
114 : void setupDetailPanel();
115 : void toggleCurrentTask();
116 : void deleteCurrentTask();
117 : void startDescriptionEdit();
118 : void setupEditorToolbar();
119 : void insertMarkdownWrap(const QString &before, const QString &after);
120 : void insertMarkdownPrefix(const QString &prefix);
121 : void modifyCurrentTask(const std::function<void(CalendarTask&)> &mutator);
122 : bool matchesEditingTask(const CalendarTask &task) const;
123 : void moveSelectionBy(int delta);
124 : void showDetail(int row);
125 : void updateSidebar();
126 : void onSidebarClicked(int row);
127 : void applyFilter();
128 : void saveSettings();
129 : void restoreSettings();
130 :
131 : CalendarStore *m_store = nullptr;
132 : TaskListModel *m_model = nullptr;
133 :
134 : // 3-Pane layout
135 : QSplitter *m_mainSplitter = nullptr;
136 : QSplitter *m_rightSplitter = nullptr;
137 :
138 : // Sidebar (left)
139 : QListWidget *m_sidebarList = nullptr;
140 : QWidget *m_sidebarContainer = nullptr;
141 : // Task list (right upper)
142 : QTreeView *m_treeView = nullptr;
143 :
144 : // Detail panel (right lower)
145 : QTextBrowser *m_headerBrowser = nullptr; // persistent header (above editor)
146 : QTextBrowser *m_detailBrowser = nullptr;
147 : // T-535: Inline editing
148 : QWidget *m_detailContainer = nullptr; // header + stack container
149 : QStackedWidget *m_detailStack = nullptr;
150 : QTextEdit *m_descriptionEditor = nullptr;
151 : MarkdownHighlighter *m_highlighter = nullptr;
152 : QWidget *m_editorToolbar = nullptr;
153 : QToolButton *m_boldBtn = nullptr;
154 : QToolButton *m_italicBtn = nullptr;
155 : QToolButton *m_codeBtn = nullptr;
156 : QToolButton *m_headingBtn = nullptr;
157 : QToolButton *m_checkboxBtn = nullptr;
158 : QToolButton *m_dividerBtn = nullptr;
159 : QToolButton *m_linkBtn = nullptr;
160 : bool m_editing = false;
161 : qint64 m_editingTaskId = 0;
162 : QString m_editingUid;
163 : QString m_editingAccountId;
164 : QString m_editingCalendarPath;
165 :
166 : // State
167 : bool m_showCompleted = false;
168 : QString m_currentFilter; ///< "all", "current", "urgent", "completed", or calendar path
169 : QSet<QString> m_hiddenCalendars;
170 : QString m_filterText; ///< text filter from CommandBar
171 :
172 : // All loaded tasks (pre-filter)
173 : QList<CalendarTask> m_allTasks;
174 : };
|