Changeset View
Changeset View
Standalone View
Standalone View
plugins/projectmanagerview/projecttreeview.cpp
Show All 23 Lines | |||||
24 | 24 | | |||
25 | #include <QAction> | 25 | #include <QAction> | ||
26 | #include <QAbstractProxyModel> | 26 | #include <QAbstractProxyModel> | ||
27 | #include <QKeyEvent> | 27 | #include <QKeyEvent> | ||
28 | #include <QApplication> | 28 | #include <QApplication> | ||
29 | #include <QHeaderView> | 29 | #include <QHeaderView> | ||
30 | #include <QMenu> | 30 | #include <QMenu> | ||
31 | #include <QPainter> | 31 | #include <QPainter> | ||
32 | #include <QScrollBar> | ||||
33 | #include <QAbstractItemView> | ||||
32 | 34 | | |||
33 | #include <KConfigGroup> | 35 | #include <KConfigGroup> | ||
34 | #include <KLocalizedString> | 36 | #include <KLocalizedString> | ||
35 | 37 | | |||
36 | #include <project/projectmodel.h> | 38 | #include <project/projectmodel.h> | ||
37 | #include <interfaces/contextmenuextension.h> | 39 | #include <interfaces/contextmenuextension.h> | ||
38 | #include <interfaces/iprojectcontroller.h> | 40 | #include <interfaces/iprojectcontroller.h> | ||
39 | #include <interfaces/iproject.h> | 41 | #include <interfaces/iproject.h> | ||
40 | #include <interfaces/context.h> | 42 | #include <interfaces/context.h> | ||
41 | #include <interfaces/iplugincontroller.h> | 43 | #include <interfaces/iplugincontroller.h> | ||
42 | #include <interfaces/icore.h> | 44 | #include <interfaces/icore.h> | ||
43 | #include <interfaces/iselectioncontroller.h> | 45 | #include <interfaces/iselectioncontroller.h> | ||
44 | #include <interfaces/isession.h> | 46 | #include <interfaces/isession.h> | ||
45 | #include <project/interfaces/iprojectfilemanager.h> | 47 | #include <project/interfaces/iprojectfilemanager.h> | ||
46 | #include <project/interfaces/ibuildsystemmanager.h> | 48 | #include <project/interfaces/ibuildsystemmanager.h> | ||
47 | 49 | | |||
48 | #include "projectmanagerviewplugin.h" | 50 | #include "projectmanagerviewplugin.h" | ||
49 | #include "projectmodelsaver.h" | 51 | #include "projectmodelsaver.h" | ||
50 | #include "projectmodelitemdelegate.h" | 52 | #include "projectmodelitemdelegate.h" | ||
51 | #include "debug.h" | 53 | #include "debug.h" | ||
52 | #include <project/projectutils.h> | 54 | #include <project/projectutils.h> | ||
53 | #include <widgetcolorizer.h> | 55 | #include <widgetcolorizer.h> | ||
54 | 56 | | |||
57 | | ||||
mwolff: undo this hunk | |||||
55 | using namespace KDevelop; | 58 | using namespace KDevelop; | ||
56 | 59 | | |||
57 | namespace { | 60 | namespace { | ||
58 | const char settingsConfigGroup[] = "ProjectTreeView"; | 61 | const char settingsConfigGroup[] = "ProjectTreeView"; | ||
59 | 62 | | |||
60 | QList<ProjectFileItem*> fileItemsWithin(const QList<ProjectBaseItem*>& items) | 63 | QList<ProjectFileItem*> fileItemsWithin(const QList<ProjectBaseItem*>& items) | ||
61 | { | 64 | { | ||
62 | QList<ProjectFileItem*> fileItems; | 65 | QList<ProjectFileItem*> fileItems; | ||
▲ Show 20 Lines • Show All 55 Lines • ▼ Show 20 Line(s) | 116 | { | |||
118 | setContextMenuPolicy( Qt::CustomContextMenu ); | 121 | setContextMenuPolicy( Qt::CustomContextMenu ); | ||
119 | setSelectionMode( QAbstractItemView::ExtendedSelection ); | 122 | setSelectionMode( QAbstractItemView::ExtendedSelection ); | ||
120 | 123 | | |||
121 | setIndentation(10); | 124 | setIndentation(10); | ||
122 | 125 | | |||
123 | setDragEnabled(true); | 126 | setDragEnabled(true); | ||
124 | setDragDropMode(QAbstractItemView::InternalMove); | 127 | setDragDropMode(QAbstractItemView::InternalMove); | ||
125 | setAutoScroll(true); | 128 | setAutoScroll(true); | ||
126 | setAutoExpandDelay(300); | 129 | setAutoScrollMargin(32); | ||
130 | setAutoExpandDelay(400); | ||||
127 | setItemDelegate(new ProjectModelItemDelegate(this)); | 131 | setItemDelegate(new ProjectModelItemDelegate(this)); | ||
128 | 132 | | |||
129 | connect( this, &ProjectTreeView::customContextMenuRequested, this, &ProjectTreeView::popupContextMenu ); | 133 | connect( this, &ProjectTreeView::customContextMenuRequested, this, &ProjectTreeView::popupContextMenu ); | ||
130 | connect( this, &ProjectTreeView::activated, this, &ProjectTreeView::slotActivated ); | 134 | connect( this, &ProjectTreeView::activated, this, &ProjectTreeView::slotActivated ); | ||
131 | 135 | | |||
132 | connect( ICore::self(), &ICore::aboutToShutdown, | 136 | connect( ICore::self(), &ICore::aboutToShutdown, | ||
133 | this, &ProjectTreeView::aboutToShutdown); | 137 | this, &ProjectTreeView::aboutToShutdown); | ||
134 | connect( ICore::self()->projectController(), &IProjectController::projectOpened, | 138 | connect( ICore::self()->projectController(), &IProjectController::projectOpened, | ||
135 | this, &ProjectTreeView::restoreState ); | 139 | this, &ProjectTreeView::restoreState ); | ||
136 | connect( ICore::self()->projectController(), &IProjectController::projectClosed, | 140 | connect( ICore::self()->projectController(), &IProjectController::projectClosed, | ||
137 | this, &ProjectTreeView::projectClosed ); | 141 | this, &ProjectTreeView::projectClosed ); | ||
138 | } | 142 | } | ||
139 | 143 | | |||
140 | ProjectTreeView::~ProjectTreeView() | 144 | ProjectTreeView::~ProjectTreeView() | ||
141 | { | 145 | { | ||
142 | } | 146 | } | ||
143 | 147 | | |||
144 | ProjectBaseItem* ProjectTreeView::itemAtPos(const QPoint& pos) const | 148 | ProjectBaseItem* ProjectTreeView::itemAtPos(const QPoint& pos) const | ||
145 | { | 149 | { | ||
146 | return indexAt(pos).data(ProjectModel::ProjectItemRole).value<ProjectBaseItem*>(); | 150 | return indexAt(pos).data(ProjectModel::ProjectItemRole).value<ProjectBaseItem*>(); | ||
147 | } | 151 | } | ||
148 | 152 | | |||
153 | void ProjectTreeView::timerEvent(QTimerEvent *event) { | ||||
154 | if (event->timerId() == expandTimer.timerId()) { | ||||
155 | expandTimer.stop(); | ||||
156 | auto expandTargetItem = mapFromItem(curExpandTarget); | ||||
157 | expand(expandTargetItem); | ||||
158 | | ||||
159 | auto isDescendant = [](ProjectBaseItem *needle, ProjectBaseItem *haystack) { | ||||
160 | while (needle) { | ||||
161 | if (needle->parent() == haystack) { | ||||
162 | return true; | ||||
163 | } | ||||
164 | needle = needle->parent(); | ||||
165 | } | ||||
166 | return false; | ||||
167 | }; | ||||
168 | | ||||
169 | // collapse unneeded previously opened folders | ||||
170 | int prevTargetPos = visualRect(expandTargetItem).top(); | ||||
171 | while (!expandStack.empty() && !isDescendant(curExpandTarget, expandStack.top())) { | ||||
172 | collapse(mapFromItem(expandStack.top())); | ||||
173 | expandStack.pop(); | ||||
174 | } | ||||
175 | | ||||
176 | // try to return the expanded folder back to the mouse cursor if the folder has shifted | ||||
177 | int curTargetPos = visualRect(expandTargetItem).top(); | ||||
could you maybe instead just call ensureVisible on the index below the cursor before you collapse the previously opened folders? mwolff: could you maybe instead just call `ensureVisible` on the index below the cursor before you… | |||||
178 | int targtPosChange = curTargetPos - prevTargetPos; | ||||
179 | ScrollMode prevMode = verticalScrollMode(); | ||||
180 | setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); | ||||
181 | verticalScrollBar()->setValue(verticalScrollBar()->value() + targtPosChange); | ||||
182 | setVerticalScrollMode(prevMode); | ||||
183 | | ||||
184 | expandStack.push(curExpandTarget); | ||||
185 | curExpandTarget = nullptr; | ||||
186 | } else { | ||||
187 | QTreeView::timerEvent(event); | ||||
188 | } | ||||
189 | } | ||||
190 | | ||||
191 | void ProjectTreeView::dragMoveEvent(QDragMoveEvent *event) | ||||
192 | { | ||||
193 | ProjectBaseItem *destItem = itemAtPos(event->pos()); | ||||
194 | if (destItem && dropIndicatorPosition() == OnItem) { | ||||
195 | ProjectFolderItem *folder = destItem->folder(); | ||||
196 | bool canExpand = folder && !isExpanded(mapFromItem(folder)) && autoExpandDelay() >= 0; | ||||
197 | bool expandTargetNotChanged = folder && folder == curExpandTarget; | ||||
198 | if (folder != curExpandTarget && canExpand) { | ||||
199 | curExpandTarget = folder; | ||||
200 | expandTimer.start(autoExpandDelay(), this); | ||||
201 | } else if (!expandTargetNotChanged) { | ||||
202 | expandTimer.stop(); | ||||
203 | curExpandTarget = nullptr; | ||||
204 | } | ||||
205 | } else { | ||||
206 | expandTimer.stop(); | ||||
207 | curExpandTarget = nullptr; | ||||
208 | } | ||||
209 | QAbstractItemView::dragMoveEvent(event); | ||||
210 | } | ||||
211 | | ||||
212 | void ProjectTreeView::dragLeaveEvent(QDragLeaveEvent *event) | ||||
213 | { | ||||
214 | while (!expandStack.empty()) { | ||||
215 | collapse(mapFromItem(expandStack.top())); | ||||
216 | expandStack.pop(); | ||||
217 | } | ||||
218 | QTreeView::dragLeaveEvent(event); | ||||
219 | } | ||||
220 | | ||||
149 | void ProjectTreeView::dropEvent(QDropEvent* event) | 221 | void ProjectTreeView::dropEvent(QDropEvent* event) | ||
150 | { | 222 | { | ||
151 | ProjectItemContext* selectionCtxt = | 223 | ProjectItemContext* selectionCtxt = | ||
152 | static_cast<ProjectItemContext*>(KDevelop::ICore::self()->selectionController()->currentSelection()); | 224 | static_cast<ProjectItemContext*>(KDevelop::ICore::self()->selectionController()->currentSelection()); | ||
153 | ProjectBaseItem* destItem = itemAtPos(event->pos()); | 225 | ProjectBaseItem* destItem = itemAtPos(event->pos()); | ||
154 | if (destItem && (dropIndicatorPosition() == AboveItem || dropIndicatorPosition() == BelowItem)) | 226 | if (destItem && (dropIndicatorPosition() == AboveItem || dropIndicatorPosition() == BelowItem)) | ||
155 | destItem = destItem->parent(); | 227 | destItem = destItem->parent(); | ||
156 | if (selectionCtxt && destItem) | 228 | if (selectionCtxt && destItem) | ||
▲ Show 20 Lines • Show All 89 Lines • ▼ Show 20 Line(s) | 296 | { | |||
246 | } | 318 | } | ||
247 | if (executedAction == addToTarget) { | 319 | if (executedAction == addToTarget) { | ||
248 | QList<ProjectFileItem*> usefulItems = fileItemsWithin(selectionCtxt->items()); | 320 | QList<ProjectFileItem*> usefulItems = fileItemsWithin(selectionCtxt->items()); | ||
249 | filterDroppedItems(usefulItems, destItem); | 321 | filterDroppedItems(usefulItems, destItem); | ||
250 | destItem->project()->buildSystemManager()->addFilesToTarget(usefulItems, destItem->target()); | 322 | destItem->project()->buildSystemManager()->addFilesToTarget(usefulItems, destItem->target()); | ||
251 | } | 323 | } | ||
252 | } | 324 | } | ||
253 | } | 325 | } | ||
326 | | ||||
327 | if (!expandStack.empty()) { | ||||
328 | expandStack = std::stack<ProjectFolderItem*>(); | ||||
329 | } | ||||
330 | | ||||
254 | event->accept(); | 331 | event->accept(); | ||
255 | } | 332 | } | ||
256 | 333 | | |||
257 | QModelIndex ProjectTreeView::mapFromSource(const QAbstractProxyModel* proxy, const QModelIndex& sourceIdx) | 334 | QModelIndex ProjectTreeView::mapFromSource(const QAbstractProxyModel* proxy, const QModelIndex& sourceIdx) | ||
258 | { | 335 | { | ||
259 | const QAbstractItemModel* next = proxy->sourceModel(); | 336 | const QAbstractItemModel* next = proxy->sourceModel(); | ||
260 | Q_ASSERT(next == sourceIdx.model() || qobject_cast<const QAbstractProxyModel*>(next)); | 337 | Q_ASSERT(next == sourceIdx.model() || qobject_cast<const QAbstractProxyModel*>(next)); | ||
261 | if(next == sourceIdx.model()) | 338 | if(next == sourceIdx.model()) | ||
▲ Show 20 Lines • Show All 217 Lines • Show Last 20 Lines |
undo this hunk