1 #include "widget/wlibrarysidebar.h"
2
3 #include <QFileInfo>
4 #include <QHeaderView>
5 #include <QMimeData>
6 #include <QUrl>
7 #include <QtDebug>
8
9 #include "library/sidebarmodel.h"
10 #include "moc_wlibrarysidebar.cpp"
11 #include "util/dnd.h"
12
13 const int expand_time = 250;
14
WLibrarySidebar(QWidget * parent)15 WLibrarySidebar::WLibrarySidebar(QWidget* parent)
16 : QTreeView(parent),
17 WBaseWidget(this) {
18 //Set some properties
19 setHeaderHidden(true);
20 setSelectionMode(QAbstractItemView::SingleSelection);
21 //Drag and drop setup
22 setDragEnabled(false);
23 setDragDropMode(QAbstractItemView::DragDrop);
24 setDropIndicatorShown(true);
25 setAcceptDrops(true);
26 setAutoScroll(true);
27 setAttribute(Qt::WA_MacShowFocusRect, false);
28 header()->setStretchLastSection(false);
29 header()->setSectionResizeMode(QHeaderView::ResizeToContents);
30 header()->setHorizontalScrollMode(QAbstractItemView::ScrollPerPixel);
31 }
32
contextMenuEvent(QContextMenuEvent * event)33 void WLibrarySidebar::contextMenuEvent(QContextMenuEvent *event) {
34 //if (event->state() & Qt::RightButton) { //Dis shiz don werk on windowze
35 QModelIndex clickedItem = indexAt(event->pos());
36 emit rightClicked(event->globalPos(), clickedItem);
37 //}
38 }
39
40 // Drag enter event, happens when a dragged item enters the track sources view
dragEnterEvent(QDragEnterEvent * event)41 void WLibrarySidebar::dragEnterEvent(QDragEnterEvent * event) {
42 qDebug() << "WLibrarySidebar::dragEnterEvent" << event->mimeData()->formats();
43 if (event->mimeData()->hasUrls()) {
44 // We don't have a way to ask the LibraryFeatures whether to accept a
45 // drag so for now we accept all drags. Since almost every
46 // LibraryFeature accepts all files in the drop and accepts playlist
47 // drops we default to those flags to DragAndDropHelper.
48 QList<TrackFile> files = DragAndDropHelper::supportedTracksFromUrls(
49 event->mimeData()->urls(), false, true);
50 if (!files.isEmpty()) {
51 event->acceptProposedAction();
52 return;
53 }
54 }
55 event->ignore();
56 //QTreeView::dragEnterEvent(event);
57 }
58
59 // Drag move event, happens when a dragged item hovers over the track sources view...
dragMoveEvent(QDragMoveEvent * event)60 void WLibrarySidebar::dragMoveEvent(QDragMoveEvent * event) {
61 //qDebug() << "dragMoveEvent" << event->mimeData()->formats();
62 // Start a timer to auto-expand sections the user hovers on.
63 QPoint pos = event->pos();
64 QModelIndex index = indexAt(pos);
65 if (m_hoverIndex != index) {
66 m_expandTimer.stop();
67 m_hoverIndex = index;
68 m_expandTimer.start(expand_time, this);
69 }
70 // This has to be here instead of after, otherwise all drags will be
71 // rejected -- rryan 3/2011
72 QTreeView::dragMoveEvent(event);
73 if (event->mimeData()->hasUrls()) {
74 const QList<QUrl> urls = event->mimeData()->urls();
75 // Drag and drop within this widget
76 if ((event->source() == this)
77 && (event->possibleActions() & Qt::MoveAction)) {
78 // Do nothing.
79 event->ignore();
80 } else {
81 SidebarModel* sidebarModel = qobject_cast<SidebarModel*>(model());
82 bool accepted = true;
83 if (sidebarModel) {
84 accepted = false;
85 for (const QUrl& url : urls) {
86 QModelIndex destIndex = indexAt(event->pos());
87 if (sidebarModel->dragMoveAccept(destIndex, url)) {
88 // We only need one URL to be valid for us
89 // to accept the whole drag...
90 // consider we have a long list of valid files, checking all will
91 // take a lot of time that stales Mixxx and this makes the drop feature useless
92 // Eg. you may have tried to drag two MP3's and an EXE, the drop is accepted here,
93 // but the EXE is sorted out later after dropping
94 accepted = true;
95 break;
96 }
97 }
98 }
99 if (accepted) {
100 event->acceptProposedAction();
101 } else {
102 event->ignore();
103 }
104 }
105 } else {
106 event->ignore();
107 }
108 }
109
timerEvent(QTimerEvent * event)110 void WLibrarySidebar::timerEvent(QTimerEvent *event) {
111 if (event->timerId() == m_expandTimer.timerId()) {
112 QPoint pos = viewport()->mapFromGlobal(QCursor::pos());
113 if (viewport()->rect().contains(pos)) {
114 QModelIndex index = indexAt(pos);
115 if (m_hoverIndex == index) {
116 setExpanded(index, !isExpanded(index));
117 }
118 }
119 m_expandTimer.stop();
120 return;
121 }
122 QTreeView::timerEvent(event);
123 }
124
125 // Drag-and-drop "drop" event. Occurs when something is dropped onto the track sources view
dropEvent(QDropEvent * event)126 void WLibrarySidebar::dropEvent(QDropEvent * event) {
127 if (event->mimeData()->hasUrls()) {
128 // Drag and drop within this widget
129 if ((event->source() == this)
130 && (event->possibleActions() & Qt::MoveAction)) {
131 // Do nothing.
132 event->ignore();
133 } else {
134 //Reset the selected items (if you had anything highlighted, it clears it)
135 //this->selectionModel()->clear();
136 //Drag-and-drop from an external application or the track table widget
137 //eg. dragging a track from Windows Explorer onto the sidebar
138 SidebarModel* sidebarModel = qobject_cast<SidebarModel*>(model());
139 if (sidebarModel) {
140 QModelIndex destIndex = indexAt(event->pos());
141 // event->source() will return NULL if something is dropped from
142 // a different application
143 const QList<QUrl> urls = event->mimeData()->urls();
144 if (sidebarModel->dropAccept(destIndex, urls, event->source())) {
145 event->acceptProposedAction();
146 } else {
147 event->ignore();
148 }
149 }
150 }
151 //emit trackDropped(name);
152 //repaintEverything();
153 } else {
154 event->ignore();
155 }
156 }
157
158
toggleSelectedItem()159 void WLibrarySidebar::toggleSelectedItem() {
160 QModelIndexList selectedIndices = this->selectionModel()->selectedRows();
161 if (selectedIndices.size() > 0) {
162 QModelIndex index = selectedIndices.at(0);
163 // Activate the item so its content shows in the main library.
164 emit pressed(index);
165 // Expand or collapse the item as necessary.
166 setExpanded(index, !isExpanded(index));
167 }
168 }
169
isLeafNodeSelected()170 bool WLibrarySidebar::isLeafNodeSelected() {
171 QModelIndexList selectedIndices = this->selectionModel()->selectedRows();
172 if (selectedIndices.size() > 0) {
173 QModelIndex index = selectedIndices.at(0);
174 if(!index.model()->hasChildren(index)) {
175 return true;
176 }
177 const SidebarModel* sidebarModel = qobject_cast<const SidebarModel*>(index.model());
178 if (sidebarModel) {
179 return sidebarModel->hasTrackTable(index);
180 }
181 }
182 return false;
183 }
184
keyPressEvent(QKeyEvent * event)185 void WLibrarySidebar::keyPressEvent(QKeyEvent* event) {
186 if (event->key() == Qt::Key_Return) {
187 toggleSelectedItem();
188 return;
189 } else if (event->key() == Qt::Key_Down || event->key() == Qt::Key_Up) {
190 // Let the tree view move up and down for us.
191 QTreeView::keyPressEvent(event);
192
193 // But force the index to be activated/clicked after the selection
194 // changes. (Saves you from having to push "enter" after changing the
195 // selection.)
196 QModelIndexList selectedIndices = this->selectionModel()->selectedRows();
197
198 //Note: have to get the selected indices _after_ QTreeView::keyPressEvent()
199 if (selectedIndices.size() > 0) {
200 QModelIndex index = selectedIndices.at(0);
201 emit pressed(index);
202 }
203 return;
204 //} else if (event->key() == Qt::Key_Enter && (event->modifiers() & Qt::AltModifier)) {
205 // // encoder click via "GoToItem"
206 // qDebug() << "GoToItem";
207 // TODO(xxx) decide what todo here instead of in librarycontrol
208 }
209
210 // Fall through to default handler.
211 QTreeView::keyPressEvent(event);
212 }
213
selectIndex(const QModelIndex & index)214 void WLibrarySidebar::selectIndex(const QModelIndex& index) {
215 auto* pModel = new QItemSelectionModel(model());
216 pModel->select(index, QItemSelectionModel::Select);
217 setSelectionModel(pModel);
218
219 if (index.parent().isValid()) {
220 expand(index.parent());
221 }
222 scrollTo(index);
223 }
224
event(QEvent * pEvent)225 bool WLibrarySidebar::event(QEvent* pEvent) {
226 if (pEvent->type() == QEvent::ToolTip) {
227 updateTooltip();
228 }
229 return QTreeView::event(pEvent);
230 }
231
slotSetFont(const QFont & font)232 void WLibrarySidebar::slotSetFont(const QFont& font) {
233 setFont(font);
234 // Resize the feature icons to be a bit taller than the label's capital
235 int iconSize = static_cast<int>(QFontMetrics(font).height() * 0.8);
236 setIconSize(QSize(iconSize, iconSize));
237 }
238