diff --git a/build/depends.py b/build/depends.py
index 2a9015240f10..4c88c68b359f 100644
--- a/build/depends.py
+++ b/build/depends.py
@@ -826,6 +826,10 @@ def sources(self, build):
"widget/wcoverartmenu.cpp",
"widget/wsingletoncontainer.cpp",
"widget/wmainmenubar.cpp",
+ "widget/wbuttonbar.cpp",
+ "widget/wfeatureclickbutton.cpp",
+ "widget/wlibrarystack.cpp",
+ "widget/wlibrarybreadcrumb.cpp",
"musicbrainz/network.cpp",
"musicbrainz/tagfetcher.cpp",
@@ -839,6 +843,7 @@ def sources(self, build):
"widget/wtracktableviewheader.cpp",
"widget/wlibrarysidebar.cpp",
"widget/wlibrary.cpp",
+ "widget/wbaselibrary.cpp",
"widget/wlibrarytableview.cpp",
"widget/wanalysislibrarytableview.cpp",
"widget/wlibrarytextbrowser.cpp",
@@ -866,7 +871,7 @@ def sources(self, build):
"library/mixxxlibraryfeature.cpp",
"library/baseplaylistfeature.cpp",
"library/playlistfeature.cpp",
- "library/setlogfeature.cpp",
+ "library/historyfeature.cpp",
"library/autodj/dlgautodj.cpp",
"library/dlganalysis.cpp",
"library/dlgcoverartfullsize.cpp",
@@ -905,6 +910,8 @@ def sources(self, build):
"library/cratefeature.cpp",
"library/sidebarmodel.cpp",
"library/library.cpp",
+ "library/librarypanemanager.cpp",
+ "library/librarysidebarexpandedmanager.cpp",
"library/scanner/libraryscanner.cpp",
"library/scanner/libraryscannerdlg.cpp",
diff --git a/res/skins/Deere/library.xml b/res/skins/Deere/library.xml
index 0745dd779beb..e572a467fd6a 100644
--- a/res/skins/Deere/library.xml
+++ b/res/skins/Deere/library.xml
@@ -14,35 +14,34 @@
LibraryExpanded
- vertical
-
- me,f
- 0,0
+ horizontal
+
+ vertical
+ min,me
+
+
+ show_library
+ LibraryToggle
+ [Library],show_library
+
+
+ min,me
+ LibrarySidebarButtons
+
+
+
LibrarySplitter
horizontal
me,me
[Deere],LibrarySidebarSplitSize
- 2,8
+ 2,4,4
vertical
-
- horizontal
-
-
- show_library
- LibraryToggle
- [Library],show_library
-
-
-
-
-
PreviewDeckContainer
vertical
@@ -153,8 +152,9 @@
2,8
0,0
-
-
+
+ LibrarySidebarExpanded
+
LibraryCoverArt
@@ -170,8 +170,40 @@
-
-
+
+
+
+ vertical
+
+
+ 1
+
+
+ LibraryBreadCrumb
+ 1
+
+
+ 1
+
+
+
+
+
+
+ vertical
+
+
+ 2
+
+
+ LibraryBreadCrumb
+ 2
+
+
+ 2
+
+
+
diff --git a/res/skins/Deere/style.qss b/res/skins/Deere/style.qss
index cd82be4f4009..665abc0739de 100644
--- a/res/skins/Deere/style.qss
+++ b/res/skins/Deere/style.qss
@@ -143,6 +143,16 @@ QTableView::indicator:unchecked {
background: url(skin:/image/style_checkbox_unchecked.png);
}
+WBaseLibrary[showFocus="0"] {
+ padding: 1px 0 0 0;
+ border: none;
+}
+
+WBaseLibrary[showFocus="1"] {
+ padding: 1px 1px 1px 1px;
+ border-top: 1px solid #DE6B0F;
+}
+
/* BPM lock icon in the library "BPM" column. */
#LibraryBPMButton::indicator:checked {
image: url(:/images/library/ic_library_checked.png);
@@ -152,6 +162,94 @@ QTableView::indicator:unchecked {
image: url(:/images/library/ic_library_unchecked.png);
}
+#LibrarySidebarButtons {
+ margin-top: 5px;
+}
+
+#LibrarySidebarButtons, #LibrarySidebarButtons WButtonBar {
+ background-color: #222222;
+ margin-right: 13px;
+}
+
+#LibraryBreadCrumb,
+WBaseLibrary QLabel {
+ margin: 4px 4px;
+ font-size: 12px;
+ font-weight: bold;
+ color: #B3B3B3;
+}
+
+#LibraryCoverArtSplitter QTabWidget {
+ border: none;
+}
+
+#LibraryCoverArtSplitter QTabWidget::pane {
+ border: 1px solid #1A1A1A;
+}
+
+#LibraryCoverArtSplitter QTabWidget QTreeView, #DlgAutoDJ {
+ margin: 0;
+ border: none;
+}
+
+#LibraryCoverArtSplitter::handle {
+ image: url(skin:/image/style_handle_vertical_unchecked.svg);
+ background: none;
+}
+
+#LibraryCoverArtSplitter::handle:pressed {
+ image: url(skin:/image/style_handle_vertical_checked.svg);
+ background: none;
+}
+
+#LibraryCoverArtSplitter::handle:horizontal {
+ width: 6px;
+}
+
+#LibraryCoverArtSplitter::handle:vertical {
+ height: 6px;
+}
+
+#DlgAutoDJ #scrollAreaWidgetContents {
+ background-color: #222222;
+ border: none;
+}
+
+#LibraryCoverArtSplitter QTabBar::tab {
+ padding: 4px;
+ border: none;
+ color: #cfb32c;
+ background-color: #191919;
+ border-top-left-radius: 2px;
+ border-top-right-radius: 2px;
+
+ color: #D2D2D2;
+ background-color: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0,
+ stop: 0 #4B4B4B,
+ stop: 1 #4B4B4B);
+ border: 0px solid #4B4B4B;
+ outline: none;
+}
+
+#LibraryCoverArtSplitter QTabBar::tab:hover {
+ border-top: 0px solid #5F5F5F;
+ border-right: 0px solid #5F5F5F;
+ border-left: 0px solid #5F5F5F;
+ color: #D2D2D2;
+ background-color: #5F5F5F;
+}
+
+#LibraryCoverArtSplitter QTabBar::tab:!enabled {
+ color: #969696;
+ background-color: #525252;
+}
+
+#LibraryCoverArtSplitter QTabBar::tab:selected {
+ color: #FDFDFD;
+ background-color: #006596;
+ border: 0px solid #006596;
+}
+
/* button in library "Preview" column */
QPushButton#LibraryPreviewButton {
width: 23px;
@@ -296,25 +394,6 @@ QTreeView::branch:open:has-children:has-siblings {
height: 6px;
}
-/* QSplitter between LibrarySidebar and CoverArt */
-#LibraryCoverArtSplitter::handle {
- image: url(skin:/image/style_handle_vertical_unchecked.svg);
- background: none;
-}
-
-#LibraryCoverArtSplitter::handle:pressed {
- image: url(skin:/image/style_handle_vertical_checked.svg);
- background: none;
-}
-
-#LibraryCoverArtSplitter::handle:horizontal {
- width: 6px;
-}
-
-#LibraryCoverArtSplitter::handle:vertical {
- height: 6px;
-}
-
/* library cover art widget */
#LibraryCoverArt {
padding: 8px 4px 4px 4px;
@@ -322,156 +401,94 @@ QTreeView::branch:open:has-children:has-siblings {
border: 1px solid #1A1A1A;
}
/* transition time in Auto DJ tab */
-WLibrary QSpinBox {
+WBaseLibrary QSpinBox {
min-height: 20px;
max-height: 20px;
min-width: 40px;
max-width: 40px;
}
-WLibrary QSpinBox:editable {
+WBaseLibrary QSpinBox:editable {
background: transparent;
color:#d2d2d2;
}
-/* Extra declaration for QRadionButton otherwise it shows up with wrong colors in Linux with Gnome */
-WLibrary QLabel, WLibrary QRadioButton {
- /* same as QTreeview */
+WBaseLibrary QLabel, WBaseLibrary QRadioButton {
color: #d2d2d2;
- margin: 9px 10px 6px 0px;
}
-WLibrary QRadioButton::indicator {
+WBaseLibrary QRadioButton::indicator {
margin: 0px 5px 0px 2px;
width: 18px;
height: 18px;
}
-/* Additional space for the first QRadionButton in the row */
-WLibrary QRadioButton#radioButtonRecentlyAdded {
- margin: 9px 10px 6px 14px;
-}
-
-WLibrary QRadioButton::indicator:checked {
+WBaseLibrary QRadioButton::indicator:checked {
background: url(skin:/icon/ic_radio_button_on_18px.svg);
}
-WLibrary QRadioButton::indicator:unchecked {
+WBaseLibrary QRadioButton::indicator:unchecked {
background: url(skin:/icon/ic_radio_button_off_18px.svg);
}
+
+WButtonBar QAbstractButton {
+ border-radius: 0px;
+}
+
/* buttons in library (in hierarchical order of appearance)
Style them just as the other regular buttons */
-#DlgMissing > QPushButton,
-#DlgHidden > QPushButton,
-#DlgAutoDJ > QPushButton,
-#DlgRecording > QPushButton,
-#DlgAnalysis > QPushButton {
- margin: 9px 3px 6px 3px;
- padding: 4px;
+WBaseLibrary QPushButton {
+ margin: 2px 3px 2px 3px;
+ padding: 2px;
color: #D2D2D2;
- background-color: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0,
- stop: 0 #4B4B4B,
- stop: 1 #4B4B4B);
+
+ background-color: #4B4B4B;
border: 1px solid #4B4B4B;
border-radius: 2px;
outline: none;
}
-#DlgMissing > QPushButton:!enabled,
-#DlgHidden > QPushButton:!enabled,
-#DlgAutoDJ > QPushButton:!enabled,
-#DlgAnalysis > QPushButton:!enabled {
+WBaseLibrary QPushButton:!enabled {
/* buttons in "disabled" (not click-able) state. They are nearly invisible
by default QT palette, so style accordingly */
- margin: 9px 3px 6px 3px;
- padding: 4px;
color: #808080; /* Default #A3A3A3 -90L HSL*/
- background-color: qlineargradient(spread:pad,
- x1:0, y1:0, x2:1, y2:0,
- stop:0 rgba(95, 95, 95, 127),
- stop:1 rgba(95, 95, 95, 127));
- /* 50% #5F5F5F = RGBA#5F5F5F7F */
+ background-color: rgba(95, 95, 95, 127);
border: 0px solid #5F5F5F;
- border-radius: 2px;
- outline: none;
}
-#DlgMissing > QPushButton:hover,
-#DlgHidden > QPushButton:hover,
-#DlgAutoDJ > QPushButton:hover,
-#DlgRecording > QPushButton:hover,
-#DlgAnalysis > QPushButton:hover {
- margin: 9px 3px 6px 3px;
- padding: 4px;
+WBaseLibrary QPushButton:hover {
color: #D2D2D2;
- background-color: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0,
- stop: 0 #5F5F5F,
- stop: 1 #5F5F5F);
+ background-color: #5F5F5F;
border: 0px solid #5F5F5F;
- border-radius: 2px;
- outline: none;
}
-#DlgAutoDJ > QPushButton:checked,
-#DlgRecording > QPushButton:checked,
-#DlgAnalysis > QPushButton:checked {
+WBaseLibrary QPushButton:checked {
/* checkbuttons in active state */
- margin: 9px 3px 6px 3px;
- padding: 4px;
color: #FDFDFD;
background-color: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0,
stop: 0 #006596,
stop: 1 #006596);
border: 0px solid #006596;
- border-radius: 2px;
- outline: none;
}
-#DlgAutoDJ > QPushButton:checked:hover,
-#DlgRecording > QPushButton:checked:hover,
-#DlgAnalysis > QPushButton:checked:hover {
+WBaseLibrary QPushButton:checked:hover {
/* checkbuttons hovered over in "active" state */
- margin: 9px 3px 6px 3px;
- padding: 4px;
color: #FDFDFD;
background-color: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0,
stop: 0 #0080BE,
stop: 1 #0080BE);
border: 0px solid #0080BE;
- border-radius: 2px;
- outline: none;
}
-#DlgMissing > QPushButton:pressed,
-#DlgHidden > QPushButton:pressed,
-#DlgAutoDJ > QPushButton:pressed,
-#DlgAnalysis > QPushButton:pressed {
+WBaseLibrary QPushButton:pressed {
/* pushbuttons in "down" state */
- margin: 9px 3px 6px 3px;
- padding: 4px;
color: #FDFDFD;
background-color: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0,
stop: 0 #006596,
stop: 1 #006596);
border: 0px solid #006596;
- border-radius: 2px;
- outline: none;
-}
-
-/* Additional space for the first and the last QPushButton in the row */
-#DlgMissing > QPushButton#btnPurge,
-#DlgHidden > QPushButton#btnUnhide,
-#DlgAutoDJ > QPushButton#pushButtonAutoDJ,
-#DlgRecording > QPushButton#pushButtonRecording,
-#DlgAnalysis > QPushButton#pushButtonAnalyze {
- margin: 9px 12px 6px 3px;
}
-#DlgAutoDJ > QPushButton#pushButtonShuffle {
- margin: 9px 3px 6px 12px;
-}
-
-
/* Scroll bars */
QScrollBar:horizontal {
border-top: 1px solid #141414;
@@ -519,6 +536,12 @@ QScrollBar::sub-line:horizontal, QScrollBar::sub-line:vertical {
border: none;
}
+QScrollArea {
+ border: 1px solid #1A1A1A;
+ background-color: #222222;
+}
+
+
/*******************************************************************************
** END LIBRARY *****************************************************************
*******************************************************************************/
@@ -582,10 +605,13 @@ QScrollBar::sub-line:horizontal, QScrollBar::sub-line:vertical {
WWidget, QLabel {
font-family: "Open Sans";
- font-size: 8px;
text-transform: uppercase;
}
+WWidget {
+ font-size: 8px;
+}
+
/* Start spacing for Deck overview row (small waveform, option grid) */
#OptionGrid {
background-color: #333333;
@@ -1077,17 +1103,17 @@ WWidgetGroup {
** Buttons *******************************************************************
*******************************************************************************/
-WPushButton {
+WPushButton, QToolButton {
color: #D2D2D2;
background-color: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0,
stop: 0 #4B4B4B,
stop: 1 #4B4B4B);
- border: 1px solid #4B4B4B;
+ border: 0px solid #4B4B4B;
border-radius: 2px;
outline: none;
}
-WPushButton:hover {
+WPushButton:hover, QToolButton:hover {
color: #D2D2D2;
background-color: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0,
stop: 0 #5F5F5F,
@@ -1096,7 +1122,7 @@ WPushButton:hover {
}
/*"Pressed" state*/
-WPushButton[value="1"] {
+WPushButton[value="1"], QToolButton:pressed {
/*color: #FDFDFD;*/
color: #FDFDFD;
background-color: qlineargradient(x1: 0, y1: 1, x2: 0, y2: 0,
diff --git a/res/skins/LateNight/library.xml b/res/skins/LateNight/library.xml
index 4c1c1d4ad664..aeedf94cc3da 100644
--- a/res/skins/LateNight/library.xml
+++ b/res/skins/LateNight/library.xml
@@ -13,32 +13,36 @@
horizontal
+
+ LibrarySidebarButtons
+
LibrarySplitter
me,me
- 1,12
+ 1,6,6
[LateNight],LibrarySidebarSplitSize
vertical
-
-
CoverArtSplitter
me,me
- 1,1
+ 30,30
+ 2,8
[LateNight],CoverArtSplitSize
vertical
0,0
-
+
+ LibrarySidebarExpanded
+
me,me
- 40,40
+ 30,30,
[Library],show_coverart
visible
@@ -49,14 +53,31 @@
-
-
vertical
-
- #585858
- #eece33
-
+
+ 1
+
+
+ 1
+
+
+ 1
+
+
+
+
+ vertical
+
+
+ 2
+
+
+ 2
+
+
+ 2
+
diff --git a/res/skins/LateNight/style.qss b/res/skins/LateNight/style.qss
index 048b542d72ea..6574cba37f21 100644
--- a/res/skins/LateNight/style.qss
+++ b/res/skins/LateNight/style.qss
@@ -49,19 +49,6 @@
background-color: #0f0f0f;
}
-#LibrarySingleton {
- padding-top: 5px;
- padding-bottom: 2px;
-}
-
-#Library {
- border-left: 0px solid #585858;
- background-color: #0e0e0e;
- padding-top: 5px;
- padding-bottom: 2px;
- /*border-top: 1px solid #585858;*/
-}
-
#DeckRowOne {
qproperty-layoutAlignment: 'AlignLeft | AlignTop';
border-bottom: 1px solid #585858;
@@ -1156,17 +1143,142 @@
/* Library styling is hard */
-QTableView, QTextBrowser, QTreeView {
+#LibrarySingleton {
+ padding-top: 5px;
+ padding-bottom: 2px;
+}
+
+#Library {
+ border-left: 0px solid #585858;
+ background-color: #0e0e0e;
+ padding-top: 5px;
+ padding-bottom: 2px;
+ /*border-top: 1px solid #585858;*/
+}
+
+#LibrarySidebarExpanded QWidget {
+ background-color: #0f0f0f;
+}
+
+#LibrarySidebarExpanded QScrollArea {
+ border: 1px solid #585858;
+}
+
+#LibrarySidebarExpanded QTabWidget QTreeView, #DlgAutoDJ QScrollArea {
+ margin: 0;
+ border: none;
+}
+
+#LibrarySidebarExpanded QTabWidget {
+ border: none
+}
+
+#LibrarySidebarExpanded QTabWidget::pane,
+#LibrarySidebarExpanded #DlgRecording,
+#LibrarySidebarExpanded #DlgAnalysis {
+ border: 1px solid #585858;
+}
+
+#LibrarySidebarExpanded QTabBar::tab {
+ padding: 5px;
+ border: none;
+ color: #cfb32c;
+ background-color: #191919;
+ border-top-left-radius: 2px;
+ border-top-right-radius: 2px;
+}
+
+#LibrarySidebarExpanded QTabBar::tab:hover {
+ border-top: 2px solid #585858;
+ border-right: 2px solid #585858;
+ border-left: 2px solid #585858;
+ background-color: #232323;
+}
+
+#LibrarySidebarExpanded QTabBar::tab:!enabled {
+ color: #7A6919;
+ background-color: #191919;
+}
+
+
+#LibrarySidebarExpanded QTabBar::tab:focus {
+ border-top: 2px solid #8E5C00;
+ border-right: 2px solid #8E5C00;
+ border-left: 2px solid #8E5C00;
+ background-color: #232323;
+}
+
+#LibrarySidebarExpanded QTabBar::tab:selected {
+ background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #585858, stop:1 #0f0f0f);
+}
+
+#LibrarySidebarExpanded QWidget:!enabled {
+ color: #666666;
+}
+
+#LibrarySidebarButtons QToolButton {
+ margin: 0px 0px 0px 0px;
+ padding: 0px 0px 0px 0px;
+ border: none;
+ color: #cfb32c;
+ background-color: #191919;
+}
+
+#LibrarySidebarExpanded QPushButton {
+ margin: 2px 3px 2px 3px;
+ padding: 4px 6px;
+ min-width: 65px;
+ border: none;
+ color: #cfb32c;
+ background-color: #191919;
+}
+
+#LibrarySidebarButtons QToolButton:hover,
+#LibrarySidebarExpanded QPushButton:hover {
+ border: 1px solid #585858;
+ background-color: #232323;
+ color: #cfb32c;
+}
+
+#LibrarySidebarButtons QToolButton:hover {
+ border-radius: 10px;
+}
+
+#LibrarySidebarButtons QToolButton:focus {
+ border-radius: 10px;
+}
+
+#LibrarySidebarButtons:focus,
+#LibrarySidebarButtons QToolButton:focus,
+#LibrarySidebarExpanded > QWidget:focus,
+#LibrarySidebarExpanded QAbstractScrollArea > QWidget:focus {
+ border: 1px solid #8E5C00;
+}
+
+#LibrarySidebarButtons WButtonBar {
+ background-color: #191919;
+ margin-right: 11px;
+}
+
+#LibrarySidebarButtons {
+ margin-right: 5px;
+}
+
+#LibrarySidebarButtons, QTableView, QTextBrowser, QTreeView {
border: 1px solid #585858;
/*font: 15px/18px;*/
color: #cfb32c;
- background-color: #0f0f0f;
+ background-color: #191919;
alternate-background-color: #1a1a1a;
selection-color: #cfb32c;
selection-background-color: #725309;
}
+WLibraryBreadCrumb {
+ margin: 4px 2px;
+}
+
/* checkbox in library "Played" column */
QTableView::indicator { width: 12px; height: 12px;}
QTableView::indicator:checked { background: url(skin:/style/style_checkbox_checked.png);}
@@ -1286,30 +1398,13 @@ WCoverArt { background: transparent; color: #ACACAC; }
QLabel, QRadioButton { background: transparent; color: #cfb32c; }
/* Additional space for QRadionButtons and QLabels */
-WLibrary QRadioButton, WLibrary QLabel { margin: 9px 3px 6px 3px; }
-
-/* Additional space for the first QRadionButton in the row */
-WLibrary QRadioButton#radioButtonRecentlyAdded { margin: 9px 3px 6px 12px; }
+WBaseLibrary QRadioButton, WBaseLibrary QLabel { margin: 9px 3px 6px 3px; }
-/* Additional space for the QPushButtons */
-#DlgMissing > QPushButton,
-#DlgHidden > QPushButton,
-#DlgAutoDJ > QPushButton,
-#DlgRecording > QPushButton,
-#DlgAnalysis > QPushButton { margin: 9px 3px 6px 3px; padding: 3px 8px; min-width: 65px; }
-
-/* Additional space for the first QPushButton in the row */
-#DlgMissing > QPushButton#btnPurge,
-#DlgHidden > QPushButton#btnUnhide,
-#DlgAutoDJ > QPushButton#pushButtonAutoDJ,
-#DlgRecording > QPushButton#pushButtonRecording,
-#DlgAnalysis > QPushButton#pushButtonAnalyze { margin: 9px 12px 6px 3px; }
-
-/* Additional space for the last QPushButton in the row */
-#DlgAutoDJ > QPushButton#pushButtonShuffle { margin: 9px 3px 6px 12px; }
+/* Additional space for the first QRadionButton in the row
+WBaseLibrary QRadioButton#radioButtonRecentlyAdded { margin: 9px 3px 6px 12px; } */
/* Spacing between treeview and searchbar */
-QTreeView { margin: 10px 0px 0px 0px; }
+QTreeView { margin: 0px 0px 0px 0px; }
/* triangle for closed/opened branches in treeview */
QTreeView { show-decoration-selected: 0; background-color: #151515; } /* Suppresses that selected sidebar items branch indicator shows wrong color when out of focus ; lp:880588 */
@@ -1333,3 +1428,13 @@ QTreeView::item:selected {
background-color:qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #585858, stop:1 #0f0f0f);
color: #cfb32c;
}
+
+WLibrary[showFocus="0"] {
+ padding: 1px 0 0 0;
+ border: none;
+}
+
+WLibrary[showFocus="1"] {
+ padding: 1px 0 0 0;
+ border-top: 1px solid #FF7100 !important;
+}
\ No newline at end of file
diff --git a/res/skins/Shade/skin.xml b/res/skins/Shade/skin.xml
index e61033ff9b00..3cf830d730b1 100644
--- a/res/skins/Shade/skin.xml
+++ b/res/skins/Shade/skin.xml
@@ -1,3 +1,4 @@
+
QLabel, QRadioButton {
@@ -460,32 +461,65 @@
background: transparent;
color: #C1C1C1;}
-
- WLibrary QRadioButton, WLibrary QLabel { margin: 9px 3px 6px 3px; }
+
+ WBaseLibrary QPushButton {
+ margin: 2px 3px;
+ padding: 3px 3px;
+ }
+
+ WBaseLibrary QScrollArea,
+ QScrollArea QWidget {
+ background-color: transparent;
+ }
-
- WLibrary QRadioButton#radioButtonRecentlyAdded { margin: 9px 3px 6px 12px; }
+ WBaseLibrary QTabWidget QTreeView, #DlgAutoDJ QScrollArea {
+ background-color: #191919;
+ border: none;
+ }
-
- #DlgMissing > QPushButton,
- #DlgHidden > QPushButton,
- #DlgAutoDJ > QPushButton,
- #DlgRecording > QPushButton,
- #DlgAnalysis > QPushButton {
- margin: 9px 3px 6px 3px;
- padding: 3px 8px;
- min-width: 65px;
+ WBaseLibrary QTabWidget::pane {
+ background-color: #191919;
+ border: 1px solid #646464;
+ }
+
+ WBaseLibrary QPushButton {
+ border: 1px solid black;
+ background-color: #aab2b7;
+ }
+
+ #LibrarySidebarButtons, #LibrarySidebarButtons WButtonBar {
+ background-color: #8d98a3;
+ margin-right: 13px;
+ }
+
+ #LibrarySidebarButtons QScrollArea {
+ background-color: #8d98a3;
}
-
- #DlgMissing > QPushButton#btnPurge,
- #DlgHidden > QPushButton#btnUnhide,
- #DlgAutoDJ > QPushButton#pushButtonAutoDJ,
- #DlgRecording > QPushButton#pushButtonRecording,
- #DlgAnalysis > QPushButton#pushButtonAnalyze { margin: 9px 12px 6px 3px; }
+ WButtonBar QToolButton {
+ padding: 2px 2px 2px 2px;
+ color: black;
+ border: none;
+ background-color: #aab2b7;
+ }
+
+ WButtonBar QToolButton:hover {
+ border: 2px solid #626f87;
+ }
+
+ WBaseLibrary[showFocus="0"] {
+ padding: 2px 0 0 0;
+ border: none;
+ }
+
+ WBaseLibrary[showFocus="1"] {
+ padding: 2px 1px 1px 1px;
+ border-top: 2px solid aqua;
+ }
-
- #DlgAutoDJ > QPushButton#pushButtonShuffle { margin: 9px 3px 6px 12px; }
+ WLibraryBreadCrumb {
+ margin: 2px 4px;
+ }
QTreeView { margin: 0px 0px 0px 5px; }
@@ -506,11 +540,10 @@
me,me
-
+ [Shade],LibrarySidebarSplitSize
1,e
-
vertical
@@ -527,138 +560,138 @@
- vertical
-
-
-
- horizontal
+ vertical
-
-
- text
-
- [PreviewDeck1]
-
- 50me,15f
- right
-
-
-
- eject
-
- 1
-
- 0
- btn_eject1_over.png
- btn_eject1.png
-
-
-
- [PreviewDeck1],eject
- true
- LeftButton
- false
-
-
-
-
-
-
-
- horizontal
-
-
- play_start
-
- 2
- true
-
- 0
- btn_play_sampler_down.png
- btn_play_sampler.png
-
-
- 1
- btn_play_sampler_overdown.png
- btn_play_sampler_over.png
-
- 2,2
-
- [PreviewDeck1],play
- true
- LeftButton
-
-
- [PreviewDeck1],start
- true
- RightButton
- false
-
-
-
- waveform_overview
-
- [PreviewDeck1]
- me,30f
- #8D98A3
- #FFE300
- #0099FF
- #FF0035
- #FF8000
- #00FF00
-
- bottom
- #FFFFFF
- #00FF00
- %1
-
-
- cue_point
- C
- top
- #FF001C
- #00FF00
-
-
- [PreviewDeck1],playposition
- false
-
-
+
+ horizontal
+
+
+
+ text
+
+ [PreviewDeck1]
+
+ 50me,15f
+ right
+
+
+
+ eject
+
+ 1
+
+ 0
+ btn_eject1_over.png
+ btn_eject1.png
+
+
+
+ [PreviewDeck1],eject
+ true
+ LeftButton
+ false
+
+
+
+
+
+
+
+ horizontal
+
+
+ play_start
+
+ 2
+ true
+
+ 0
+ btn_play_sampler_down.png
+ btn_play_sampler.png
+
+
+ 1
+ btn_play_sampler_overdown.png
+ btn_play_sampler_over.png
+
+ 2,2
+
+ [PreviewDeck1],play
+ true
+ LeftButton
+
+
+ [PreviewDeck1],start
+ true
+ RightButton
+ false
+
+
+
+ waveform_overview
+
+ [PreviewDeck1]
+ me,30f
+ #8D98A3
+ #FFE300
+ #0099FF
+ #FF0035
+ #FF8000
+ #00FF00
+
+ bottom
+ #FFFFFF
+ #00FF00
+ %1
+
+
+ cue_point
+ C
+ top
+ #FF001C
+ #00FF00
+
+
+ [PreviewDeck1],playposition
+ false
+
+
+
+
-
-
@@ -708,7 +741,7 @@
**********************************************
-->
- pregain
+ [Deere],LibrarySidebarSplitSizepregain
knob_volume_previewdeck.png
slider_volume_previewdeck.png
@@ -727,35 +760,62 @@
visible
-
-
-
- e,me
-
- 1,e
- 0,0
+
+ horizontal
-
-
-
- 16,16
+
+ LibrarySidebarButtons
+
+
+ vertical
+ 8,2
me,me
-
- [Library],show_coverart
- visible
-
-
+
+
+ LibrarySidebarExpanded
+
+
+
+ 30,30
+ me,me
+
+ [Library],show_coverart
+ visible
+
+
+
+
-
+
+
+
+
+ vertical
+
+
+ 1
+
+
+ 1
+
+
+ 1
+
-
-
vertical
-
+
+ 2
+
+
+ 2
+
+
+ 2
+
diff --git a/src/library/analysisfeature.cpp b/src/library/analysisfeature.cpp
index ab925a9a2b7a..3d0ac1ec1642 100644
--- a/src/library/analysisfeature.cpp
+++ b/src/library/analysisfeature.cpp
@@ -4,29 +4,31 @@
#include
+#include "analyzer/analyzerqueue.h"
+#include "controllers/keyboard/keyboardeventfilter.h"
#include "library/analysisfeature.h"
+#include "library/dlganalysis.h"
+#include "library/library.h"
#include "library/librarytablemodel.h"
#include "library/trackcollection.h"
-#include "library/dlganalysis.h"
-#include "widget/wlibrary.h"
-#include "controllers/keyboard/keyboardeventfilter.h"
-#include "analyzer/analyzerqueue.h"
+#include "library/treeitem.h"
#include "sources/soundsourceproxy.h"
-#include "util/dnd.h"
#include "util/debug.h"
+#include "util/dnd.h"
+#include "widget/wanalysislibrarytableview.h"
+#include "widget/wlibrary.h"
+#include "widget/wtracktableview.h"
-const QString AnalysisFeature::m_sAnalysisViewName = QString("Analysis");
-
-AnalysisFeature::AnalysisFeature(QObject* parent,
- UserSettingsPointer pConfig,
- TrackCollection* pTrackCollection) :
- LibraryFeature(parent),
- m_pConfig(pConfig),
- m_pTrackCollection(pTrackCollection),
- m_pAnalyzerQueue(NULL),
+AnalysisFeature::AnalysisFeature(UserSettingsPointer pConfig,
+ Library* pLibrary, TrackCollection* pTrackCollection,
+ QObject* parent) :
+ LibraryFeature(pConfig, pLibrary, pTrackCollection, parent),
+ m_pAnalyzerQueue(nullptr),
m_iOldBpmEnabled(0),
m_analysisTitleName(tr("Analyze")),
- m_pAnalysisView(NULL) {
+ m_pAnalysisView(nullptr){
+
+ m_childModel.setRootItem(new TreeItem("$root", "$root", this, nullptr));
setTitleDefault();
}
@@ -58,35 +60,36 @@ QIcon AnalysisFeature::getIcon() {
return QIcon(":/images/library/ic_library_prepare.png");
}
-void AnalysisFeature::bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* keyboard) {
- m_pAnalysisView = new DlgAnalysis(libraryWidget,
- m_pConfig,
- m_pTrackCollection);
- connect(m_pAnalysisView, SIGNAL(loadTrack(TrackPointer)),
- this, SIGNAL(loadTrack(TrackPointer)));
- connect(m_pAnalysisView, SIGNAL(loadTrackToPlayer(TrackPointer, QString)),
- this, SIGNAL(loadTrackToPlayer(TrackPointer, QString)));
- connect(m_pAnalysisView, SIGNAL(analyzeTracks(QList)),
- this, SLOT(analyzeTracks(QList)));
- connect(m_pAnalysisView, SIGNAL(stopAnalysis()),
- this, SLOT(stopAnalysis()));
-
- connect(m_pAnalysisView, SIGNAL(trackSelected(TrackPointer)),
- this, SIGNAL(trackSelected(TrackPointer)));
+QWidget* AnalysisFeature::createPaneWidget(KeyboardEventFilter* pKeyboard,
+ int paneId) {
+ WTrackTableView* pTable = LibraryFeature::createTableWidget(pKeyboard, paneId);
+ pTable->loadTrackModel(getAnalysisTableModel());
+ connect(pTable->selectionModel(),
+ SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
+ this,
+ SLOT(tableSelectionChanged(const QItemSelection&, const QItemSelection&)));
+
+ return pTable;
+}
+QWidget* AnalysisFeature::createInnerSidebarWidget(KeyboardEventFilter* pKeyboard) {
+ m_pAnalysisView = new DlgAnalysis(nullptr, this, m_pTrackCollection);
+
+ m_pAnalysisView->setTableModel(getAnalysisTableModel());
+
connect(this, SIGNAL(analysisActive(bool)),
m_pAnalysisView, SLOT(analysisActive(bool)));
connect(this, SIGNAL(trackAnalysisStarted(int)),
m_pAnalysisView, SLOT(trackAnalysisStarted(int)));
- m_pAnalysisView->installEventFilter(keyboard);
-
+ m_pAnalysisView->installEventFilter(pKeyboard);
+
// Let the DlgAnalysis know whether or not analysis is active.
- bool bAnalysisActive = m_pAnalyzerQueue != NULL;
+ bool bAnalysisActive = m_pAnalyzerQueue != nullptr;
emit(analysisActive(bAnalysisActive));
-
- libraryWidget->registerView(m_sAnalysisViewName, m_pAnalysisView);
+ m_pAnalysisView->onShow();
+
+ return m_pAnalysisView;
}
TreeItemModel* AnalysisFeature::getChildModel() {
@@ -94,22 +97,32 @@ TreeItemModel* AnalysisFeature::getChildModel() {
}
void AnalysisFeature::refreshLibraryModels() {
- if (m_pAnalysisView) {
+ if (!m_pAnalysisView.isNull()) {
m_pAnalysisView->onShow();
}
}
+void AnalysisFeature::selectAll() {
+ QPointer pTable = LibraryFeature::getFocusedTable();
+ if (!pTable.isNull()) {
+ pTable->selectAll();
+ }
+}
+
void AnalysisFeature::activate() {
//qDebug() << "AnalysisFeature::activate()";
- emit(switchToView(m_sAnalysisViewName));
- if (m_pAnalysisView) {
- emit(restoreSearch(m_pAnalysisView->currentSearch()));
+ //m_pLibrary->switchToView(m_sAnalysisViewName);
+ m_pLibrary->switchToFeature(this);
+ m_pLibrary->showBreadCrumb(m_childModel.getItem(QModelIndex()));
+
+ if (!m_pAnalysisView.isNull()) {
+ m_pLibrary->restoreSearch(m_pAnalysisView->currentSearch());
}
emit(enableCoverArtDisplay(true));
}
void AnalysisFeature::analyzeTracks(QList trackIds) {
- if (m_pAnalyzerQueue == NULL) {
+ if (m_pAnalyzerQueue == nullptr) {
// Save the old BPM detection prefs setting (on or off)
m_iOldBpmEnabled = m_pConfig->getValueString(ConfigKey("[BPM]","BPMDetectionEnabled")).toInt();
// Force BPM detection to be on.
@@ -153,7 +166,7 @@ void AnalysisFeature::slotProgressUpdate(int num_left) {
void AnalysisFeature::stopAnalysis() {
//qDebug() << this << "stopAnalysis()";
- if (m_pAnalyzerQueue != NULL) {
+ if (m_pAnalyzerQueue != nullptr) {
m_pAnalyzerQueue->stop();
}
}
@@ -161,15 +174,27 @@ void AnalysisFeature::stopAnalysis() {
void AnalysisFeature::cleanupAnalyzer() {
setTitleDefault();
emit(analysisActive(false));
- if (m_pAnalyzerQueue != NULL) {
+ if (m_pAnalyzerQueue != nullptr) {
m_pAnalyzerQueue->stop();
m_pAnalyzerQueue->deleteLater();
- m_pAnalyzerQueue = NULL;
+ m_pAnalyzerQueue = nullptr;
// Restore old BPM detection setting for preferences...
m_pConfig->set(ConfigKey("[BPM]","BPMDetectionEnabled"), ConfigValue(m_iOldBpmEnabled));
}
}
+void AnalysisFeature::tableSelectionChanged(const QItemSelection&,
+ const QItemSelection&) {
+ //qDebug() << "AnalysisFeature::tableSelectionChanged" << sender();
+ QPointer pTable = LibraryFeature::getFocusedTable();
+ if (pTable.isNull()) {
+ return;
+ }
+
+ const QModelIndexList &indexes = pTable->selectionModel()->selectedIndexes();
+ m_pAnalysisView->setSelectedIndexes(indexes);
+}
+
bool AnalysisFeature::dropAccept(QList urls, QObject* pSource) {
Q_UNUSED(pSource);
QList files = DragAndDropHelper::supportedTracksFromUrls(urls, false, true);
@@ -182,3 +207,12 @@ bool AnalysisFeature::dropAccept(QList urls, QObject* pSource) {
bool AnalysisFeature::dragMoveAccept(QUrl url) {
return SoundSourceProxy::isUrlSupported(url);
}
+
+AnalysisLibraryTableModel* AnalysisFeature::getAnalysisTableModel() {
+ if (m_pAnalysisLibraryTableModel.isNull()) {
+ m_pAnalysisLibraryTableModel =
+ new AnalysisLibraryTableModel(this, m_pTrackCollection);
+ }
+
+ return m_pAnalysisLibraryTableModel;
+}
diff --git a/src/library/analysisfeature.h b/src/library/analysisfeature.h
index bbdd853fc45c..2516c8c9efbf 100644
--- a/src/library/analysisfeature.h
+++ b/src/library/analysisfeature.h
@@ -23,9 +23,10 @@ class TrackCollection;
class AnalysisFeature : public LibraryFeature {
Q_OBJECT
public:
- AnalysisFeature(QObject* parent,
- UserSettingsPointer pConfig,
- TrackCollection* pTrackCollection);
+ AnalysisFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ TrackCollection* pTrackCollection,
+ QObject* parent);
virtual ~AnalysisFeature();
QVariant title();
@@ -33,24 +34,28 @@ class AnalysisFeature : public LibraryFeature {
bool dropAccept(QList urls, QObject* pSource);
bool dragMoveAccept(QUrl url);
- void bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* keyboard);
-
+
+ QWidget* createPaneWidget(KeyboardEventFilter* pKeyboard, int paneId) override;
+ QWidget* createInnerSidebarWidget(KeyboardEventFilter* pKeyboard) override;
+
TreeItemModel* getChildModel();
void refreshLibraryModels();
+ void stopAnalysis();
signals:
void analysisActive(bool bActive);
void trackAnalysisStarted(int size);
public slots:
+ void selectAll();
void activate();
void analyzeTracks(QList trackIds);
private slots:
void slotProgressUpdate(int num_left);
- void stopAnalysis();
void cleanupAnalyzer();
+ void tableSelectionChanged(const QItemSelection&,
+ const QItemSelection&);
private:
// Sets the title of this feature to the default name, given by
@@ -61,18 +66,18 @@ class AnalysisFeature : public LibraryFeature {
// where x is the current track being analyzed and y is the total number of
// tracks in the job
void setTitleProgress(int trackNum, int totalNum);
+
+ AnalysisLibraryTableModel* getAnalysisTableModel();
- UserSettingsPointer m_pConfig;
- TrackCollection* m_pTrackCollection;
AnalyzerQueue* m_pAnalyzerQueue;
// Used to temporarily enable BPM detection in the prefs before we analyse
int m_iOldBpmEnabled;
// The title returned by title()
QVariant m_Title;
TreeItemModel m_childModel;
- const static QString m_sAnalysisViewName;
QString m_analysisTitleName;
- DlgAnalysis* m_pAnalysisView;
+ QPointer m_pAnalysisView;
+ QPointer m_pAnalysisLibraryTableModel;
};
diff --git a/src/library/autodj/autodjfeature.cpp b/src/library/autodj/autodjfeature.cpp
index 78ce04f40a5c..27f04b6b003d 100644
--- a/src/library/autodj/autodjfeature.cpp
+++ b/src/library/autodj/autodjfeature.cpp
@@ -5,37 +5,38 @@
#include
#include
#include
+#include
+#include
#include "library/autodj/autodjfeature.h"
#include "library/library.h"
#include "library/parser.h"
-#include "mixer/playermanager.h"
#include "library/autodj/autodjprocessor.h"
#include "library/trackcollection.h"
#include "library/autodj/dlgautodj.h"
#include "library/treeitem.h"
+#include "mixer/playermanager.h"
#include "widget/wlibrary.h"
+#include "widget/wlibrarysidebar.h"
#include "controllers/keyboard/keyboardeventfilter.h"
#include "sources/soundsourceproxy.h"
#include "util/dnd.h"
-const QString AutoDJFeature::m_sAutoDJViewName = QString("Auto DJ");
static const int kMaxRetrieveAttempts = 3;
-AutoDJFeature::AutoDJFeature(Library* pLibrary,
- UserSettingsPointer pConfig,
+AutoDJFeature::AutoDJFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
PlayerManagerInterface* pPlayerManager,
TrackCollection* pTrackCollection)
- : LibraryFeature(pLibrary),
- m_pConfig(pConfig),
- m_pLibrary(pLibrary),
+ : LibraryFeature(pConfig, pLibrary, pTrackCollection, parent),
m_pTrackCollection(pTrackCollection),
m_crateDao(pTrackCollection->getCrateDAO()),
m_playlistDao(pTrackCollection->getPlaylistDAO()),
m_iAutoDJPlaylistId(-1),
- m_pAutoDJProcessor(NULL),
- m_pAutoDJView(NULL),
+ m_pAutoDJProcessor(nullptr),
+ m_pAutoDJView(nullptr),
m_autoDjCratesDao(pTrackCollection->getDatabase(),
pTrackCollection->getTrackDAO(),
pTrackCollection->getCrateDAO(),
@@ -57,6 +58,8 @@ AutoDJFeature::AutoDJFeature(Library* pLibrary,
// Create the "Crates" tree-item under the root item.
TreeItem* root = m_childModel.getItem(QModelIndex());
+ root->setLibraryFeature(this);
+
m_pCratesTreeItem = new TreeItem(tr("Crates"), "", this, root);
m_pCratesTreeItem->setIcon(QIcon(":/images/library/ic_library_crates.png"));
root->appendChild(m_pCratesTreeItem);
@@ -96,28 +99,60 @@ QIcon AutoDJFeature::getIcon() {
return QIcon(":/images/library/ic_library_autodj.png");
}
-void AutoDJFeature::bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* keyboard) {
- m_pAutoDJView = new DlgAutoDJ(libraryWidget,
- m_pConfig,
- m_pLibrary,
- m_pAutoDJProcessor,
- m_pTrackCollection,
- keyboard);
- libraryWidget->registerView(m_sAutoDJViewName, m_pAutoDJView);
- connect(m_pAutoDJView, SIGNAL(loadTrack(TrackPointer)),
- this, SIGNAL(loadTrack(TrackPointer)));
- connect(m_pAutoDJView, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)),
- this, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)));
+QWidget* AutoDJFeature::createPaneWidget(KeyboardEventFilter* pKeyboard, int paneId) {
+ WTrackTableView* pTrackTableView =
+ new WTrackTableView(nullptr, m_pConfig, m_pTrackCollection, false);
+
+ pTrackTableView->installEventFilter(pKeyboard);
+
+ connect(m_pLibrary, SIGNAL(setTrackTableFont(const QFont&)),
+ pTrackTableView, SLOT(setTrackTableFont(const QFont&)));
+ connect(m_pLibrary, SIGNAL(setTrackTableRowHeight(int)),
+ pTrackTableView, SLOT(setTrackTableRowHeight(int)));
+
+ connect(pTrackTableView, SIGNAL(trackSelected(TrackPointer)),
+ m_pLibrary, SIGNAL(trackSelected(TrackPointer)));
+
+ m_trackTables[paneId] = pTrackTableView;
+
+ pTrackTableView->loadTrackModel(m_pAutoDJProcessor->getTableModel());
+
+ connect(pTrackTableView->selectionModel(),
+ SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
+ this,
+ SLOT(selectionChanged(const QItemSelection&, const QItemSelection&)));
+
+ return pTrackTableView;
+}
- connect(m_pAutoDJView, SIGNAL(trackSelected(TrackPointer)),
- this, SIGNAL(trackSelected(TrackPointer)));
+QWidget* AutoDJFeature::createInnerSidebarWidget(KeyboardEventFilter* pKeyboard) {
+ QTabWidget* pContainer = new QTabWidget(nullptr);
+
+ // Add controls
+ m_pAutoDJView = new DlgAutoDJ(pContainer, m_pLibrary, m_pAutoDJProcessor);
+ m_pAutoDJView->installEventFilter(pKeyboard);
+ QScrollArea* pScroll = new QScrollArea(pContainer);
+ pScroll->setWidget(m_pAutoDJView);
+ pScroll->setWidgetResizable(true);
+ pContainer->addTab(pScroll, tr("Controls"));
+
+ // Add drop target
+ WLibrarySidebar* pSidebar = new WLibrarySidebar(pContainer);
+ pSidebar->setModel(&m_childModel);
+ pSidebar->installEventFilter(pKeyboard);
+
+ connect(pSidebar, SIGNAL(rightClicked(const QPoint&, const QModelIndex&)),
+ this, SLOT(onRightClickChild(const QPoint&, const QModelIndex&)));
+
+ pContainer->addTab(pSidebar, tr("Track source"));
// Be informed when the user wants to add another random track.
connect(m_pAutoDJProcessor,SIGNAL(randomTrackRequested(int)),
this,SLOT(slotRandomQueue(int)));
connect(m_pAutoDJView, SIGNAL(addRandomButton(bool)),
this, SLOT(slotAddRandomTrack(bool)));
+
+ return pContainer;
}
TreeItemModel* AutoDJFeature::getChildModel() {
@@ -126,8 +161,16 @@ TreeItemModel* AutoDJFeature::getChildModel() {
void AutoDJFeature::activate() {
//qDebug() << "AutoDJFeature::activate()";
- emit(switchToView(m_sAutoDJViewName));
- emit(restoreSearch(QString())); //Null String disables search box
+ DEBUG_ASSERT_AND_HANDLE(!m_pAutoDJView.isNull()) {
+ return;
+ }
+
+ m_pAutoDJView->onShow();
+
+ m_pLibrary->switchToFeature(this);
+ m_pLibrary->showBreadCrumb(m_childModel.getItem(QModelIndex()));
+ m_pLibrary->restoreSearch(QString()); //Null String disables search box
+
emit(enableCoverArtDisplay(true));
}
@@ -264,6 +307,10 @@ void AutoDJFeature::slotAddRandomTrack(bool) {
TrackPointer addedTrack = (m_pTrackCollection->getTrackDAO()).getTrack(trackId);
if(addedTrack->exists()) {
playlistDao.appendTrackToPlaylist(trackId, m_iAutoDJPlaylistId);
+ DEBUG_ASSERT_AND_HANDLE(!m_pAutoDJView.isNull()) {
+ return;
+ }
+
m_pAutoDJView->onShow();
return;
} else {
@@ -284,6 +331,10 @@ void AutoDJFeature::slotAddRandomTrack(bool) {
if(addedTrack->exists()) {
if(!addedTrack->getPlayCounter().isPlayed()) {
playlistDao.appendTrackToPlaylist(trackId, m_iAutoDJPlaylistId);
+ DEBUG_ASSERT_AND_HANDLE(!m_pAutoDJView.isNull()) {
+ return;
+ }
+
m_pAutoDJView->onShow();
return;
}
@@ -334,21 +385,31 @@ void AutoDJFeature::constructCrateChildModel() {
void AutoDJFeature::onRightClickChild(const QPoint& globalPos,
QModelIndex index) {
//Save the model index so we can get it in the action slots...
- m_lastRightClickedIndex = index;
-
- TreeItem *item = static_cast(index.internalPointer());
- QString crateName = item->dataPath().toString();
- if (crateName.length() > 0) {
+ QString crateName;
+ if (index.isValid()) {
+ m_lastRightClickedIndex = index;
+
+ TreeItem* item = static_cast(index.internalPointer());
+ DEBUG_ASSERT_AND_HANDLE(item) {
+ return;
+ }
+
+ crateName = item->dataPath().toString();
+ }
+
+ if (!crateName.isEmpty()) {
// A crate was right-clicked.
// Bring up the context menu.
- QMenu menu(NULL);
+ QMenu menu(nullptr);
menu.addAction(m_pRemoveCrateFromAutoDj);
menu.exec(globalPos);
- } else {
+ return;
+ }
+ else {
// The "Crates" tree-item was right-clicked.
// Bring up the context menu.
- QMenu menu(NULL);
- QMenu crateMenu(NULL);
+ QMenu menu(nullptr);
+ QMenu crateMenu(nullptr);
crateMenu.setTitle(tr("Add Crate as Track Source"));
QMap crateMap;
m_crateDao.getAutoDjCrates(false, &crateMap);
@@ -375,3 +436,17 @@ void AutoDJFeature::slotRandomQueue(int tracksToAdd) {
tracksToAdd -= 1;
}
}
+
+void AutoDJFeature::selectionChanged(const QItemSelection&, const QItemSelection&) {
+ DEBUG_ASSERT_AND_HANDLE(!m_pAutoDJView.isNull()) {
+ return;
+ }
+
+ auto it = m_trackTables.find(m_featureFocus);
+ if (it == m_trackTables.end() || it->isNull()) {
+ return;
+ }
+
+ const QModelIndexList& selectedRows = (*it)->selectionModel()->selectedRows();
+ m_pAutoDJView->setSelectedRows(selectedRows);
+}
diff --git a/src/library/autodj/autodjfeature.h b/src/library/autodj/autodjfeature.h
index 7cc7d2803c89..a433ec07237c 100644
--- a/src/library/autodj/autodjfeature.h
+++ b/src/library/autodj/autodjfeature.h
@@ -21,6 +21,7 @@
#include "library/treeitemmodel.h"
#include "library/dao/autodjcratesdao.h"
+#include "widget/wtracktableview.h"
class DlgAutoDJ;
class Library;
@@ -31,8 +32,9 @@ class AutoDJProcessor;
class AutoDJFeature : public LibraryFeature {
Q_OBJECT
public:
- AutoDJFeature(Library* pLibrary,
- UserSettingsPointer pConfig,
+ AutoDJFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
PlayerManagerInterface* pPlayerManager,
TrackCollection* pTrackCollection);
virtual ~AutoDJFeature();
@@ -43,8 +45,8 @@ class AutoDJFeature : public LibraryFeature {
bool dropAccept(QList urls, QObject* pSource);
bool dragMoveAccept(QUrl url);
- void bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* keyboard);
+ QWidget* createPaneWidget(KeyboardEventFilter* pKeyboard, int paneId) override;
+ QWidget* createInnerSidebarWidget(KeyboardEventFilter* pKeyboard) override;
TreeItemModel* getChildModel();
@@ -55,17 +57,15 @@ class AutoDJFeature : public LibraryFeature {
void onRightClickChild(const QPoint& globalPos, QModelIndex index);
private:
- UserSettingsPointer m_pConfig;
- Library* m_pLibrary;
TrackCollection* m_pTrackCollection;
CrateDAO& m_crateDao;
PlaylistDAO& m_playlistDao;
// The id of the AutoDJ playlist.
int m_iAutoDJPlaylistId;
AutoDJProcessor* m_pAutoDJProcessor;
- const static QString m_sAutoDJViewName;
TreeItemModel m_childModel;
- DlgAutoDJ* m_pAutoDJView;
+ QPointer m_pAutoDJView;
+ QHash > m_trackTables;
// Initialize the list of crates loaded into the auto-DJ queue.
void constructCrateChildModel();
@@ -118,6 +118,7 @@ class AutoDJFeature : public LibraryFeature {
// of tracks in the playlist
void slotRandomQueue(int);
+ void selectionChanged(const QItemSelection&, const QItemSelection&);
};
diff --git a/src/library/autodj/dlgautodj.cpp b/src/library/autodj/dlgautodj.cpp
index 9b2197e422e8..30a449dc4308 100644
--- a/src/library/autodj/dlgautodj.cpp
+++ b/src/library/autodj/dlgautodj.cpp
@@ -8,67 +8,31 @@
#include "util/duration.h"
DlgAutoDJ::DlgAutoDJ(QWidget* parent,
- UserSettingsPointer pConfig,
Library* pLibrary,
- AutoDJProcessor* pProcessor,
- TrackCollection* pTrackCollection,
- KeyboardEventFilter* pKeyboard)
- : QWidget(parent),
+ AutoDJProcessor* pProcessor)
+ : QFrame(parent),
Ui::DlgAutoDJ(),
m_pAutoDJProcessor(pProcessor),
// no sorting
- m_pTrackTableView(new WTrackTableView(this, pConfig,
- pTrackCollection, false)),
- m_pAutoDJTableModel(NULL) {
+ m_pAutoDJTableModel(nullptr),
+ m_pLibrary(pLibrary) {
setupUi(this);
- m_pTrackTableView->installEventFilter(pKeyboard);
- connect(m_pTrackTableView, SIGNAL(loadTrack(TrackPointer)),
- this, SIGNAL(loadTrack(TrackPointer)));
- connect(m_pTrackTableView, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)),
- this, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)));
- connect(m_pTrackTableView, SIGNAL(trackSelected(TrackPointer)),
- this, SIGNAL(trackSelected(TrackPointer)));
- connect(pLibrary, SIGNAL(setTrackTableFont(QFont)),
- m_pTrackTableView, SLOT(setTrackTableFont(QFont)));
- connect(pLibrary, SIGNAL(setTrackTableRowHeight(int)),
- m_pTrackTableView, SLOT(setTrackTableRowHeight(int)));
- connect(m_pTrackTableView, SIGNAL(trackSelected(TrackPointer)),
- this, SLOT(updateSelectionInfo()));
-
-
- QBoxLayout* box = dynamic_cast(layout());
- DEBUG_ASSERT_AND_HANDLE(box) { //Assumes the form layout is a QVBox/QHBoxLayout!
- } else {
- box->removeWidget(m_pTrackTablePlaceholder);
- m_pTrackTablePlaceholder->hide();
- box->insertWidget(1, m_pTrackTableView);
- }
-
// We do _NOT_ take ownership of this from AutoDJProcessor.
m_pAutoDJTableModel = m_pAutoDJProcessor->getTableModel();
- m_pTrackTableView->loadTrackModel(m_pAutoDJTableModel);
// Override some playlist-view properties:
- // Do not set this because it disables auto-scrolling
- //m_pTrackTableView->setDragDropMode(QAbstractItemView::InternalMove);
-
connect(pushButtonShuffle, SIGNAL(clicked(bool)),
this, SLOT(shufflePlaylistButton(bool)));
-
connect(pushButtonSkipNext, SIGNAL(clicked(bool)),
this, SLOT(skipNextButton(bool)));
-
connect(pushButtonAddRandom, SIGNAL(clicked(bool)),
this, SIGNAL(addRandomButton(bool)));
-
connect(pushButtonFadeNow, SIGNAL(clicked(bool)),
this, SLOT(fadeNowButton(bool)));
-
connect(spinBoxTransition, SIGNAL(valueChanged(int)),
this, SLOT(transitionSliderChanged(int)));
-
connect(pushButtonAutoDJ, SIGNAL(toggled(bool)),
this, SLOT(toggleAutoDJButton(bool)));
@@ -81,45 +45,30 @@ DlgAutoDJ::DlgAutoDJ(QWidget* parent,
connect(m_pAutoDJProcessor, SIGNAL(autoDJStateChanged(AutoDJProcessor::AutoDJState)),
this, SLOT(autoDJStateChanged(AutoDJProcessor::AutoDJState)));
autoDJStateChanged(m_pAutoDJProcessor->getState());
-
- updateSelectionInfo();
}
DlgAutoDJ::~DlgAutoDJ() {
- qDebug() << "~DlgAutoDJ()";
-
- // Delete m_pTrackTableView before the table model. This is because the
- // table view saves the header state using the model.
- delete m_pTrackTableView;
+ //qDebug() << "~DlgAutoDJ()";
}
void DlgAutoDJ::onShow() {
m_pAutoDJTableModel->select();
}
-void DlgAutoDJ::onSearch(const QString& text) {
- // Do not allow filtering the Auto DJ playlist, because
- // Auto DJ will work from the filtered table
- Q_UNUSED(text);
-}
-
-void DlgAutoDJ::loadSelectedTrack() {
- m_pTrackTableView->loadSelectedTrack();
-}
-
-void DlgAutoDJ::loadSelectedTrackToGroup(QString group, bool play) {
- m_pTrackTableView->loadSelectedTrackToGroup(group, play);
-}
-
-void DlgAutoDJ::moveSelection(int delta) {
- m_pTrackTableView->moveSelection(delta);
+void DlgAutoDJ::setSelectedRows(const QModelIndexList& selectedRows) {
+ m_selectedRows = selectedRows;
+ updateSelectionInfo();
}
-void DlgAutoDJ::shufflePlaylistButton(bool) {
- QModelIndexList indexList = m_pTrackTableView->selectionModel()->selectedRows();
-
- // Activate regardless of button being checked
- m_pAutoDJProcessor->shufflePlaylist(indexList);
+void DlgAutoDJ::shufflePlaylistButton(bool) {
+ LibraryView* pView = m_pLibrary->getActiveView();
+ WTrackTableView* pTrackTable = dynamic_cast(pView);
+
+ if (pView) {
+ QModelIndexList indexList = pTrackTable->selectionModel()->selectedRows();
+ // Activate regardless of button being checked
+ m_pAutoDJProcessor->shufflePlaylist(indexList);
+ }
}
void DlgAutoDJ::skipNextButton(bool) {
@@ -191,35 +140,24 @@ void DlgAutoDJ::autoDJStateChanged(AutoDJProcessor::AutoDJState state) {
}
}
-void DlgAutoDJ::setTrackTableFont(const QFont& font) {
- m_pTrackTableView->setTrackTableFont(font);
-}
-
-void DlgAutoDJ::setTrackTableRowHeight(int rowHeight) {
- m_pTrackTableView->setTrackTableRowHeight(rowHeight);
-}
-
void DlgAutoDJ::updateSelectionInfo() {
+ if (m_selectedRows.isEmpty()) {
+ labelSelectionInfo->setText("");
+ labelSelectionInfo->setEnabled(false);
+ return;
+ }
+
double duration = 0.0;
-
- QModelIndexList indices = m_pTrackTableView->selectionModel()->selectedRows();
-
- for (int i = 0; i < indices.size(); ++i) {
- TrackPointer pTrack = m_pAutoDJTableModel->getTrack(indices.at(i));
+ for (const QModelIndex& mIndex : m_selectedRows) {
+ TrackPointer pTrack = m_pAutoDJTableModel->getTrack(mIndex);
if (pTrack) {
duration += pTrack->getDuration();
}
}
QString label;
-
- if (!indices.isEmpty()) {
- label.append(mixxx::Duration::formatSeconds(duration));
- label.append(QString(" (%1)").arg(indices.size()));
- labelSelectionInfo->setText(label);
- labelSelectionInfo->setEnabled(true);
- } else {
- labelSelectionInfo->setText("");
- labelSelectionInfo->setEnabled(false);
- }
+ label.append(mixxx::Duration::formatSeconds(duration));
+ label.append(QString(" (%1)").arg(m_selectedRows.size()));
+ labelSelectionInfo->setText(label);
+ labelSelectionInfo->setEnabled(true);
}
diff --git a/src/library/autodj/dlgautodj.h b/src/library/autodj/dlgautodj.h
index fda36bcdcbbe..f7ac02d61968 100644
--- a/src/library/autodj/dlgautodj.h
+++ b/src/library/autodj/dlgautodj.h
@@ -3,6 +3,7 @@
#include
#include
+#include
#include "library/autodj/ui_dlgautodj.h"
#include "preferences/usersettings.h"
@@ -16,20 +17,16 @@
class PlaylistTableModel;
class WTrackTableView;
-class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView {
+class DlgAutoDJ : public QFrame, public Ui::DlgAutoDJ {
Q_OBJECT
public:
- DlgAutoDJ(QWidget* parent, UserSettingsPointer pConfig,
- Library* pLibrary,
- AutoDJProcessor* pProcessor, TrackCollection* pTrackCollection,
- KeyboardEventFilter* pKeyboard);
+ DlgAutoDJ(QWidget* parent, Library *pLibrary, AutoDJProcessor* pProcessor);
virtual ~DlgAutoDJ();
-
+
void onShow();
- void onSearch(const QString& text);
- void loadSelectedTrack();
- void loadSelectedTrackToGroup(QString group, bool play);
- void moveSelection(int delta);
+
+ // These seleced rows are always from the focused pane
+ void setSelectedRows(const QModelIndexList& selectedRows);
public slots:
void shufflePlaylistButton(bool buttonChecked);
@@ -39,20 +36,17 @@ class DlgAutoDJ : public QWidget, public Ui::DlgAutoDJ, public LibraryView {
void transitionTimeChanged(int time);
void transitionSliderChanged(int value);
void autoDJStateChanged(AutoDJProcessor::AutoDJState state);
- void setTrackTableFont(const QFont& font);
- void setTrackTableRowHeight(int rowHeight);
void updateSelectionInfo();
signals:
void addRandomButton(bool buttonChecked);
- void loadTrack(TrackPointer tio);
- void loadTrackToPlayer(TrackPointer tio, QString group, bool);
- void trackSelected(TrackPointer pTrack);
-
+
private:
AutoDJProcessor* m_pAutoDJProcessor;
- WTrackTableView* m_pTrackTableView;
PlaylistTableModel* m_pAutoDJTableModel;
+ Library* m_pLibrary;
+
+ QModelIndexList m_selectedRows;
};
#endif //DLGAUTODJ_H
diff --git a/src/library/autodj/dlgautodj.ui b/src/library/autodj/dlgautodj.ui
index f71a2a1cbd6d..b8c2bb67a1c4 100644
--- a/src/library/autodj/dlgautodj.ui
+++ b/src/library/autodj/dlgautodj.ui
@@ -6,7 +6,7 @@
0
0
- 560
+ 507
399
@@ -14,81 +14,15 @@
Auto DJ
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
-
- Shuffle the content of the Auto DJ playlist.
-
-
- Shuffle
-
-
- false
-
-
-
- -
-
-
- Add a random track from track sources (crates) or Library to the Auto DJ playlist.
-
-
- Add Random
-
-
-
- -
-
-
- Skip the next track in the Auto DJ playlist.
-
-
- Skip Track
-
-
- false
-
-
-
-
-
+
- Trigger the transition to the next track.
+ Seconds
- Fade Now
+ sec.
@@ -114,16 +48,6 @@
- -
-
-
- Seconds
-
-
- sec.
-
-
-
-
@@ -131,45 +55,95 @@
- 1
+ 40
20
- -
-
-
-
-
-
-
- -
-
-
- Turn Auto DJ on or off.
-
-
- Enable Auto DJ
-
-
- true
-
-
-
-
-
-
+
+
+ Turn Auto DJ on or off.
+
+
+ Enable Auto DJ
+
+
true
+ -
+
+
+
+
+
+
+ -
+
+
+ Trigger the transition to the next track.
+
+
+ Fade Now
+
+
+
+ -
+
+
+ Skip the next track in the Auto DJ playlist.
+
+
+ Skip Track
+
+
+ false
+
+
+
+ -
+
+
+ Add a random track from track sources (crates) or Library to the Auto DJ playlist.
+
+
+ Add Random
+
+
+
+ -
+
+
+ Shuffle the content of the Auto DJ playlist.
+
+
+ Shuffle
+
+
+ false
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 172
+
+
+
+
-
-
-
+
diff --git a/src/library/banshee/bansheefeature.cpp b/src/library/banshee/bansheefeature.cpp
index 05ee9c67a3dc..6e90b8b67bbb 100644
--- a/src/library/banshee/bansheefeature.cpp
+++ b/src/library/banshee/bansheefeature.cpp
@@ -8,15 +8,17 @@
#include "library/dao/settingsdao.h"
#include "library/baseexternalplaylistmodel.h"
#include "library/banshee/bansheeplaylistmodel.h"
+#include "library/library.h"
const QString BansheeFeature::BANSHEE_MOUNT_KEY = "mixxx.BansheeFeature.mount";
QString BansheeFeature::m_databaseFile;
-BansheeFeature::BansheeFeature(QObject* parent,
- TrackCollection* pTrackCollection,
- UserSettingsPointer pConfig)
- : BaseExternalLibraryFeature(parent, pTrackCollection),
+BansheeFeature::BansheeFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection)
+ : BaseExternalLibraryFeature(pConfig, pLibrary, parent, pTrackCollection),
m_pTrackCollection(pTrackCollection),
m_cancelImport(false) {
Q_UNUSED(pConfig);
@@ -91,7 +93,8 @@ void BansheeFeature::activate() {
m_isActivated = true;
- TreeItem* playlist_root = new TreeItem();
+ TreeItem* playlistRoot = new TreeItem();
+ playlistRoot->setLibraryFeature(this);
QList list = m_connection.getPlaylists();
@@ -99,12 +102,12 @@ void BansheeFeature::activate() {
foreach (playlist, list) {
qDebug() << playlist.name;
// append the playlist to the child model
- TreeItem *item = new TreeItem(playlist.name, playlist.playlistId, this, playlist_root);
- playlist_root->appendChild(item);
+ TreeItem *item = new TreeItem(playlist.name, playlist.playlistId, this, playlistRoot);
+ playlistRoot->appendChild(item);
}
- if (playlist_root) {
- m_childModel.setRootItem(playlist_root);
+ if (playlistRoot) {
+ m_childModel.setRootItem(playlistRoot);
if (m_isActivated) {
activate();
}
@@ -117,7 +120,9 @@ void BansheeFeature::activate() {
}
m_pBansheePlaylistModel->setTableModel(0); // Gets the master playlist
- emit(showTrackModel(m_pBansheePlaylistModel));
+
+ showTrackModel(m_pBansheePlaylistModel);
+ m_pLibrary->showBreadCrumb(m_childModel.getItem(QModelIndex()));
emit(enableCoverArtDisplay(false));
}
@@ -129,7 +134,9 @@ void BansheeFeature::activateChild(const QModelIndex& index) {
if (playlistID > 0) {
qDebug() << "Activating " << item->data().toString();
m_pBansheePlaylistModel->setTableModel(playlistID);
- emit(showTrackModel(m_pBansheePlaylistModel));
+
+ showTrackModel(m_pBansheePlaylistModel);
+ m_pLibrary->showBreadCrumb(item);
emit(enableCoverArtDisplay(false));
}
}
diff --git a/src/library/banshee/bansheefeature.h b/src/library/banshee/bansheefeature.h
index 566835896290..096a3b924cdf 100644
--- a/src/library/banshee/bansheefeature.h
+++ b/src/library/banshee/bansheefeature.h
@@ -20,7 +20,10 @@ class BansheePlaylistModel;
class BansheeFeature : public BaseExternalLibraryFeature {
Q_OBJECT
public:
- BansheeFeature(QObject* parent, TrackCollection* pTrackCollection, UserSettingsPointer pConfig);
+ BansheeFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection);
virtual ~BansheeFeature();
static bool isSupported();
static void prepareDbPath(UserSettingsPointer pConfig);
@@ -55,7 +58,7 @@ class BansheeFeature : public BaseExternalLibraryFeature {
bool m_cancelImport;
static QString m_databaseFile;
-
+
static const QString BANSHEE_MOUNT_KEY;
};
diff --git a/src/library/baseexternallibraryfeature.cpp b/src/library/baseexternallibraryfeature.cpp
index 27d69ee48e34..450a9277689f 100644
--- a/src/library/baseexternallibraryfeature.cpp
+++ b/src/library/baseexternallibraryfeature.cpp
@@ -4,10 +4,11 @@
#include "library/basesqltablemodel.h"
-BaseExternalLibraryFeature::BaseExternalLibraryFeature(QObject* pParent,
+BaseExternalLibraryFeature::BaseExternalLibraryFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* pParent,
TrackCollection* pCollection)
- : LibraryFeature(pParent),
- m_pTrackCollection(pCollection) {
+ : LibraryFeature(pConfig, pLibrary, pCollection, pParent) {
m_pAddToAutoDJAction = new QAction(tr("Add to Auto DJ Queue (bottom)"), this);
connect(m_pAddToAutoDJAction, SIGNAL(triggered()),
this, SLOT(slotAddToAutoDJ()));
diff --git a/src/library/baseexternallibraryfeature.h b/src/library/baseexternallibraryfeature.h
index 7a13f5d47d20..43ce15bbbbb8 100644
--- a/src/library/baseexternallibraryfeature.h
+++ b/src/library/baseexternallibraryfeature.h
@@ -12,7 +12,10 @@ class TrackCollection;
class BaseExternalLibraryFeature : public LibraryFeature {
Q_OBJECT
public:
- BaseExternalLibraryFeature(QObject* pParent, TrackCollection* pCollection);
+ BaseExternalLibraryFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* pParent,
+ TrackCollection* pCollection);
virtual ~BaseExternalLibraryFeature();
public slots:
@@ -38,7 +41,6 @@ class BaseExternalLibraryFeature : public LibraryFeature {
private:
void addToAutoDJ(bool bTop);
- TrackCollection* m_pTrackCollection;
QAction* m_pAddToAutoDJAction;
QAction* m_pAddToAutoDJTopAction;
QAction* m_pImportAsMixxxPlaylistAction;
diff --git a/src/library/baseplaylistfeature.cpp b/src/library/baseplaylistfeature.cpp
index f210b08d031a..33221f1cf7e3 100644
--- a/src/library/baseplaylistfeature.cpp
+++ b/src/library/baseplaylistfeature.cpp
@@ -16,19 +16,18 @@
#include "library/treeitem.h"
#include "controllers/keyboard/keyboardeventfilter.h"
#include "widget/wlibrary.h"
+#include "widget/wlibrarystack.h"
#include "widget/wlibrarytextbrowser.h"
#include "util/assert.h"
-BasePlaylistFeature::BasePlaylistFeature(QObject* parent,
- UserSettingsPointer pConfig,
- TrackCollection* pTrackCollection,
- QString rootViewName)
- : LibraryFeature(pConfig, parent),
- m_pTrackCollection(pTrackCollection),
+BasePlaylistFeature::BasePlaylistFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection)
+ : LibraryFeature(pConfig, pLibrary, pTrackCollection, parent),
m_playlistDao(pTrackCollection->getPlaylistDAO()),
m_trackDao(pTrackCollection->getTrackDAO()),
- m_pPlaylistTableModel(NULL),
- m_rootViewName(rootViewName) {
+ m_pPlaylistTableModel(nullptr) {
m_pCreatePlaylistAction = new QAction(tr("Create New Playlist"),this);
connect(m_pCreatePlaylistAction, SIGNAL(triggered()),
this, SLOT(slotCreatePlaylist()));
@@ -92,7 +91,6 @@ BasePlaylistFeature::BasePlaylistFeature(QObject* parent,
connect(&m_playlistDao, SIGNAL(lockChanged(int)),
this, SLOT(slotPlaylistTableChanged(int)));
- Library* pLibrary = static_cast(parent);
connect(pLibrary, SIGNAL(trackSelected(TrackPointer)),
this, SLOT(slotTrackSelected(TrackPointer)));
connect(pLibrary, SIGNAL(switchToView(const QString&)),
@@ -100,7 +98,8 @@ BasePlaylistFeature::BasePlaylistFeature(QObject* parent,
}
BasePlaylistFeature::~BasePlaylistFeature() {
- delete m_pPlaylistTableModel;
+ qDeleteAll(m_playlistTableModel);
+ m_playlistTableModel.clear();
delete m_pCreatePlaylistAction;
delete m_pDeletePlaylistAction;
delete m_pImportPlaylistAction;
@@ -130,18 +129,58 @@ int BasePlaylistFeature::playlistIdFromIndex(QModelIndex index) {
return playlistId;
}
+QPointer BasePlaylistFeature::getPlaylistTableModel(int paneId) {
+ if (paneId < 0) {
+ paneId = m_focusedPane;
+ }
+ auto it = m_playlistTableModel.find(paneId);
+ if (it == m_playlistTableModel.end() || it->isNull()) {
+ it = m_playlistTableModel.insert(paneId, constructTableModel());
+ }
+ return *it;
+}
+
void BasePlaylistFeature::activate() {
- emit(switchToView(m_rootViewName));
- emit(restoreSearch(QString())); // Null String disables search box
+ auto it = m_panes.find(m_featureFocus);
+ auto itId = m_idBrowse.find(m_featureFocus);
+ if (it == m_panes.end() || it->isNull() || itId == m_idBrowse.end()) {
+ return;
+ }
+
+ (*it)->setCurrentIndex(*itId);
+ switchToFeature();
+ showBreadCrumb(m_childModel.getItem(QModelIndex()));
+
+ restoreSearch(QString()); // Null String disables search box
emit(enableCoverArtDisplay(true));
+ m_featureFocus = -1;
}
void BasePlaylistFeature::activateChild(const QModelIndex& index) {
//qDebug() << "BasePlaylistFeature::activateChild()" << index;
int playlistId = playlistIdFromIndex(index);
+ m_pPlaylistTableModel = getPlaylistTableModel(m_focusedPane);
+
if (playlistId != -1 && m_pPlaylistTableModel) {
m_pPlaylistTableModel->setTableModel(playlistId);
- emit(showTrackModel(m_pPlaylistTableModel));
+
+ auto it = m_panes.find(m_focusedPane);
+ auto itId = m_idTable.find(m_focusedPane);
+ if (it == m_panes.end() || it->isNull() || itId == m_idTable.end()) {
+ return;
+ }
+
+ (*it)->setCurrentIndex(*itId);
+
+ // Set the feature Focus for a moment to allow the LibraryFeature class
+ // to find the focused WTrackTable
+ m_featureFocus = m_focusedPane;
+ showTrackModel(m_pPlaylistTableModel);
+ m_featureFocus = -1;
+
+ restoreSearch("");
+ showBreadCrumb(static_cast(index.internalPointer()));
+
emit(enableCoverArtDisplay(true));
}
}
@@ -151,7 +190,8 @@ void BasePlaylistFeature::activatePlaylist(int playlistId) {
QModelIndex index = indexFromPlaylistId(playlistId);
if (playlistId != -1 && index.isValid() && m_pPlaylistTableModel) {
m_pPlaylistTableModel->setTableModel(playlistId);
- emit(showTrackModel(m_pPlaylistTableModel));
+ showTrackModel(m_pPlaylistTableModel);
+ //m_pPlaylistTableModel->select();
emit(enableCoverArtDisplay(true));
// Update selection
emit(featureSelect(this, m_lastRightClickedIndex));
@@ -310,6 +350,11 @@ void BasePlaylistFeature::slotCreatePlaylist() {
}
}
+void BasePlaylistFeature::setFeatureFocus(int focus) {
+ m_pPlaylistTableModel = getPlaylistTableModel(focus);
+ LibraryFeature::setFeatureFocus(focus);
+}
+
void BasePlaylistFeature::slotDeletePlaylist() {
//qDebug() << "slotDeletePlaylist() row:" << m_lastRightClickedIndex.data();
int playlistId = playlistIdFromIndex(m_lastRightClickedIndex);
@@ -593,15 +638,24 @@ TreeItemModel* BasePlaylistFeature::getChildModel() {
return &m_childModel;
}
-void BasePlaylistFeature::bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* keyboard) {
- Q_UNUSED(keyboard);
- WLibraryTextBrowser* edit = new WLibraryTextBrowser(libraryWidget);
+QWidget* BasePlaylistFeature::createPaneWidget(KeyboardEventFilter* pKeyboard,
+ int paneId) {
+ WLibraryStack* pStack = new WLibraryStack(nullptr);
+ m_panes[paneId] = pStack;
+
+ WLibraryTextBrowser* edit = new WLibraryTextBrowser(pStack);
edit->setHtml(getRootViewHtml());
edit->setOpenLinks(false);
+ edit->installEventFilter(pKeyboard);
connect(edit, SIGNAL(anchorClicked(const QUrl)),
this, SLOT(htmlLinkClicked(const QUrl)));
- libraryWidget->registerView(m_rootViewName, edit);
+ m_idBrowse[paneId] = pStack->addWidget(edit);
+
+ QWidget* pTable = LibraryFeature::createPaneWidget(pKeyboard, paneId);
+ pTable->setParent(pStack);
+ m_idTable[paneId] = pStack->addWidget(pTable);
+
+ return pStack;
}
void BasePlaylistFeature::htmlLinkClicked(const QUrl& link) {
@@ -619,6 +673,7 @@ void BasePlaylistFeature::htmlLinkClicked(const QUrl& link) {
*/
QModelIndex BasePlaylistFeature::constructChildModel(int selected_id) {
buildPlaylistList();
+ m_childModel.setRootItem(new TreeItem("$root", "$root", this, nullptr));
QList data_list;
int selected_row = -1;
// Access the invisible root item
diff --git a/src/library/baseplaylistfeature.h b/src/library/baseplaylistfeature.h
index 4b8583cc22d0..73391ef52fc1 100644
--- a/src/library/baseplaylistfeature.h
+++ b/src/library/baseplaylistfeature.h
@@ -16,25 +16,25 @@
#include "library/dao/trackdao.h"
#include "track/track.h"
-class WLibrary;
class KeyboardEventFilter;
class PlaylistTableModel;
class TrackCollection;
class TreeItem;
+class WLibrary;
+class WLibraryStack;
class BasePlaylistFeature : public LibraryFeature {
Q_OBJECT
public:
- BasePlaylistFeature(QObject* parent,
- UserSettingsPointer pConfig,
- TrackCollection* pTrackCollection,
- QString rootViewName);
+ BasePlaylistFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection);
virtual ~BasePlaylistFeature();
TreeItemModel* getChildModel();
- void bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* keyboard);
+ QWidget* createPaneWidget(KeyboardEventFilter*pKeyboard, int paneId) override;
signals:
void showPage(const QUrl& page);
@@ -50,6 +50,7 @@ class BasePlaylistFeature : public LibraryFeature {
virtual void slotPlaylistContentChanged(int playlistId) = 0;
virtual void slotPlaylistTableRenamed(int playlistId, QString a_strName) = 0;
void slotCreatePlaylist();
+ void setFeatureFocus(int focus);
protected slots:
void slotDeletePlaylist();
@@ -75,14 +76,17 @@ class BasePlaylistFeature : public LibraryFeature {
virtual void addToAutoDJ(bool bTop);
int playlistIdFromIndex(QModelIndex index);
+ QPointer getPlaylistTableModel(int paneId);
+ virtual PlaylistTableModel* constructTableModel() = 0;
+
// Get the QModelIndex of a playlist based on its id. Returns QModelIndex()
// on failure.
QModelIndex indexFromPlaylistId(int playlistId);
- TrackCollection* m_pTrackCollection;
PlaylistDAO &m_playlistDao;
TrackDAO &m_trackDao;
- PlaylistTableModel* m_pPlaylistTableModel;
+ QPointer m_pPlaylistTableModel;
+ QHash > m_playlistTableModel;
QAction *m_pCreatePlaylistAction;
QAction *m_pDeletePlaylistAction;
QAction *m_pAddToAutoDJAction;
@@ -108,7 +112,10 @@ class BasePlaylistFeature : public LibraryFeature {
virtual QString getRootViewHtml() const = 0;
QSet m_playlistsSelectedTrackIsIn;
- QString m_rootViewName;
+
+ QHash > m_panes;
+ QHash m_idBrowse;
+ QHash m_idTable;
};
#endif /* BASEPLAYLISTFEATURE_H */
diff --git a/src/library/browse/browsefeature.cpp b/src/library/browse/browsefeature.cpp
index 9f6231b78c0c..cf8c9e586fc7 100644
--- a/src/library/browse/browsefeature.cpp
+++ b/src/library/browse/browsefeature.cpp
@@ -1,33 +1,36 @@
// browsefeature.cpp
// Created 9/8/2009 by RJ Ryan (rryan@mit.edu)
-#include
-#include
+#include
+#include
#include
-#include
#include
-#include
-#include
#include
#include
+#include
+#include
+#include
-#include "track/track.h"
-#include "library/treeitem.h"
+#include "controllers/keyboard/keyboardeventfilter.h"
#include "library/browse/browsefeature.h"
+#include "library/library.h"
#include "library/trackcollection.h"
-#include "widget/wlibrarytextbrowser.h"
-#include "widget/wlibrary.h"
-#include "controllers/keyboard/keyboardeventfilter.h"
+#include "library/treeitem.h"
+#include "track/track.h"
#include "util/sandbox.h"
+#include "widget/wlibrary.h"
+#include "widget/wlibrarystack.h"
+#include "widget/wlibrarytextbrowser.h"
+
const QString kQuickLinksSeparator = "-+-";
-BrowseFeature::BrowseFeature(QObject* parent,
- UserSettingsPointer pConfig,
+BrowseFeature::BrowseFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
TrackCollection* pTrackCollection,
RecordingManager* pRecordingManager)
- : LibraryFeature(parent),
- m_pConfig(pConfig),
+ : LibraryFeature(pConfig, pLibrary, pTrackCollection, parent),
m_browseModel(this, pTrackCollection, pRecordingManager),
m_proxyModel(&m_browseModel),
m_pTrackCollection(pTrackCollection),
@@ -55,6 +58,7 @@ BrowseFeature::BrowseFeature(QObject* parent,
// The invisible root item of the child model
TreeItem* rootItem = new TreeItem();
+ rootItem->setLibraryFeature(this);
m_pQuickLinkItem = new TreeItem(tr("Quick Links"), QUICK_LINK_NODE, this, rootItem);
rootItem->appendChild(m_pQuickLinkItem);
@@ -207,17 +211,35 @@ TreeItemModel* BrowseFeature::getChildModel() {
return &m_childModel;
}
-void BrowseFeature::bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* keyboard) {
- Q_UNUSED(keyboard);
- WLibraryTextBrowser* edit = new WLibraryTextBrowser(libraryWidget);
- edit->setHtml(getRootViewHtml());
- libraryWidget->registerView("BROWSEHOME", edit);
+QWidget* BrowseFeature::createPaneWidget(KeyboardEventFilter* pKeyboard,
+ int paneId) {
+ WLibraryStack* pStack = new WLibraryStack(nullptr);
+ m_panes[paneId] = pStack;
+
+ WLibraryTextBrowser* pEdit = new WLibraryTextBrowser(nullptr);
+ pEdit->setHtml(getRootViewHtml());
+ pEdit->installEventFilter(pKeyboard);
+ m_idBrowse[paneId] = pStack->addWidget(pEdit);
+
+ QWidget* pTable = LibraryFeature::createPaneWidget(pKeyboard, paneId);
+ pTable->setParent(pStack);
+ m_idTable[paneId] = pStack->addWidget(pTable);
+
+ return pStack;
}
void BrowseFeature::activate() {
- emit(switchToView("BROWSEHOME"));
- emit(restoreSearch(QString()));
+ auto it = m_panes.find(m_featureFocus);
+ auto itId = m_idBrowse.find(m_featureFocus);
+ if (it == m_panes.end() || it->isNull() || itId == m_idBrowse.end()) {
+ return;
+ }
+
+ (*it)->setCurrentIndex(*itId);
+ switchToFeature();
+ m_pLibrary->showBreadCrumb(m_childModel.getItem(QModelIndex()));
+ m_pLibrary->restoreSearch(QString());
+
emit(enableCoverArtDisplay(false));
}
@@ -246,8 +268,20 @@ void BrowseFeature::activateChild(const QModelIndex& index) {
}
m_browseModel.setPath(dir);
}
- emit(showTrackModel(&m_proxyModel));
- emit(enableCoverArtDisplay(false));
+
+ auto itId = m_idTable.find(m_featureFocus);
+ auto it = m_panes.find(m_featureFocus);
+
+ if (it == m_panes.end() || it->isNull() || itId == m_idTable.end()) {
+ qDebug() << "BrowseFeature::activateChild item not found";
+ return;
+ }
+
+ (*it)->setCurrentIndex(*itId);
+ showTrackModel(&m_proxyModel);
+ m_pLibrary->showBreadCrumb(item);
+
+ emit(enableCoverArtDisplay(true));
}
void BrowseFeature::onRightClickChild(const QPoint& globalPos, QModelIndex index) {
diff --git a/src/library/browse/browsefeature.h b/src/library/browse/browsefeature.h
index 94188ee6b0d0..46fdce22f4d8 100644
--- a/src/library/browse/browsefeature.h
+++ b/src/library/browse/browsefeature.h
@@ -8,6 +8,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -23,12 +24,14 @@
#define DEVICE_NODE "::mixxx_device_node::"
class TrackCollection;
+class WLibraryStack;
class BrowseFeature : public LibraryFeature {
Q_OBJECT
public:
- BrowseFeature(QObject* parent,
- UserSettingsPointer pConfig,
+ BrowseFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
TrackCollection* pTrackCollection,
RecordingManager* pRec);
virtual ~BrowseFeature();
@@ -36,8 +39,7 @@ class BrowseFeature : public LibraryFeature {
QVariant title();
QIcon getIcon();
- void bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* keyboard);
+ QWidget* createPaneWidget(KeyboardEventFilter*pKeyboard, int paneId) override;
TreeItemModel* getChildModel();
@@ -64,7 +66,6 @@ class BrowseFeature : public LibraryFeature {
void saveQuickLinks();
void loadQuickLinks();
- UserSettingsPointer m_pConfig;
BrowseTableModel m_browseModel;
ProxyTrackModel m_proxyModel;
TrackCollection* m_pTrackCollection;
@@ -75,6 +76,10 @@ class BrowseFeature : public LibraryFeature {
TreeItem* m_pLastRightClickedItem;
TreeItem* m_pQuickLinkItem;
QStringList m_quickLinkList;
+
+ QHash > m_panes;
+ QHash m_idBrowse;
+ QHash m_idTable;
};
#endif // BROWSEFEATURE_H
diff --git a/src/library/browse/foldertreemodel.cpp b/src/library/browse/foldertreemodel.cpp
index 62b28afc4124..6776e394ecfc 100644
--- a/src/library/browse/foldertreemodel.cpp
+++ b/src/library/browse/foldertreemodel.cpp
@@ -33,11 +33,19 @@ FolderTreeModel::~FolderTreeModel() {
* is only called if necessary.
*/
bool FolderTreeModel::hasChildren(const QModelIndex& parent) const {
+ if (!parent.isValid()) {
+ return true;
+ }
+
TreeItem *item = static_cast(parent.internalPointer());
/* Usually the child count is 0 becuase we do lazy initalization
* However, for, buid-in items such as 'Quick Links' there exist
* child items at init time
*/
+ if (item == nullptr) {
+ return false;
+ }
+
if(item->dataPath().toString() == QUICK_LINK_NODE)
return true;
//Can only happen on Windows
diff --git a/src/library/cratefeature.cpp b/src/library/cratefeature.cpp
index 0d53d49e321e..f56d5a1452a9 100644
--- a/src/library/cratefeature.cpp
+++ b/src/library/cratefeature.cpp
@@ -7,31 +7,34 @@
#include
#include
+
+#include "controllers/keyboard/keyboardeventfilter.h"
#include "library/cratefeature.h"
+#include "library/cratetablemodel.h"
#include "library/export/trackexportwizard.h"
+#include "library/parsercsv.h"
#include "library/parser.h"
#include "library/parserm3u.h"
#include "library/parserpls.h"
-#include "library/parsercsv.h"
-
-#include "library/cratetablemodel.h"
-#include "library/trackcollection.h"
#include "library/queryutil.h"
-#include "widget/wlibrarytextbrowser.h"
-#include "widget/wlibrary.h"
-#include "controllers/keyboard/keyboardeventfilter.h"
-#include "treeitem.h"
+#include "library/trackcollection.h"
#include "sources/soundsourceproxy.h"
+#include "treeitem.h"
#include "util/dnd.h"
#include "util/duration.h"
+#include "util/time.h"
+#include "widget/wlibrary.h"
+#include "widget/wlibrarytextbrowser.h"
+#include "widget/wlibrarystack.h"
-CrateFeature::CrateFeature(Library* pLibrary,
- TrackCollection* pTrackCollection,
- UserSettingsPointer pConfig)
- : LibraryFeature(pConfig),
+CrateFeature::CrateFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection)
+ : LibraryFeature(pConfig, pLibrary, pTrackCollection, parent),
m_pTrackCollection(pTrackCollection),
m_crateDao(pTrackCollection->getCrateDAO()),
- m_crateTableModel(this, pTrackCollection) {
+ m_pCrateTableModel(nullptr) {
m_pCreateCrateAction = new QAction(tr("Create New Crate"),this);
connect(m_pCreateCrateAction, SIGNAL(triggered()),
@@ -94,14 +97,13 @@ CrateFeature::CrateFeature(Library* pLibrary,
this, SLOT(slotCrateTableChanged(int)));
// construct child model
- TreeItem *rootItem = new TreeItem();
- m_childModel.setRootItem(rootItem);
+ TreeItem *pRootItem = new TreeItem();
+ pRootItem->setLibraryFeature(this);
+ m_childModel.setRootItem(pRootItem);
constructChildModel(-1);
connect(pLibrary, SIGNAL(trackSelected(TrackPointer)),
this, SLOT(slotTrackSelected(TrackPointer)));
- connect(pLibrary, SIGNAL(switchToView(const QString&)),
- this, SLOT(slotResetSelectedTrack()));
}
CrateFeature::~CrateFeature() {
@@ -127,7 +129,7 @@ QIcon CrateFeature::getIcon() {
int CrateFeature::crateIdFromIndex(QModelIndex index) {
TreeItem* item = static_cast(index.internalPointer());
- if (item == NULL) {
+ if (item == nullptr) {
return -1;
}
@@ -140,6 +142,12 @@ int CrateFeature::crateIdFromIndex(QModelIndex index) {
return playlistId;
}
+bool CrateFeature::dragMoveAccept(QUrl url) {
+ return SoundSourceProxy::isUrlSupported(url) ||
+ Parser::isPlaylistFilenameSupported(url.toLocalFile());
+}
+
+
bool CrateFeature::dropAcceptChild(const QModelIndex& index, QList urls,
QObject* pSource) {
int crateId = crateIdFromIndex(index);
@@ -178,15 +186,24 @@ bool CrateFeature::dragMoveAcceptChild(const QModelIndex& index, QUrl url) {
return !locked && formatSupported;
}
-void CrateFeature::bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* keyboard) {
- Q_UNUSED(keyboard);
- WLibraryTextBrowser* edit = new WLibraryTextBrowser(libraryWidget);
- edit->setHtml(getRootViewHtml());
- edit->setOpenLinks(false);
- connect(edit, SIGNAL(anchorClicked(const QUrl)),
+QWidget* CrateFeature::createPaneWidget(KeyboardEventFilter *pKeyboard,
+ int paneId) {
+ WLibraryStack* pContainer = new WLibraryStack(nullptr);
+ m_panes[paneId] = pContainer;
+
+ WLibraryTextBrowser* pEdit = new WLibraryTextBrowser(pContainer);
+ pEdit->setHtml(getRootViewHtml());
+ pEdit->setOpenLinks(false);
+ pEdit->installEventFilter(pKeyboard);
+ connect(pEdit, SIGNAL(anchorClicked(const QUrl)),
this, SLOT(htmlLinkClicked(const QUrl)));
- libraryWidget->registerView("CRATEHOME", edit);
+
+ m_idBrowse[paneId] = pContainer->addWidget(pEdit);
+
+ QWidget* pTable = LibraryFeature::createPaneWidget(pKeyboard, paneId);
+ m_idTable[paneId] = pContainer->addWidget(pTable);
+
+ return pContainer;
}
TreeItemModel* CrateFeature::getChildModel() {
@@ -194,29 +211,59 @@ TreeItemModel* CrateFeature::getChildModel() {
}
void CrateFeature::activate() {
- emit(switchToView("CRATEHOME"));
- emit(restoreSearch(QString())); //disable search on crate home
+ auto it = m_panes.find(m_featureFocus);
+ auto itId = m_idBrowse.find(m_featureFocus);
+ if (it == m_panes.end() || it->isNull() || itId == m_idBrowse.end()) {
+ return;
+ }
+
+ (*it)->setCurrentIndex(*itId);
+
+ m_pLibrary->switchToFeature(this);
+ m_pLibrary->showBreadCrumb(m_childModel.getItem(QModelIndex()));
+ m_pLibrary->restoreSearch(QString()); //disable search on crate home
+ m_featureFocus = -1;
emit(enableCoverArtDisplay(true));
}
void CrateFeature::activateChild(const QModelIndex& index) {
- if (!index.isValid())
+ if (!index.isValid()) {
return;
+ }
int crateId = crateIdFromIndex(index);
if (crateId == -1) {
return;
}
- m_crateTableModel.setTableModel(crateId);
- emit(showTrackModel(&m_crateTableModel));
+
+ m_pCrateTableModel = getTableModel(m_focusedPane);
+ auto it = m_panes.find(m_focusedPane);
+ auto itId = m_idTable.find(m_focusedPane);
+ if (it == m_panes.end() || it->isNull() || itId == m_idTable.end()) {
+ return;
+ }
+
+ (*it)->setCurrentIndex(*itId);
+ m_pCrateTableModel->setTableModel(crateId);
+
+ // Set the feature Focus for a moment to allow the LibraryFeature class
+ // to find the focused WTrackTable
+ m_featureFocus = m_focusedPane;
+ showTrackModel(m_pCrateTableModel);
+ m_featureFocus = -1;
+
+ m_pLibrary->restoreSearch("");
+ m_pLibrary->showBreadCrumb(static_cast(index.internalPointer()));
emit(enableCoverArtDisplay(true));
}
void CrateFeature::activateCrate(int crateId) {
//qDebug() << "CrateFeature::activateCrate()" << crateId;
+ m_pCrateTableModel = getTableModel(m_focusedPane);
+
QModelIndex index = indexFromCrateId(crateId);
if (crateId != -1 && index.isValid()) {
- m_crateTableModel.setTableModel(crateId);
- emit(showTrackModel(&m_crateTableModel));
+ m_pCrateTableModel->setTableModel(crateId);
+ showTrackModel(m_pCrateTableModel);
emit(enableCoverArtDisplay(true));
// Update selection
emit(featureSelect(this, m_lastRightClickedIndex));
@@ -227,7 +274,7 @@ void CrateFeature::activateCrate(int crateId) {
void CrateFeature::onRightClick(const QPoint& globalPos) {
m_lastRightClickedIndex = QModelIndex();
- QMenu menu(NULL);
+ QMenu menu(nullptr);
menu.addAction(m_pCreateCrateAction);
menu.addSeparator();
menu.addAction(m_pCreateImportPlaylistAction);
@@ -238,9 +285,6 @@ void CrateFeature::onRightClickChild(const QPoint& globalPos, QModelIndex index)
//Save the model index so we can get it in the action slots...
m_lastRightClickedIndex = index;
int crateId = crateIdFromIndex(index);
- if (crateId == -1) {
- return;
- }
bool locked = m_crateDao.isCrateLocked(crateId);
@@ -610,7 +654,7 @@ void CrateFeature::slotImportPlaylistFile(const QString &playlist_file) {
//qDebug() << "Size of Imported Playlist: " << entries.size();
//Iterate over the List that holds URLs of playlist entires
- m_crateTableModel.addTracks(QModelIndex(), entries);
+ m_pCrateTableModel->addTracks(QModelIndex(), entries);
//delete the parser object
delete playlist_parser;
@@ -658,7 +702,7 @@ void CrateFeature::slotCreateImportCrate() {
lastCrateId = m_crateDao.createCrate(name);
if (lastCrateId != -1) {
- m_crateTableModel.setTableModel(lastCrateId);
+ m_pCrateTableModel->setTableModel(lastCrateId);
}
else {
QMessageBox::warning(NULL,
@@ -684,7 +728,7 @@ void CrateFeature::slotAnalyzeCrate() {
}
void CrateFeature::slotExportPlaylist() {
- int crateId = m_crateTableModel.getCrate();
+ int crateId = m_pCrateTableModel->getCrate();
QString crateName = m_crateDao.crateName(crateId);
qDebug() << "Export crate" << crateId << crateName;
@@ -722,7 +766,7 @@ void CrateFeature::slotExportPlaylist() {
// Create a new table model since the main one might have an active search.
QScopedPointer pCrateTableModel(
new CrateTableModel(this, m_pTrackCollection));
- pCrateTableModel->setTableModel(m_crateTableModel.getCrate());
+ pCrateTableModel->setTableModel(m_pCrateTableModel->getCrate());
pCrateTableModel->select();
if (file_location.endsWith(".csv", Qt::CaseInsensitive)) {
@@ -734,8 +778,8 @@ void CrateFeature::slotExportPlaylist() {
QList playlist_items;
int rows = pCrateTableModel->rowCount();
for (int i = 0; i < rows; ++i) {
- QModelIndex index = m_crateTableModel.index(i, 0);
- playlist_items << m_crateTableModel.getTrackLocation(index);
+ QModelIndex index = m_pCrateTableModel->index(i, 0);
+ playlist_items << m_pCrateTableModel->getTrackLocation(index);
}
if (file_location.endsWith(".pls", Qt::CaseInsensitive)) {
@@ -759,14 +803,14 @@ void CrateFeature::slotExportTrackFiles() {
// Create a new table model since the main one might have an active search.
QScopedPointer pCrateTableModel(
new CrateTableModel(this, m_pTrackCollection));
- pCrateTableModel->setTableModel(m_crateTableModel.getCrate());
+ pCrateTableModel->setTableModel(m_pCrateTableModel->getCrate());
pCrateTableModel->select();
int rows = pCrateTableModel->rowCount();
QList trackpointers;
for (int i = 0; i < rows; ++i) {
- QModelIndex index = m_crateTableModel.index(i, 0);
- trackpointers.push_back(m_crateTableModel.getTrack(index));
+ QModelIndex index = m_pCrateTableModel->index(i, 0);
+ trackpointers.push_back(m_pCrateTableModel->getTrack(index));
}
TrackExportWizard track_export(nullptr, m_pConfig, trackpointers);
@@ -863,3 +907,12 @@ QModelIndex CrateFeature::indexFromCrateId(int crateId) {
}
return QModelIndex();
}
+
+QPointer CrateFeature::getTableModel(int paneId) {
+ auto it = m_crateTableModel.find(paneId);
+ if (it == m_crateTableModel.end() || it->isNull()) {
+ it = m_crateTableModel.insert(paneId,
+ new CrateTableModel(this, m_pTrackCollection));
+ }
+ return *it;
+}
diff --git a/src/library/cratefeature.h b/src/library/cratefeature.h
index 495b74ad7c33..fd5870f3ddc1 100644
--- a/src/library/cratefeature.h
+++ b/src/library/cratefeature.h
@@ -24,21 +24,24 @@ class TrackCollection;
class CrateFeature : public LibraryFeature {
Q_OBJECT
public:
- CrateFeature(Library* pLibrary,
- TrackCollection* pTrackCollection,
- UserSettingsPointer pConfig);
+ CrateFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection);
virtual ~CrateFeature();
QVariant title();
QIcon getIcon();
+
+ void onSearch(QString&) {}
+ bool dragMoveAccept(QUrl url);
bool dropAcceptChild(const QModelIndex& index, QList urls,
QObject* pSource);
bool dragMoveAcceptChild(const QModelIndex& index, QUrl url);
- void bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* keyboard);
-
+ QWidget* createPaneWidget(KeyboardEventFilter* pKeyboard, int paneId) override;
+
TreeItemModel* getChildModel();
signals:
@@ -83,6 +86,8 @@ class CrateFeature : public LibraryFeature {
// Get the QModelIndex of a crate based on its id. Returns QModelIndex()
// on failure.
QModelIndex indexFromCrateId(int crateId);
+
+ QPointer getTableModel(int paneId);
TrackCollection* m_pTrackCollection;
CrateDAO& m_crateDao;
@@ -98,11 +103,15 @@ class CrateFeature : public LibraryFeature {
QAction *m_pExportTrackFilesAction;
QAction *m_pAnalyzeCrateAction;
QList > m_crateList;
- CrateTableModel m_crateTableModel;
+ QHash > m_crateTableModel;
+ CrateTableModel* m_pCrateTableModel;
QModelIndex m_lastRightClickedIndex;
TreeItemModel m_childModel;
TrackPointer m_pSelectedTrack;
QSet m_cratesSelectedTrackIsIn;
+ QHash > m_panes;
+ QHash m_idBrowse;
+ QHash m_idTable;
};
#endif /* CRATEFEATURE_H */
diff --git a/src/library/dlganalysis.cpp b/src/library/dlganalysis.cpp
index 6d8ec9f38012..e552827aaad0 100644
--- a/src/library/dlganalysis.cpp
+++ b/src/library/dlganalysis.cpp
@@ -1,66 +1,32 @@
#include
-#include "widget/wwidget.h"
-#include "widget/wskincolor.h"
-#include "widget/wanalysislibrarytableview.h"
-#include "library/trackcollection.h"
+#include "library/analysisfeature.h"
#include "library/dlganalysis.h"
+#include "library/trackcollection.h"
#include "util/assert.h"
+#include "widget/wanalysislibrarytableview.h"
+#include "widget/wskincolor.h"
+#include "widget/wwidget.h"
-DlgAnalysis::DlgAnalysis(QWidget* parent,
- UserSettingsPointer pConfig,
- TrackCollection* pTrackCollection)
- : QWidget(parent),
- m_pConfig(pConfig),
+DlgAnalysis::DlgAnalysis(QWidget* parent, AnalysisFeature *pAnalysis,
+ TrackCollection* pTrackCollection)
+ : QFrame(parent),
m_pTrackCollection(pTrackCollection),
m_bAnalysisActive(false),
+ m_pAnalysis(pAnalysis),
m_tracksInQueue(0),
m_currentTrack(0) {
setupUi(this);
m_songsButtonGroup.addButton(radioButtonRecentlyAdded);
m_songsButtonGroup.addButton(radioButtonAllSongs);
- m_pAnalysisLibraryTableView = new WAnalysisLibraryTableView(this, pConfig, pTrackCollection);
- connect(m_pAnalysisLibraryTableView, SIGNAL(loadTrack(TrackPointer)),
- this, SIGNAL(loadTrack(TrackPointer)));
- connect(m_pAnalysisLibraryTableView, SIGNAL(loadTrackToPlayer(TrackPointer, QString)),
- this, SIGNAL(loadTrackToPlayer(TrackPointer, QString)));
-
- connect(m_pAnalysisLibraryTableView, SIGNAL(trackSelected(TrackPointer)),
- this, SIGNAL(trackSelected(TrackPointer)));
-
- QBoxLayout* box = dynamic_cast(layout());
- DEBUG_ASSERT_AND_HANDLE(box) { // Assumes the form layout is a QVBox/QHBoxLayout!
- } else {
- box->removeWidget(m_pTrackTablePlaceholder);
- m_pTrackTablePlaceholder->hide();
- box->insertWidget(1, m_pAnalysisLibraryTableView);
- }
-
- m_pAnalysisLibraryTableModel = new AnalysisLibraryTableModel(this, pTrackCollection);
- m_pAnalysisLibraryTableView->loadTrackModel(m_pAnalysisLibraryTableModel);
-
- connect(radioButtonRecentlyAdded, SIGNAL(clicked()),
- this, SLOT(showRecentSongs()));
- connect(radioButtonAllSongs, SIGNAL(clicked()),
- this, SLOT(showAllSongs()));
-
- // TODO(rryan): This triggers a library search before the UI has even
- // started up. Accounts for 0.2% of skin creation time. Get rid of this!
- radioButtonRecentlyAdded->click();
-
labelProgress->setText("");
pushButtonAnalyze->setEnabled(false);
connect(pushButtonAnalyze, SIGNAL(clicked()),
this, SLOT(analyze()));
connect(pushButtonSelectAll, SIGNAL(clicked()),
- this, SLOT(selectAll()));
-
- connect(m_pAnalysisLibraryTableView->selectionModel(),
- SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection&)),
- this,
- SLOT(tableSelectionChanged(const QItemSelection &, const QItemSelection&)));
+ m_pAnalysis, SLOT(selectAll()));
}
DlgAnalysis::~DlgAnalysis() {
@@ -70,54 +36,19 @@ void DlgAnalysis::onShow() {
// Refresh table
// There might be new tracks dropped to other views
m_pAnalysisLibraryTableModel->select();
-}
-
-void DlgAnalysis::onSearch(const QString& text) {
- m_pAnalysisLibraryTableModel->search(text);
-}
-
-void DlgAnalysis::loadSelectedTrack() {
- m_pAnalysisLibraryTableView->loadSelectedTrack();
-}
-
-void DlgAnalysis::loadSelectedTrackToGroup(QString group, bool play) {
- m_pAnalysisLibraryTableView->loadSelectedTrackToGroup(group, play);
-}
-
-void DlgAnalysis::slotSendToAutoDJ() {
- // append to auto DJ
- m_pAnalysisLibraryTableView->slotSendToAutoDJ();
-}
-
-void DlgAnalysis::slotSendToAutoDJTop() {
- m_pAnalysisLibraryTableView->slotSendToAutoDJTop();
-}
-
-void DlgAnalysis::moveSelection(int delta) {
- m_pAnalysisLibraryTableView->moveSelection(delta);
-}
-
-void DlgAnalysis::tableSelectionChanged(const QItemSelection& selected,
- const QItemSelection& deselected) {
- Q_UNUSED(selected);
- Q_UNUSED(deselected);
- bool tracksSelected = m_pAnalysisLibraryTableView->selectionModel()->hasSelection();
- pushButtonAnalyze->setEnabled(tracksSelected || m_bAnalysisActive);
-}
-
-void DlgAnalysis::selectAll() {
- m_pAnalysisLibraryTableView->selectAll();
+
+ // TODO(rryan): This triggers a library search before the UI has even
+ // started up. Accounts for 0.2% of skin creation time. Get rid of this!
+ radioButtonRecentlyAdded->click();
}
void DlgAnalysis::analyze() {
//qDebug() << this << "analyze()";
if (m_bAnalysisActive) {
- emit(stopAnalysis());
+ m_pAnalysis->stopAnalysis();
} else {
QList trackIds;
-
- QModelIndexList selectedIndexes = m_pAnalysisLibraryTableView->selectionModel()->selectedRows();
- foreach(QModelIndex selectedIndex, selectedIndexes) {
+ for (QModelIndex selectedIndex : m_selectedIndexes) {
TrackId trackId(selectedIndex.sibling(
selectedIndex.row(),
m_pAnalysisLibraryTableModel->fieldIndex(LIBRARYTABLE_ID)).data());
@@ -126,12 +57,12 @@ void DlgAnalysis::analyze() {
}
}
m_currentTrack = 1;
- emit(analyzeTracks(trackIds));
+ m_pAnalysis->analyzeTracks(trackIds);
}
}
void DlgAnalysis::analysisActive(bool bActive) {
- qDebug() << this << "analysisActive" << bActive;
+ //qDebug() << this << "analysisActive" << bActive;
m_bAnalysisActive = bActive;
if (bActive) {
pushButtonAnalyze->setEnabled(true);
@@ -146,7 +77,7 @@ void DlgAnalysis::analysisActive(bool bActive) {
// slot
void DlgAnalysis::trackAnalysisFinished(int size) {
- qDebug() << "Analysis finished" << size << "tracks left";
+ //qDebug() << "Analysis finished" << size << "tracks left";
if (size > 0) {
m_currentTrack = m_tracksInQueue - size + 1;
}
@@ -167,19 +98,22 @@ int DlgAnalysis::getNumTracks() {
return m_tracksInQueue;
}
-void DlgAnalysis::trackAnalysisStarted(int size) {
- m_tracksInQueue = size;
-}
-
-void DlgAnalysis::showRecentSongs() {
- m_pAnalysisLibraryTableModel->showRecentSongs();
+void DlgAnalysis::setSelectedIndexes(const QModelIndexList& selectedIndexes) {
+ //qDebug() << "DlgAnalysis::setSelectedIndexes" << selectedIndexes;
+ m_selectedIndexes = selectedIndexes;
+ pushButtonAnalyze->setEnabled(m_selectedIndexes.size() > 0 ||
+ m_bAnalysisActive);
}
-void DlgAnalysis::showAllSongs() {
- m_pAnalysisLibraryTableModel->showAllSongs();
+void DlgAnalysis::setTableModel(AnalysisLibraryTableModel *pTableModel) {
+ m_pAnalysisLibraryTableModel = pTableModel;
+
+ connect(radioButtonRecentlyAdded, SIGNAL(clicked()),
+ m_pAnalysisLibraryTableModel, SLOT(showRecentSongs()));
+ connect(radioButtonAllSongs, SIGNAL(clicked()),
+ m_pAnalysisLibraryTableModel, SLOT(showAllSongs()));
}
-void DlgAnalysis::installEventFilter(QObject* pFilter) {
- QWidget::installEventFilter(pFilter);
- m_pAnalysisLibraryTableView->installEventFilter(pFilter);
+void DlgAnalysis::trackAnalysisStarted(int size) {
+ m_tracksInQueue = size;
}
diff --git a/src/library/dlganalysis.h b/src/library/dlganalysis.h
index 84520b38cf66..9a83b0491ef5 100644
--- a/src/library/dlganalysis.h
+++ b/src/library/dlganalysis.h
@@ -2,6 +2,7 @@
#define DLGANALYSIS_H
#include
+#include
#include "preferences/usersettings.h"
#include "library/analysislibrarytablemodel.h"
@@ -11,57 +12,48 @@
class AnalysisLibraryTableModel;
class WAnalysisLibraryTableView;
+class AnalysisFeature;
-class DlgAnalysis : public QWidget, public Ui::DlgAnalysis, public virtual LibraryView {
+class DlgAnalysis : public QFrame, public Ui::DlgAnalysis {
+
Q_OBJECT
+
public:
+
DlgAnalysis(QWidget *parent,
- UserSettingsPointer pConfig,
- TrackCollection* pTrackCollection);
+ AnalysisFeature* pAnalysis,
+ TrackCollection* pTrackCollection);
virtual ~DlgAnalysis();
- virtual void onSearch(const QString& text);
virtual void onShow();
- virtual void loadSelectedTrack();
- virtual void loadSelectedTrackToGroup(QString group, bool play);
- virtual void slotSendToAutoDJ();
- virtual void slotSendToAutoDJTop();
- virtual void moveSelection(int delta);
inline const QString currentSearch() {
return m_pAnalysisLibraryTableModel->currentSearch();
}
int getNumTracks();
+
+ // The selected indexes are always from the focused pane
+ void setSelectedIndexes(const QModelIndexList& selectedIndexes);
+ void setTableModel(AnalysisLibraryTableModel* pTableModel);
public slots:
- void tableSelectionChanged(const QItemSelection& selected,
- const QItemSelection& deselected);
- void selectAll();
+
void analyze();
void trackAnalysisFinished(int size);
void trackAnalysisProgress(int progress);
void trackAnalysisStarted(int size);
- void showRecentSongs();
- void showAllSongs();
- void installEventFilter(QObject* pFilter);
void analysisActive(bool bActive);
-
- signals:
- void loadTrack(TrackPointer pTrack);
- void loadTrackToPlayer(TrackPointer pTrack, QString player);
- void analyzeTracks(QList trackIds);
- void stopAnalysis();
- void trackSelected(TrackPointer pTrack);
-
+
private:
//Note m_pTrackTablePlaceholder is defined in the .ui file
- UserSettingsPointer m_pConfig;
TrackCollection* m_pTrackCollection;
bool m_bAnalysisActive;
QButtonGroup m_songsButtonGroup;
- WAnalysisLibraryTableView* m_pAnalysisLibraryTableView;
AnalysisLibraryTableModel* m_pAnalysisLibraryTableModel;
+ AnalysisFeature* m_pAnalysis;
int m_tracksInQueue;
int m_currentTrack;
+
+ QModelIndexList m_selectedIndexes;
};
#endif //DLGTRIAGE_H
diff --git a/src/library/dlganalysis.ui b/src/library/dlganalysis.ui
index de46af0a67d5..48e7249aba27 100644
--- a/src/library/dlganalysis.ui
+++ b/src/library/dlganalysis.ui
@@ -14,107 +14,66 @@
Analyze
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
- 0
+
+
+ Shows tracks added to the library within the last 7 days.
-
- 0
+
+ New
-
- 0
+
+
+ -
+
+
+ Shows all tracks in the library.
-
- 0
+
+ All
-
- 0
+
+
+ -
+
+
+ Progress
-
-
-
-
- Shows tracks added to the library within the last 7 days.
-
-
- New
-
-
-
- -
-
-
- Shows all tracks in the library.
-
-
- All
-
-
-
- -
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Progress
-
-
-
- -
-
-
- Selects all tracks in the table below.
-
-
- Select All
-
-
-
- -
-
-
- Runs beatgrid, key, and ReplayGain detection on the selected tracks. Does not generate waveforms for the selected tracks to save disk space.
-
-
- Analyze
-
-
-
-
+
-
-
-
- true
+
+
+ Selects all tracks in the table below.
+
+
+ Select All
+ -
+
+
+ Runs beatgrid, key, and ReplayGain detection on the selected tracks. Does not generate waveforms for the selected tracks to save disk space.
+
+
+ Analyze
+
+
+
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 235
+
+
+
+
diff --git a/src/library/dlghidden.cpp b/src/library/dlghidden.cpp
index 9cddafb9912d..7adcc47323d0 100644
--- a/src/library/dlghidden.cpp
+++ b/src/library/dlghidden.cpp
@@ -5,55 +5,20 @@
#include "widget/wtracktableview.h"
#include "util/assert.h"
-DlgHidden::DlgHidden(QWidget* parent, UserSettingsPointer pConfig,
- Library* pLibrary, TrackCollection* pTrackCollection,
- KeyboardEventFilter* pKeyboard)
- : QWidget(parent),
- Ui::DlgHidden(),
- m_pTrackTableView(
- new WTrackTableView(this, pConfig, pTrackCollection, false)) {
+DlgHidden::DlgHidden(QWidget* parent)
+ : QFrame(parent),
+ Ui::DlgHidden() {
setupUi(this);
- m_pTrackTableView->installEventFilter(pKeyboard);
-
- // Install our own trackTable
- QBoxLayout* box = dynamic_cast(layout());
- DEBUG_ASSERT_AND_HANDLE(box) { //Assumes the form layout is a QVBox/QHBoxLayout!
- } else {
- box->removeWidget(m_pTrackTablePlaceholder);
- m_pTrackTablePlaceholder->hide();
- box->insertWidget(1, m_pTrackTableView);
- }
-
- m_pHiddenTableModel = new HiddenTableModel(this, pTrackCollection);
- m_pTrackTableView->loadTrackModel(m_pHiddenTableModel);
-
- connect(btnUnhide, SIGNAL(clicked()),
- m_pTrackTableView, SLOT(slotUnhide()));
- connect(btnUnhide, SIGNAL(clicked()),
- this, SLOT(clicked()));
- connect(btnPurge, SIGNAL(clicked()),
- m_pTrackTableView, SLOT(slotPurge()));
- connect(btnPurge, SIGNAL(clicked()),
- this, SLOT(clicked()));
- connect(btnSelect, SIGNAL(clicked()),
- this, SLOT(selectAll()));
- connect(m_pTrackTableView->selectionModel(),
- SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
- this,
- SLOT(selectionChanged(const QItemSelection&, const QItemSelection&)));
-
- connect(m_pTrackTableView, SIGNAL(trackSelected(TrackPointer)),
- this, SIGNAL(trackSelected(TrackPointer)));
- connect(pLibrary, SIGNAL(setTrackTableFont(QFont)),
- m_pTrackTableView, SLOT(setTrackTableFont(QFont)));
- connect(pLibrary, SIGNAL(setTrackTableRowHeight(int)),
- m_pTrackTableView, SLOT(setTrackTableRowHeight(int)));
+
+ connect(btnPurge, SIGNAL(clicked()), this, SLOT(onShow()));
+ connect(btnSelect, SIGNAL(clicked()), this, SIGNAL(selectAll()));
+ connect(btnPurge, SIGNAL(clicked()), this, SIGNAL(purge()));
+ connect(btnUnhide, SIGNAL(clicked()), this, SIGNAL(unhide()));
}
DlgHidden::~DlgHidden() {
// Delete m_pTrackTableView before the table model. This is because the
// table view saves the header state using the model.
- delete m_pTrackTableView;
delete m_pHiddenTableModel;
}
@@ -63,34 +28,15 @@ void DlgHidden::onShow() {
activateButtons(false);
}
-void DlgHidden::onSearch(const QString& text) {
- m_pHiddenTableModel->search(text);
-}
-
-void DlgHidden::clicked() {
- // all marked tracks are gone now anyway
- onShow();
+void DlgHidden::setSelectedIndexes(const QModelIndexList& selectedIndexes) {
+ activateButtons(!selectedIndexes.empty());
}
-void DlgHidden::selectAll() {
- m_pTrackTableView->selectAll();
+void DlgHidden::setTableModel(HiddenTableModel* pTableModel) {
+ m_pHiddenTableModel = pTableModel;
}
void DlgHidden::activateButtons(bool enable) {
btnPurge->setEnabled(enable);
btnUnhide->setEnabled(enable);
}
-
-void DlgHidden::selectionChanged(const QItemSelection &selected,
- const QItemSelection &deselected) {
- Q_UNUSED(deselected);
- activateButtons(!selected.indexes().isEmpty());
-}
-
-void DlgHidden::setTrackTableFont(const QFont& font) {
- m_pTrackTableView->setTrackTableFont(font);
-}
-
-void DlgHidden::setTrackTableRowHeight(int rowHeight) {
- m_pTrackTableView->setTrackTableRowHeight(rowHeight);
-}
diff --git a/src/library/dlghidden.h b/src/library/dlghidden.h
index 6b78d85f1fca..a084ea450e37 100644
--- a/src/library/dlghidden.h
+++ b/src/library/dlghidden.h
@@ -12,30 +12,27 @@ class WTrackTableView;
class HiddenTableModel;
class QItemSelection;
-class DlgHidden : public QWidget, public Ui::DlgHidden, public LibraryView {
+class DlgHidden : public QFrame, public Ui::DlgHidden {
Q_OBJECT
public:
- DlgHidden(QWidget* parent, UserSettingsPointer pConfig,
- Library* pLibrary, TrackCollection* pTrackCollection,
- KeyboardEventFilter* pKeyboard);
+ DlgHidden(QWidget* parent);
virtual ~DlgHidden();
- void onShow();
- void onSearch(const QString& text);
+ // The indexes are always from the focused pane
+ void setSelectedIndexes(const QModelIndexList& selectedIndexes);
+ void setTableModel(HiddenTableModel* pTableModel);
public slots:
- void clicked();
- void selectAll();
- void selectionChanged(const QItemSelection&, const QItemSelection&);
- void setTrackTableFont(const QFont& font);
- void setTrackTableRowHeight(int rowHeight);
+ void onShow();
signals:
+ void selectAll();
+ void unhide();
+ void purge();
void trackSelected(TrackPointer pTrack);
private:
void activateButtons(bool enable);
- WTrackTableView* m_pTrackTableView;
HiddenTableModel* m_pHiddenTableModel;
};
diff --git a/src/library/dlghidden.ui b/src/library/dlghidden.ui
index d80de64e4210..2b96be8becce 100644
--- a/src/library/dlghidden.ui
+++ b/src/library/dlghidden.ui
@@ -14,103 +14,60 @@
Hidden Tracks
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
- 0
+
+
+ Selects all tracks in the table below.
-
- 0
+
+ Select All
-
- 0
+
+
+ -
+
+
+ Purge selected tracks from the library.
-
- 0
+
+ Purge
-
- 0
+
+ false
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Selects all tracks in the table below.
-
-
- Select All
-
-
-
- -
-
-
- Purge selected tracks from the library.
-
-
- Purge
-
-
- false
-
-
-
- -
-
-
- Unhide selected tracks from the library.
-
-
- Unhide
-
-
- Ctrl+S
-
-
- false
-
-
-
-
+
-
-
-
- true
+
+
+ Unhide selected tracks from the library.
+
+
+ Unhide
+
+
+ Ctrl+S
+
+
+ false
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 285
+
+
+
+
-
-
-
+
diff --git a/src/library/dlgmissing.cpp b/src/library/dlgmissing.cpp
index 3f5918bfb3ed..4eb22b2bcacb 100644
--- a/src/library/dlgmissing.cpp
+++ b/src/library/dlgmissing.cpp
@@ -4,51 +4,19 @@
#include "widget/wtracktableview.h"
#include "util/assert.h"
-DlgMissing::DlgMissing(QWidget* parent, UserSettingsPointer pConfig,
- Library* pLibrary,
- TrackCollection* pTrackCollection, KeyboardEventFilter* pKeyboard)
- : QWidget(parent),
- Ui::DlgMissing(),
- m_pTrackTableView(
- new WTrackTableView(this, pConfig, pTrackCollection, false)) {
- setupUi(this);
- m_pTrackTableView->installEventFilter(pKeyboard);
-
- // Install our own trackTable
- QBoxLayout* box = dynamic_cast(layout());
- DEBUG_ASSERT_AND_HANDLE(box) { //Assumes the form layout is a QVBox/QHBoxLayout!
- } else {
- box->removeWidget(m_pTrackTablePlaceholder);
- m_pTrackTablePlaceholder->hide();
- box->insertWidget(1, m_pTrackTableView);
- }
-
- m_pMissingTableModel = new MissingTableModel(this, pTrackCollection);
- m_pTrackTableView->loadTrackModel(m_pMissingTableModel);
-
- connect(btnPurge, SIGNAL(clicked()),
- m_pTrackTableView, SLOT(slotPurge()));
- connect(btnPurge, SIGNAL(clicked()),
- this, SLOT(clicked()));
- connect(btnSelect, SIGNAL(clicked()),
- this, SLOT(selectAll()));
- connect(m_pTrackTableView->selectionModel(),
- SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
- this,
- SLOT(selectionChanged(const QItemSelection&, const QItemSelection&)));
- connect(pLibrary, SIGNAL(setTrackTableFont(QFont)),
- m_pTrackTableView, SLOT(setTrackTableFont(QFont)));
- connect(pLibrary, SIGNAL(setTrackTableRowHeight(int)),
- m_pTrackTableView, SLOT(setTrackTableRowHeight(int)));
-
- connect(m_pTrackTableView, SIGNAL(trackSelected(TrackPointer)),
- this, SIGNAL(trackSelected(TrackPointer)));
+DlgMissing::DlgMissing(QWidget* parent)
+ : QFrame(parent),
+ Ui::DlgMissing() {
+ setupUi(this);
+
+ connect(btnPurge, SIGNAL(clicked()), this, SLOT(onShow()));
+ connect(btnPurge, SIGNAL(clicked()), this, SIGNAL(purge()));
+ connect(btnSelect, SIGNAL(clicked()), this, SIGNAL(selectAll()));
}
DlgMissing::~DlgMissing() {
// Delete m_pTrackTableView before the table model. This is because the
// table view saves the header state using the model.
- delete m_pTrackTableView;
delete m_pMissingTableModel;
}
@@ -57,33 +25,14 @@ void DlgMissing::onShow() {
activateButtons(false);
}
-void DlgMissing::clicked() {
- // all marked tracks are gone now anyway
- onShow();
-}
-
-void DlgMissing::onSearch(const QString& text) {
- m_pMissingTableModel->search(text);
+void DlgMissing::setSelectedIndexes(const QModelIndexList& selectedIndexes) {
+ activateButtons(!selectedIndexes.isEmpty());
}
-void DlgMissing::selectAll() {
- m_pTrackTableView->selectAll();
+void DlgMissing::setTableModel(MissingTableModel* pTableModel) {
+ m_pMissingTableModel = pTableModel;
}
void DlgMissing::activateButtons(bool enable) {
btnPurge->setEnabled(enable);
}
-
-void DlgMissing::selectionChanged(const QItemSelection &selected,
- const QItemSelection &deselected) {
- Q_UNUSED(deselected);
- activateButtons(!selected.indexes().isEmpty());
-}
-
-void DlgMissing::setTrackTableFont(const QFont& font) {
- m_pTrackTableView->setTrackTableFont(font);
-}
-
-void DlgMissing::setTrackTableRowHeight(int rowHeight) {
- m_pTrackTableView->setTrackTableRowHeight(rowHeight);
-}
diff --git a/src/library/dlgmissing.h b/src/library/dlgmissing.h
index fe287e8e8ef3..6438e035b36e 100644
--- a/src/library/dlgmissing.h
+++ b/src/library/dlgmissing.h
@@ -11,30 +11,27 @@
class WTrackTableView;
class MissingTableModel;
-class DlgMissing : public QWidget, public Ui::DlgMissing, public LibraryView {
+class DlgMissing : public QFrame, public Ui::DlgMissing {
Q_OBJECT
public:
- DlgMissing(QWidget* parent, UserSettingsPointer pConfig,
- Library* pLibrary, TrackCollection* pTrackCollection,
- KeyboardEventFilter* pKeyboard);
+ DlgMissing(QWidget* parent);
virtual ~DlgMissing();
- void onShow();
- void onSearch(const QString& text);
+ // The indexes are always from the Focused pane
+ void setSelectedIndexes(const QModelIndexList& selectedIndexes);
+ void setTableModel(MissingTableModel* pTableModel);
public slots:
- void clicked();
- void selectAll();
- void selectionChanged(const QItemSelection&, const QItemSelection&);
- void setTrackTableFont(const QFont& font);
- void setTrackTableRowHeight(int rowHeight);
+ void onShow();
signals:
+ void purge();
+ void selectAll();
void trackSelected(TrackPointer pTrack);
private:
void activateButtons(bool enable);
- WTrackTableView* m_pTrackTableView;
+
MissingTableModel* m_pMissingTableModel;
};
diff --git a/src/library/dlgmissing.ui b/src/library/dlgmissing.ui
index 8db680a895ce..bc3a8805537c 100644
--- a/src/library/dlgmissing.ui
+++ b/src/library/dlgmissing.ui
@@ -14,87 +14,44 @@
Missing Tracks
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
- 0
+
+
+ Selects all tracks in the table below.
-
- 0
+
+ Select All
-
- 0
+
+
+ -
+
+
+ Purge selected tracks from the library.
-
- 0
+
+ Purge
-
- 0
+
+ false
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Selects all tracks in the table below.
-
-
- Select All
-
-
-
- -
-
-
- Purge selected tracks from the library.
-
-
- Purge
-
-
- false
-
-
-
-
+
-
-
-
- true
+
+
+ Qt::Vertical
-
+
+
+ 20
+ 316
+
+
+
-
-
-
+
diff --git a/src/library/setlogfeature.cpp b/src/library/historyfeature.cpp
similarity index 88%
rename from src/library/setlogfeature.cpp
rename to src/library/historyfeature.cpp
index 01e2ba7919d0..14e8c222b992 100644
--- a/src/library/setlogfeature.cpp
+++ b/src/library/historyfeature.cpp
@@ -2,7 +2,7 @@
#include
#include
-#include "library/setlogfeature.h"
+#include "library/historyfeature.h"
#include "control/controlobject.h"
#include "library/playlisttablemodel.h"
@@ -11,14 +11,12 @@
#include "mixer/playerinfo.h"
#include "mixer/playermanager.h"
-SetlogFeature::SetlogFeature(QObject* parent,
- UserSettingsPointer pConfig,
+HistoryFeature::HistoryFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
TrackCollection* pTrackCollection)
- : BasePlaylistFeature(parent, pConfig, pTrackCollection, "SETLOGHOME"),
+ : BasePlaylistFeature(pConfig, pLibrary, parent, pTrackCollection),
m_playlistId(-1) {
- m_pPlaylistTableModel = new PlaylistTableModel(this, pTrackCollection,
- "mixxx.db.model.setlog",
- true); //show all tracks
m_pJoinWithPreviousAction = new QAction(tr("Join with previous"), this);
connect(m_pJoinWithPreviousAction, SIGNAL(triggered()),
this, SLOT(slotJoinWithPrevious()));
@@ -33,9 +31,12 @@ SetlogFeature::SetlogFeature(QObject* parent,
TreeItem *rootItem = new TreeItem();
m_childModel.setRootItem(rootItem);
constructChildModel(-1);
+
+ connect(&PlayerInfo::instance(), SIGNAL(currentPlayingTrackChanged(TrackPointer)),
+ this, SLOT(slotPlayingTrackChanged(TrackPointer)));
}
-SetlogFeature::~SetlogFeature() {
+HistoryFeature::~HistoryFeature() {
// If the history playlist we created doesn't have any tracks in it then
// delete it so we don't end up with tons of empty playlists. This is mostly
// for developers since they regularly open Mixxx without loading a track.
@@ -45,24 +46,15 @@ SetlogFeature::~SetlogFeature() {
}
}
-QVariant SetlogFeature::title() {
+QVariant HistoryFeature::title() {
return tr("History");
}
-QIcon SetlogFeature::getIcon() {
+QIcon HistoryFeature::getIcon() {
return QIcon(":/images/library/ic_library_history.png");
}
-void SetlogFeature::bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* keyboard) {
- BasePlaylistFeature::bindWidget(libraryWidget,
- keyboard);
- connect(&PlayerInfo::instance(), SIGNAL(currentPlayingTrackChanged(TrackPointer)),
- this, SLOT(slotPlayingTrackChanged(TrackPointer)));
-}
-
-void SetlogFeature::onRightClick(const QPoint& globalPos) {
- Q_UNUSED(globalPos);
+void HistoryFeature::onRightClick(const QPoint&) {
m_lastRightClickedIndex = QModelIndex();
// Create the right-click menu
@@ -72,7 +64,7 @@ void SetlogFeature::onRightClick(const QPoint& globalPos) {
// menu.exec(globalPos);
}
-void SetlogFeature::onRightClickChild(const QPoint& globalPos, QModelIndex index) {
+void HistoryFeature::onRightClickChild(const QPoint& globalPos, QModelIndex index) {
//Save the model index so we can get it in the action slots...
m_lastRightClickedIndex = index;
QString playlistName = index.data().toString();
@@ -113,7 +105,7 @@ void SetlogFeature::onRightClickChild(const QPoint& globalPos, QModelIndex index
}
-void SetlogFeature::buildPlaylistList() {
+void HistoryFeature::buildPlaylistList() {
m_playlistList.clear();
// Setup the sidebar playlist model
QSqlTableModel playlistTableModel(this, m_pTrackCollection->getDatabase());
@@ -138,7 +130,7 @@ void SetlogFeature::buildPlaylistList() {
}
}
-void SetlogFeature::decorateChild(TreeItem* item, int playlist_id) {
+void HistoryFeature::decorateChild(TreeItem* item, int playlist_id) {
if (playlist_id == m_playlistId) {
item->setIcon(QIcon(":/images/library/ic_library_history_current.png"));
} else if (m_playlistDao.isPlaylistLocked(playlist_id)) {
@@ -148,7 +140,12 @@ void SetlogFeature::decorateChild(TreeItem* item, int playlist_id) {
}
}
-void SetlogFeature::slotGetNewPlaylist() {
+PlaylistTableModel* HistoryFeature::constructTableModel() {
+ return new PlaylistTableModel(this, m_pTrackCollection,
+ "mixxx.db.model.setlog", true);
+}
+
+void HistoryFeature::slotGetNewPlaylist() {
//qDebug() << "slotGetNewPlaylist() succesfully triggered !";
// create a new playlist for today
@@ -174,10 +171,10 @@ void SetlogFeature::slotGetNewPlaylist() {
}
slotPlaylistTableChanged(m_playlistId); // For moving selection
- emit(showTrackModel(m_pPlaylistTableModel));
+ showTrackModel(m_pPlaylistTableModel);
}
-void SetlogFeature::slotJoinWithPrevious() {
+void HistoryFeature::slotJoinWithPrevious() {
//qDebug() << "slotJoinWithPrevious() row:" << m_lastRightClickedIndex.data();
if (m_lastRightClickedIndex.isValid()) {
@@ -222,14 +219,14 @@ void SetlogFeature::slotJoinWithPrevious() {
if (m_playlistDao.copyPlaylistTracks(currentPlaylistId, previousPlaylistId)) {
m_playlistDao.deletePlaylist(currentPlaylistId);
slotPlaylistTableChanged(previousPlaylistId); // For moving selection
- emit(showTrackModel(m_pPlaylistTableModel));
+ showTrackModel(m_pPlaylistTableModel);
}
}
}
}
}
-void SetlogFeature::slotPlayingTrackChanged(TrackPointer currentPlayingTrack) {
+void HistoryFeature::slotPlayingTrackChanged(TrackPointer currentPlayingTrack) {
if (!currentPlayingTrack) {
return;
}
@@ -264,6 +261,8 @@ void SetlogFeature::slotPlayingTrackChanged(TrackPointer currentPlayingTrack) {
if (!currentPlayingTrackId.isValid()) {
return;
}
+
+ m_pPlaylistTableModel = getPlaylistTableModel(-1);
if (m_pPlaylistTableModel->getPlaylist() == m_playlistId) {
// View needs a refresh
@@ -275,7 +274,7 @@ void SetlogFeature::slotPlayingTrackChanged(TrackPointer currentPlayingTrack) {
}
}
-void SetlogFeature::slotPlaylistTableChanged(int playlistId) {
+void HistoryFeature::slotPlaylistTableChanged(int playlistId) {
if (!m_pPlaylistTableModel) {
return;
}
@@ -289,7 +288,7 @@ void SetlogFeature::slotPlaylistTableChanged(int playlistId) {
}
}
-void SetlogFeature::slotPlaylistContentChanged(int playlistId) {
+void HistoryFeature::slotPlaylistContentChanged(int playlistId) {
if (!m_pPlaylistTableModel) {
return;
}
@@ -302,7 +301,7 @@ void SetlogFeature::slotPlaylistContentChanged(int playlistId) {
}
}
-void SetlogFeature::slotPlaylistTableRenamed(int playlistId,
+void HistoryFeature::slotPlaylistTableRenamed(int playlistId,
QString /* a_strName */) {
if (!m_pPlaylistTableModel) {
return;
@@ -320,7 +319,7 @@ void SetlogFeature::slotPlaylistTableRenamed(int playlistId,
}
}
-QString SetlogFeature::getRootViewHtml() const {
+QString HistoryFeature::getRootViewHtml() const {
QString playlistsTitle = tr("History");
QString playlistsSummary = tr("The history section automatically keeps a list of tracks you play in your DJ sets.");
QString playlistsSummary2 = tr("This is handy for remembering what worked in your DJ sets, posting set-lists, or reporting your plays to licensing organizations.");
diff --git a/src/library/setlogfeature.h b/src/library/historyfeature.h
similarity index 78%
rename from src/library/setlogfeature.h
rename to src/library/historyfeature.h
index d02b25e4e6ea..dffda06d2456 100644
--- a/src/library/setlogfeature.h
+++ b/src/library/historyfeature.h
@@ -13,21 +13,20 @@
class TrackCollection;
class TreeItem;
-class SetlogFeature : public BasePlaylistFeature {
+class HistoryFeature : public BasePlaylistFeature {
Q_OBJECT
public:
- SetlogFeature(QObject* parent, UserSettingsPointer pConfig,
+ HistoryFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
TrackCollection* pTrackCollection);
- virtual ~SetlogFeature();
+ virtual ~HistoryFeature();
QVariant title();
QIcon getIcon();
- virtual void bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* keyboard);
-
public slots:
- void onRightClick(const QPoint& globalPos);
+ void onRightClick(const QPoint&);
void onRightClickChild(const QPoint& globalPos, QModelIndex index);
void slotJoinWithPrevious();
void slotGetNewPlaylist();
@@ -35,6 +34,7 @@ class SetlogFeature : public BasePlaylistFeature {
protected:
void buildPlaylistList();
void decorateChild(TreeItem *pChild, int playlist_id);
+ PlaylistTableModel* constructTableModel();
private slots:
void slotPlayingTrackChanged(TrackPointer currentPlayingTrack);
diff --git a/src/library/itunes/itunesfeature.cpp b/src/library/itunes/itunesfeature.cpp
index 24a4655a31a5..0b3dac8aeaf2 100644
--- a/src/library/itunes/itunesfeature.cpp
+++ b/src/library/itunes/itunesfeature.cpp
@@ -14,6 +14,7 @@
#include "library/dao/settingsdao.h"
#include "library/baseexternaltrackmodel.h"
#include "library/baseexternalplaylistmodel.h"
+#include "library/library.h"
#include "library/queryutil.h"
#include "util/lcs.h"
#include "util/sandbox.h"
@@ -28,8 +29,11 @@ QString localhost_token() {
#endif
}
-ITunesFeature::ITunesFeature(QObject* parent, TrackCollection* pTrackCollection)
- : BaseExternalLibraryFeature(parent, pTrackCollection),
+ITunesFeature::ITunesFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection)
+ : BaseExternalLibraryFeature(pConfig, pLibrary, parent, pTrackCollection),
m_pTrackCollection(pTrackCollection),
m_cancelImport(false) {
QString tableName = "itunes_library";
@@ -143,7 +147,8 @@ void ITunesFeature::activate(bool forceReload) {
NULL, tr("Select your iTunes library"), QDir::homePath(), "*.xml");
QFileInfo dbFile(m_dbfile);
if (m_dbfile.isEmpty() || !dbFile.exists()) {
- emit(showTrackModel(m_pITunesTrackModel));
+ m_pLibrary->showBreadCrumb(m_childModel.getItem(QModelIndex()));
+ showTrackModel(m_pITunesTrackModel);
return;
}
@@ -173,7 +178,8 @@ void ITunesFeature::activate(bool forceReload) {
emit (featureIsLoading(this, true));
}
- emit(showTrackModel(m_pITunesTrackModel));
+ showTrackModel(m_pITunesTrackModel);
+ m_pLibrary->showBreadCrumb(m_childModel.getItem(QModelIndex()));
emit(enableCoverArtDisplay(false));
}
@@ -182,7 +188,9 @@ void ITunesFeature::activateChild(const QModelIndex& index) {
QString playlist = index.data().toString();
qDebug() << "Activating " << playlist;
m_pITunesPlaylistModel->setPlaylist(playlist);
- emit(showTrackModel(m_pITunesPlaylistModel));
+
+ showTrackModel(m_pITunesPlaylistModel);
+ m_pLibrary->showBreadCrumb(static_cast(index.internalPointer()));
emit(enableCoverArtDisplay(false));
}
@@ -735,6 +743,7 @@ void ITunesFeature::clearTable(QString table_name) {
void ITunesFeature::onTrackCollectionLoaded() {
TreeItem* root = m_future.result();
+ root->setLibraryFeature(this);
if (root) {
m_childModel.setRootItem(root);
@@ -742,7 +751,7 @@ void ITunesFeature::onTrackCollectionLoaded() {
m_trackSource->buildIndex();
//m_pITunesTrackModel->select();
- emit(showTrackModel(m_pITunesTrackModel));
+ showTrackModel(m_pITunesTrackModel);
qDebug() << "Itunes library loaded: success";
} else {
QMessageBox::warning(
diff --git a/src/library/itunes/itunesfeature.h b/src/library/itunes/itunesfeature.h
index 3dcf3baa5ec6..10818eca0f45 100644
--- a/src/library/itunes/itunesfeature.h
+++ b/src/library/itunes/itunesfeature.h
@@ -21,7 +21,10 @@ class BaseExternalPlaylistModel;
class ITunesFeature : public BaseExternalLibraryFeature {
Q_OBJECT
public:
- ITunesFeature(QObject* parent, TrackCollection* pTrackCollection);
+ ITunesFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection);
virtual ~ITunesFeature();
static bool isSupported();
diff --git a/src/library/library.cpp b/src/library/library.cpp
index 99520e58e8c8..625102aa005e 100644
--- a/src/library/library.cpp
+++ b/src/library/library.cpp
@@ -5,12 +5,15 @@
#include
#include
#include
+#include
#include "mixer/playermanager.h"
#include "library/library.h"
#include "library/library_preferences.h"
#include "library/libraryfeature.h"
#include "library/librarytablemodel.h"
+#include "library/librarypanemanager.h"
+#include "library/librarysidebarexpandedmanager.h"
#include "library/sidebarmodel.h"
#include "library/trackcollection.h"
#include "library/trackmodel.h"
@@ -25,20 +28,15 @@
#include "library/playlistfeature.h"
#include "library/traktor/traktorfeature.h"
#include "library/librarycontrol.h"
-#include "library/setlogfeature.h"
+#include "library/historyfeature.h"
#include "util/sandbox.h"
#include "util/assert.h"
-#include "widget/wtracktableview.h"
-#include "widget/wlibrary.h"
#include "widget/wlibrarysidebar.h"
+#include "widget/wbuttonbar.h"
#include "controllers/keyboard/keyboardeventfilter.h"
-// This is is the name which we use to register the WTrackTableView with the
-// WLibrary
-const QString Library::m_sTrackViewName = QString("WTrackTableView");
-
// The default row height of the library.
const int Library::kDefaultRowHeightPx = 20;
@@ -50,7 +48,8 @@ Library::Library(QObject* parent, UserSettingsPointer pConfig,
m_pTrackCollection(new TrackCollection(pConfig)),
m_pLibraryControl(new LibraryControl(this)),
m_pRecordingManager(pRecordingManager),
- m_scanner(m_pTrackCollection, pConfig) {
+ m_scanner(m_pTrackCollection, pConfig),
+ m_pSidebarExpanded(nullptr) {
qRegisterMetaType("Library::RemovalType");
connect(&m_scanner, SIGNAL(scanStarted()),
@@ -60,56 +59,8 @@ Library::Library(QObject* parent, UserSettingsPointer pConfig,
// Refresh the library models when the library (re)scan is finished.
connect(&m_scanner, SIGNAL(scanFinished()),
this, SLOT(slotRefreshLibraryModels()));
-
- // TODO(rryan) -- turn this construction / adding of features into a static
- // method or something -- CreateDefaultLibrary
- m_pMixxxLibraryFeature = new MixxxLibraryFeature(this, m_pTrackCollection,m_pConfig);
- addFeature(m_pMixxxLibraryFeature);
-
- addFeature(new AutoDJFeature(this, pConfig, pPlayerManager, m_pTrackCollection));
- m_pPlaylistFeature = new PlaylistFeature(this, m_pTrackCollection, m_pConfig);
- addFeature(m_pPlaylistFeature);
- m_pCrateFeature = new CrateFeature(this, m_pTrackCollection, m_pConfig);
- addFeature(m_pCrateFeature);
- BrowseFeature* browseFeature = new BrowseFeature(
- this, pConfig, m_pTrackCollection, m_pRecordingManager);
- connect(browseFeature, SIGNAL(scanLibrary()),
- &m_scanner, SLOT(scan()));
- connect(&m_scanner, SIGNAL(scanStarted()),
- browseFeature, SLOT(slotLibraryScanStarted()));
- connect(&m_scanner, SIGNAL(scanFinished()),
- browseFeature, SLOT(slotLibraryScanFinished()));
-
- addFeature(browseFeature);
- addFeature(new RecordingFeature(this, pConfig, m_pTrackCollection, m_pRecordingManager));
- addFeature(new SetlogFeature(this, pConfig, m_pTrackCollection));
- m_pAnalysisFeature = new AnalysisFeature(this, pConfig, m_pTrackCollection);
- connect(m_pPlaylistFeature, SIGNAL(analyzeTracks(QList)),
- m_pAnalysisFeature, SLOT(analyzeTracks(QList)));
- connect(m_pCrateFeature, SIGNAL(analyzeTracks(QList)),
- m_pAnalysisFeature, SLOT(analyzeTracks(QList)));
- addFeature(m_pAnalysisFeature);
- //iTunes and Rhythmbox should be last until we no longer have an obnoxious
- //messagebox popup when you select them. (This forces you to reach for your
- //mouse or keyboard if you're using MIDI control and you scroll through them...)
- if (RhythmboxFeature::isSupported() &&
- pConfig->getValueString(ConfigKey("[Library]","ShowRhythmboxLibrary"),"1").toInt()) {
- addFeature(new RhythmboxFeature(this, m_pTrackCollection));
- }
- if (pConfig->getValueString(ConfigKey("[Library]","ShowBansheeLibrary"),"1").toInt()) {
- BansheeFeature::prepareDbPath(pConfig);
- if (BansheeFeature::isSupported()) {
- addFeature(new BansheeFeature(this, m_pTrackCollection, pConfig));
- }
- }
- if (ITunesFeature::isSupported() &&
- pConfig->getValueString(ConfigKey("[Library]","ShowITunesLibrary"),"1").toInt()) {
- addFeature(new ITunesFeature(this, m_pTrackCollection));
- }
- if (TraktorFeature::isSupported() &&
- pConfig->getValueString(ConfigKey("[Library]","ShowTraktorLibrary"),"1").toInt()) {
- addFeature(new TraktorFeature(this, m_pTrackCollection));
- }
+
+ createFeatures(pConfig, pPlayerManager);
// On startup we need to check if all of the user's library folders are
// accessible to us. If the user is using a database from <1.12.0 with
@@ -137,13 +88,9 @@ Library::Library(QObject* parent, UserSettingsPointer pConfig,
Library::~Library() {
// Delete the sidebar model first since it depends on the LibraryFeatures.
delete m_pSidebarModel;
-
- QMutableListIterator features_it(m_features);
- while(features_it.hasNext()) {
- LibraryFeature* feature = features_it.next();
- features_it.remove();
- delete feature;
- }
+
+ qDeleteAll(m_features);
+ m_features.clear();
delete m_pLibraryControl;
//IMPORTANT: m_pTrackCollection gets destroyed via the QObject hierarchy somehow.
@@ -154,106 +101,113 @@ Library::~Library() {
delete m_pTrackCollection;
}
-void Library::bindSidebarWidget(WLibrarySidebar* pSidebarWidget) {
- m_pLibraryControl->bindSidebarWidget(pSidebarWidget);
-
- // Setup the sources view
- pSidebarWidget->setModel(m_pSidebarModel);
- connect(m_pSidebarModel, SIGNAL(selectIndex(const QModelIndex&)),
- pSidebarWidget, SLOT(selectIndex(const QModelIndex&)));
- connect(pSidebarWidget, SIGNAL(pressed(const QModelIndex&)),
- m_pSidebarModel, SLOT(clicked(const QModelIndex&)));
- // Lazy model: Let triangle symbol increment the model
- connect(pSidebarWidget, SIGNAL(expanded(const QModelIndex&)),
- m_pSidebarModel, SLOT(doubleClicked(const QModelIndex&)));
-
- connect(pSidebarWidget, SIGNAL(rightClicked(const QPoint&, const QModelIndex&)),
- m_pSidebarModel, SLOT(rightClicked(const QPoint&, const QModelIndex&)));
-
- pSidebarWidget->slotSetFont(m_trackTableFont);
- connect(this, SIGNAL(setTrackTableFont(QFont)),
- pSidebarWidget, SLOT(slotSetFont(QFont)));
+void Library::bindSearchBar(WSearchLineEdit* searchLine, int id) {
+ // Get the value once to avoid searching again in the hash
+ LibraryPaneManager* pPane = getPane(id);
+ pPane->bindSearchBar(searchLine);
}
-void Library::bindWidget(WLibrary* pLibraryWidget,
- KeyboardEventFilter* pKeyboard) {
- WTrackTableView* pTrackTableView =
- new WTrackTableView(pLibraryWidget, m_pConfig, m_pTrackCollection);
- pTrackTableView->installEventFilter(pKeyboard);
- connect(this, SIGNAL(showTrackModel(QAbstractItemModel*)),
- pTrackTableView, SLOT(loadTrackModel(QAbstractItemModel*)));
- connect(pTrackTableView, SIGNAL(loadTrack(TrackPointer)),
- this, SLOT(slotLoadTrack(TrackPointer)));
- connect(pTrackTableView, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)),
- this, SLOT(slotLoadTrackToPlayer(TrackPointer, QString, bool)));
- pLibraryWidget->registerView(m_sTrackViewName, pTrackTableView);
-
- connect(this, SIGNAL(switchToView(const QString&)),
- pLibraryWidget, SLOT(switchToView(const QString&)));
-
- connect(pTrackTableView, SIGNAL(trackSelected(TrackPointer)),
- this, SIGNAL(trackSelected(TrackPointer)));
-
- connect(this, SIGNAL(setTrackTableFont(QFont)),
- pTrackTableView, SLOT(setTrackTableFont(QFont)));
- connect(this, SIGNAL(setTrackTableRowHeight(int)),
- pTrackTableView, SLOT(setTrackTableRowHeight(int)));
-
- connect(this, SIGNAL(searchStarting()),
- pTrackTableView, SLOT(onSearchStarting()));
- connect(this, SIGNAL(searchCleared()),
- pTrackTableView, SLOT(onSearchCleared()));
-
- m_pLibraryControl->bindWidget(pLibraryWidget, pKeyboard);
-
- QListIterator feature_it(m_features);
- while(feature_it.hasNext()) {
- LibraryFeature* feature = feature_it.next();
- feature->bindWidget(pLibraryWidget, pKeyboard);
+void Library::bindSidebarWidget(WButtonBar* sidebar) {
+ for (LibraryFeature* f : m_features) {
+ WFeatureClickButton* button = sidebar->addButton(f);
+
+ connect(button, SIGNAL(clicked(LibraryFeature*)),
+ this, SLOT(slotActivateFeature(LibraryFeature*)));
+ connect(button, SIGNAL(hoverShow(LibraryFeature*)),
+ this, SLOT(slotHoverFeature(LibraryFeature*)));
+ connect(button, SIGNAL(rightClicked(const QPoint&)),
+ f, SLOT(onRightClick(const QPoint&)));
}
+}
+void Library::bindPaneWidget(WLibrary* pLibraryWidget,
+ KeyboardEventFilter* pKeyboard, int paneId) {
+
+ // Get the value once to avoid searching again in the hash
+ LibraryPaneManager* pPane = getPane(paneId);
+ pPane->bindPaneWidget(pLibraryWidget, pKeyboard);
+
+ connect(pPane, SIGNAL(search(const QString&)),
+ pLibraryWidget, SLOT(search(const QString&)));
+
// Set the current font and row height on all the WTrackTableViews that were
// just connected to us.
emit(setTrackTableFont(m_trackTableFont));
emit(setTrackTableRowHeight(m_iTrackTableRowHeight));
}
+void Library::bindSidebarExpanded(WBaseLibrary* expandedPane,
+ KeyboardEventFilter* pKeyboard) {
+ //qDebug() << "Library::bindSidebarExpanded";
+ m_pSidebarExpanded = new LibrarySidebarExpandedManager(this);
+ m_pSidebarExpanded->addFeatures(m_features);
+ m_pSidebarExpanded->bindPaneWidget(expandedPane, pKeyboard);
+}
+
+void Library::bindBreadCrumb(WLibraryBreadCrumb* pBreadCrumb, int paneId) {
+ // Get the value once to avoid searching again in the hash
+ LibraryPaneManager* pPane = getPane(paneId);
+ pPane->setBreadCrumb(pBreadCrumb);
+}
+
+void Library::destroyInterface() {
+ m_pSidebarExpanded->deleteLater();
+
+ for (LibraryPaneManager* p : m_panes) {
+ p->deleteLater();
+ }
+
+ for (LibraryFeature* f : m_features) {
+ f->setFeatureFocus(-1);
+ }
+ m_panes.clear();
+}
+
+LibraryView *Library::getActiveView() {
+ WBaseLibrary* pPane = m_panes[m_focusedPane]->getPaneWidget();
+ WLibrary* pLibrary = qobject_cast(pPane);
+ DEBUG_ASSERT_AND_HANDLE(pLibrary) {
+ return nullptr;
+ }
+ return pLibrary->getActiveView();
+}
+
+
void Library::addFeature(LibraryFeature* feature) {
DEBUG_ASSERT_AND_HANDLE(feature) {
return;
}
- m_features.push_back(feature);
+ m_features.append(feature);
+
m_pSidebarModel->addLibraryFeature(feature);
- connect(feature, SIGNAL(showTrackModel(QAbstractItemModel*)),
- this, SLOT(slotShowTrackModel(QAbstractItemModel*)));
- connect(feature, SIGNAL(switchToView(const QString&)),
- this, SLOT(slotSwitchToView(const QString&)));
+
+ // TODO(jmigual): this should be removed and add a direct interaction
+ // between the LibraryFeature and the Library
connect(feature, SIGNAL(loadTrack(TrackPointer)),
this, SLOT(slotLoadTrack(TrackPointer)));
connect(feature, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)),
this, SLOT(slotLoadTrackToPlayer(TrackPointer, QString, bool)));
- connect(feature, SIGNAL(restoreSearch(const QString&)),
- this, SLOT(slotRestoreSearch(const QString&)));
connect(feature, SIGNAL(enableCoverArtDisplay(bool)),
this, SIGNAL(enableCoverArtDisplay(bool)));
connect(feature, SIGNAL(trackSelected(TrackPointer)),
this, SIGNAL(trackSelected(TrackPointer)));
}
-void Library::slotShowTrackModel(QAbstractItemModel* model) {
- //qDebug() << "Library::slotShowTrackModel" << model;
- TrackModel* trackModel = dynamic_cast(model);
- DEBUG_ASSERT_AND_HANDLE(trackModel) {
- return;
+void Library::switchToFeature(LibraryFeature* pFeature) {
+ m_pSidebarExpanded->switchToFeature(pFeature);
+ slotUpdateFocus(pFeature);
+
+ WBaseLibrary* pWLibrary = m_panes[m_focusedPane]->getPaneWidget();
+ // Only change the current pane if it's not shown already
+ if (pWLibrary->getCurrentFeature() != pFeature) {
+ m_panes[m_focusedPane]->switchToFeature(pFeature);
}
- emit(showTrackModel(model));
- emit(switchToView(m_sTrackViewName));
- emit(restoreSearch(trackModel->currentSearch()));
+
+ handleFocus();
}
-void Library::slotSwitchToView(const QString& view) {
- //qDebug() << "Library::slotSwitchToView" << view;
- emit(switchToView(view));
+void Library::showBreadCrumb(TreeItem *pTree) {
+ m_panes[m_focusedPane]->showBreadCrumb(pTree);
}
void Library::slotLoadTrack(TrackPointer pTrack) {
@@ -272,8 +226,12 @@ void Library::slotLoadTrackToPlayer(TrackPointer pTrack, QString group, bool pla
emit(loadTrackToPlayer(pTrack, group, play));
}
-void Library::slotRestoreSearch(const QString& text) {
- emit(restoreSearch(text));
+void Library::restoreSearch(const QString& text) {
+ LibraryPaneManager* pane = getFocusedPane();
+ DEBUG_ASSERT_AND_HANDLE(pane) {
+ return;
+ }
+ pane->restoreSearch(text);
}
void Library::slotRefreshLibraryModels() {
@@ -291,7 +249,32 @@ void Library::slotCreateCrate() {
void Library::onSkinLoadFinished() {
// Enable the default selection when a new skin is loaded.
- m_pSidebarModel->activateDefaultSelection();
+ //m_pSidebarModel->activateDefaultSelection();
+ if (m_panes.size() > 0) {
+
+ auto itF = m_features.begin();
+ auto itP = m_panes.begin();
+
+ // Assign a feature to show on each pane unless there are more panes
+ // than features
+ while (itP != m_panes.end() && itF != m_features.end()) {
+ m_focusedPane = itP.key();
+
+ (*itF)->setFeatureFocus(itP.key());
+ (*itF)->activate();
+
+ ++itP;
+ ++itF;
+ }
+
+ // The first pane always shows the Mixxx Library feature on start
+ m_focusedPane = m_panes.begin().key();
+ (*m_features.begin())->setFeatureFocus(m_focusedPane);
+ slotActivateFeature(*m_features.begin());
+ }
+ else {
+ qDebug() << "Library::onSkinLoadFinished No Panes loaded!";
+ }
}
void Library::slotRequestAddDir(QString dir) {
@@ -368,6 +351,64 @@ QStringList Library::getDirs() {
return m_pTrackCollection->getDirectoryDAO().getDirs();
}
+void Library::paneCollapsed(int paneId) {
+ m_collapsedPanes.insert(paneId);
+
+ // Automatically switch the focus to a non collapsed pane
+ m_panes[paneId]->clearFocus();
+
+ for (LibraryPaneManager* pPane : m_panes) {
+ if (!m_collapsedPanes.contains(pPane->getPaneId())) {
+ m_focusedPane = pPane->getPaneId();
+ setFocusedPane();
+ pPane->setFocus();
+ break;
+ }
+ }
+}
+
+void Library::paneUncollapsed(int paneId) {
+ m_collapsedPanes.remove(paneId);
+}
+
+void Library::slotActivateFeature(LibraryFeature *pFeature) {
+ // The feature is being shown currently in the focused pane
+ if (m_panes[m_focusedPane]->getCurrentFeature() == pFeature) {
+ m_pSidebarExpanded->switchToFeature(pFeature);
+ handleFocus();
+ return;
+ }
+ int featureFocus = pFeature->getFeatureFocus();
+
+ // The feature is not focused anywhere
+ if (featureFocus < 0 || m_collapsedPanes.contains(featureFocus)) {
+ // Remove the previous focused feature in this pane
+ for (LibraryFeature* f : m_features) {
+ if (f->getFeatureFocus() == m_focusedPane) {
+ f->setFeatureFocus(-1);
+ }
+ }
+ } else {
+ // The feature is shown in some not collapsed pane
+ m_focusedPane = featureFocus;
+ setFocusedPane();
+ m_pSidebarExpanded->switchToFeature(pFeature);
+ handleFocus();
+ return;
+ }
+
+ m_panes[m_focusedPane]->setCurrentFeature(pFeature);
+ pFeature->setFeatureFocus(m_focusedPane);
+ pFeature->activate();
+ handleFocus();
+}
+
+void Library::slotHoverFeature(LibraryFeature *pFeature) {
+ // This function only changes the sidebar expanded to allow dropping items
+ // directly in some features sidebar panes
+ m_pSidebarExpanded->switchToFeature(pFeature);
+}
+
void Library::slotSetTrackTableFont(const QFont& font) {
m_trackTableFont = font;
emit(setTrackTableFont(font));
@@ -377,3 +418,126 @@ void Library::slotSetTrackTableRowHeight(int rowHeight) {
m_iTrackTableRowHeight = rowHeight;
emit(setTrackTableRowHeight(rowHeight));
}
+
+void Library::slotPaneFocused(LibraryPaneManager* pPane) {
+ DEBUG_ASSERT_AND_HANDLE(pPane) {
+ return;
+ }
+
+ if (pPane != m_pSidebarExpanded) {
+ m_focusedPane = pPane->getPaneId();
+ pPane->getCurrentFeature()->setFeatureFocus(m_focusedPane);
+ DEBUG_ASSERT_AND_HANDLE(m_focusedPane != -1) {
+ return;
+ }
+ setFocusedPane();
+ handleFocus();
+ }
+
+ //qDebug() << "Library::slotPaneFocused" << m_focusedPane;
+}
+
+void Library::slotUpdateFocus(LibraryFeature *pFeature) {
+ if (pFeature->getFeatureFocus() >= 0) {
+ m_focusedPane = pFeature->getFeatureFocus();
+ setFocusedPane();
+ }
+}
+
+
+LibraryPaneManager* Library::getPane(int paneId) {
+ //qDebug() << "Library::createPane" << id;
+ // Get the value once to avoid searching again in the hash
+ auto it = m_panes.find(paneId);
+ if (it != m_panes.end()) {
+ return *it;
+ }
+
+ LibraryPaneManager* pPane = new LibraryPaneManager(paneId, this);
+ pPane->addFeatures(m_features);
+ m_panes.insert(paneId, pPane);
+
+ m_focusedPane = paneId;
+ setFocusedPane();
+ return pPane;
+}
+
+LibraryPaneManager *Library::getFocusedPane() {
+ //qDebug() << "Focused" << m_focusedPane;
+ if (m_focusedPane == -1) {
+ return m_pSidebarExpanded;
+ }
+ else if (m_panes.contains(m_focusedPane)) {
+ return m_panes[m_focusedPane];
+ }
+ return nullptr;
+}
+
+void Library::createFeatures(UserSettingsPointer pConfig, PlayerManagerInterface* pPlayerManager) {
+ m_pMixxxLibraryFeature = new MixxxLibraryFeature(pConfig, this, this, m_pTrackCollection);
+ addFeature(m_pMixxxLibraryFeature);
+
+ addFeature(new AutoDJFeature(pConfig, this, this, pPlayerManager, m_pTrackCollection));
+ m_pPlaylistFeature = new PlaylistFeature(pConfig, this, this, m_pTrackCollection);
+ addFeature(m_pPlaylistFeature);
+ m_pCrateFeature = new CrateFeature(pConfig, this, this, m_pTrackCollection);
+ addFeature(m_pCrateFeature);
+ BrowseFeature* browseFeature = new BrowseFeature(
+ pConfig, this, this, m_pTrackCollection, m_pRecordingManager);
+ connect(browseFeature, SIGNAL(scanLibrary()),
+ &m_scanner, SLOT(scan()));
+ connect(&m_scanner, SIGNAL(scanStarted()),
+ browseFeature, SLOT(slotLibraryScanStarted()));
+ connect(&m_scanner, SIGNAL(scanFinished()),
+ browseFeature, SLOT(slotLibraryScanFinished()));
+
+ addFeature(browseFeature);
+ addFeature(new RecordingFeature(pConfig, this, this, m_pTrackCollection, m_pRecordingManager));
+ addFeature(new HistoryFeature(pConfig, this, this, m_pTrackCollection));
+ m_pAnalysisFeature = new AnalysisFeature(pConfig, this, m_pTrackCollection, this);
+ connect(m_pPlaylistFeature, SIGNAL(analyzeTracks(QList)),
+ m_pAnalysisFeature, SLOT(analyzeTracks(QList)));
+ connect(m_pCrateFeature, SIGNAL(analyzeTracks(QList)),
+ m_pAnalysisFeature, SLOT(analyzeTracks(QList)));
+ addFeature(m_pAnalysisFeature);
+ //iTunes and Rhythmbox should be last until we no longer have an obnoxious
+ //messagebox popup when you select them. (This forces you to reach for your
+ //mouse or keyboard if you're using MIDI control and you scroll through them...)
+ if (RhythmboxFeature::isSupported() &&
+ pConfig->getValueString(ConfigKey("[Library]","ShowRhythmboxLibrary"),"1").toInt()) {
+ addFeature(new RhythmboxFeature(pConfig, this, this, m_pTrackCollection));
+ }
+
+ if (pConfig->getValueString(ConfigKey("[Library]","ShowBansheeLibrary"),"1").toInt()) {
+ BansheeFeature::prepareDbPath(pConfig);
+ if (BansheeFeature::isSupported()) {
+ addFeature(new BansheeFeature(pConfig, this, this, m_pTrackCollection));
+ }
+ }
+ if (ITunesFeature::isSupported() &&
+ pConfig->getValueString(ConfigKey("[Library]","ShowITunesLibrary"),"1").toInt()) {
+ addFeature(new ITunesFeature(pConfig, this, this, m_pTrackCollection));
+ }
+ if (TraktorFeature::isSupported() &&
+ pConfig->getValueString(ConfigKey("[Library]","ShowTraktorLibrary"),"1").toInt()) {
+ addFeature(new TraktorFeature(pConfig, this, this, m_pTrackCollection));
+ }
+}
+
+void Library::setFocusedPane() {
+ for (LibraryFeature* pFeature : m_features) {
+ pFeature->setFocusedPane(m_focusedPane);
+ }
+}
+
+void Library::handleFocus() {
+ // Changes the visual focus effect, removes the existing one and adds the
+ // new focus
+ m_panes[m_focusedPane]->setFocus();
+ for (auto it = m_panes.begin(); it != m_panes.end(); ++it) {
+ // Remove the focus from not focused panes
+ if (it.key() != m_focusedPane) {
+ it.value()->clearFocus();
+ }
+ }
+}
diff --git a/src/library/library.h b/src/library/library.h
index dbc8c8323e3c..092eb42d6768 100644
--- a/src/library/library.h
+++ b/src/library/library.h
@@ -11,45 +11,71 @@
#include
#include
#include
+#include
#include "preferences/usersettings.h"
#include "track/track.h"
#include "recording/recordingmanager.h"
#include "analysisfeature.h"
#include "library/coverartcache.h"
-#include "library/setlogfeature.h"
+#include "library/historyfeature.h"
#include "library/scanner/libraryscanner.h"
-class TrackModel;
-class TrackCollection;
-class SidebarModel;
+#include "widget/wtracktableview.h"
+#include "widget/wfeatureclickbutton.h"
+
+class CrateFeature;
+class KeyboardEventFilter;
+class LibraryPaneManager;
+class LibraryControl;
class LibraryFeature;
class LibraryTableModel;
-class WLibrarySidebar;
-class WLibrary;
-class WSearchLineEdit;
+class LibrarySidebarExpandedManager;
class MixxxLibraryFeature;
class PlaylistFeature;
-class CrateFeature;
-class LibraryControl;
-class KeyboardEventFilter;
class PlayerManagerInterface;
+class SidebarModel;
+class TrackModel;
+class TrackCollection;
+class WLibrary;
+class WLibrarySidebar;
+class WLibraryBreadCrumb;
+class WButtonBar;
+class WSearchLineEdit;
class Library : public QObject {
Q_OBJECT
public:
+ enum RemovalType {
+ LeaveTracksUnchanged = 0,
+ HideTracks,
+ PurgeTracks
+ };
+
+ static const int kDefaultRowHeightPx;
+
Library(QObject* parent,
UserSettingsPointer pConfig,
PlayerManagerInterface* pPlayerManager,
RecordingManager* pRecordingManager);
virtual ~Library();
-
- void bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* pKeyboard);
- void bindSidebarWidget(WLibrarySidebar* sidebarWidget);
-
+
+ void bindSearchBar(WSearchLineEdit* searchLine, int id);
+ void bindSidebarWidget(WButtonBar* sidebar);
+ void bindPaneWidget(WLibrary* libraryWidget,
+ KeyboardEventFilter* pKeyboard, int paneId);
+ void bindSidebarExpanded(WBaseLibrary* expandedPane,
+ KeyboardEventFilter* pKeyboard);
+ void bindBreadCrumb(WLibraryBreadCrumb *pBreadCrumb, int paneId);
+
+ void destroyInterface();
+ LibraryView* getActiveView();
+
void addFeature(LibraryFeature* feature);
QStringList getDirs();
+
+ void paneCollapsed(int paneId);
+ void paneUncollapsed(int paneId);
// TODO(rryan) Transitionary only -- the only reason this is here is so the
// waveform widgets can signal to a player to load a track. This can be
@@ -66,24 +92,20 @@ class Library : public QObject {
inline const QFont& getTrackTableFont() const {
return m_trackTableFont;
}
-
- //static Library* buildDefaultLibrary();
-
- enum RemovalType {
- LeaveTracksUnchanged = 0,
- HideTracks,
- PurgeTracks
- };
-
- static const int kDefaultRowHeightPx;
+
+ void switchToFeature(LibraryFeature* pFeature);
+ void showBreadCrumb(TreeItem* pTree);
+ void restoreSearch(const QString& text);
public slots:
- void slotShowTrackModel(QAbstractItemModel* model);
- void slotSwitchToView(const QString& view);
+
+ void slotActivateFeature(LibraryFeature* pFeature);
+ void slotHoverFeature(LibraryFeature* pFeature);
+
+ // Updates the focus from the feature before changing the view
void slotLoadTrack(TrackPointer pTrack);
void slotLoadTrackToPlayer(TrackPointer pTrack, QString group, bool play);
void slotLoadLocationToPlayer(QString location, QString group);
- void slotRestoreSearch(const QString& text);
void slotRefreshLibraryModels();
void slotCreatePlaylist();
void slotCreateCrate();
@@ -93,20 +115,19 @@ class Library : public QObject {
void onSkinLoadFinished();
void slotSetTrackTableFont(const QFont& font);
void slotSetTrackTableRowHeight(int rowHeight);
+ void slotPaneFocused(LibraryPaneManager *pPane);
+
+ // Updates with the focus feature
+ void slotUpdateFocus(LibraryFeature* pFeature);
void scan() {
m_scanner.scan();
}
signals:
- void showTrackModel(QAbstractItemModel* model);
- void switchToView(const QString& view);
void loadTrack(TrackPointer pTrack);
void loadTrackToPlayer(TrackPointer pTrack, QString group, bool play = false);
- void restoreSearch(const QString&);
- void search(const QString& text);
- void searchCleared();
- void searchStarting();
+
// emit this signal to enable/disable the cover art widget
void enableCoverArtDisplay(bool);
void trackSelected(TrackPointer pTrack);
@@ -119,12 +140,19 @@ class Library : public QObject {
void scanFinished();
private:
+
+ // If the pane exists returns it, otherwise it creates the pane
+ LibraryPaneManager *getPane(int paneId);
+ LibraryPaneManager* getFocusedPane();
+
+ void createFeatures(UserSettingsPointer pConfig, PlayerManagerInterface *pPlayerManager);
+ void setFocusedPane();
+
+ void handleFocus();
+
UserSettingsPointer m_pConfig;
SidebarModel* m_pSidebarModel;
TrackCollection* m_pTrackCollection;
- QList m_features;
- const static QString m_sTrackViewName;
- const static QString m_sAutoDJViewName;
MixxxLibraryFeature* m_pMixxxLibraryFeature;
PlaylistFeature* m_pPlaylistFeature;
CrateFeature* m_pCrateFeature;
@@ -134,6 +162,14 @@ class Library : public QObject {
LibraryScanner m_scanner;
QFont m_trackTableFont;
int m_iTrackTableRowHeight;
+
+ QHash m_panes;
+ LibraryPaneManager* m_pSidebarExpanded;
+ QList m_features;
+ QSet m_collapsedPanes;
+
+ // Can be any integer as it's used with a HashMap
+ int m_focusedPane;
};
#endif /* LIBRARY_H */
diff --git a/src/library/librarycontrol.cpp b/src/library/librarycontrol.cpp
index 577b9fac1724..a162fdaa8308 100644
--- a/src/library/librarycontrol.cpp
+++ b/src/library/librarycontrol.cpp
@@ -50,7 +50,6 @@ void LoadToGroupController::slotLoadToGroupAndPlay(double v) {
LibraryControl::LibraryControl(Library* pLibrary)
: QObject(pLibrary),
m_pLibrary(pLibrary),
- m_pLibraryWidget(NULL),
m_pSidebarWidget(NULL),
m_numDecks("[Master]", "num_decks", this),
m_numSamplers("[Master]", "num_samplers", this),
@@ -194,30 +193,13 @@ void LibraryControl::bindSidebarWidget(WLibrarySidebar* pSidebarWidget) {
this, SLOT(sidebarWidgetDeleted()));
}
-void LibraryControl::bindWidget(WLibrary* pLibraryWidget, KeyboardEventFilter* pKeyboard) {
- Q_UNUSED(pKeyboard);
- if (m_pLibraryWidget != NULL) {
- disconnect(m_pLibraryWidget, 0, this, 0);
- }
- m_pLibraryWidget = pLibraryWidget;
- connect(m_pLibraryWidget, SIGNAL(destroyed()),
- this, SLOT(libraryWidgetDeleted()));
-}
-
-void LibraryControl::libraryWidgetDeleted() {
- m_pLibraryWidget = NULL;
-}
-
void LibraryControl::sidebarWidgetDeleted() {
m_pSidebarWidget = NULL;
}
void LibraryControl::slotLoadSelectedTrackToGroup(QString group, bool play) {
- if (m_pLibraryWidget == NULL) {
- return;
- }
- LibraryView* activeView = m_pLibraryWidget->getActiveView();
+ LibraryView* activeView = m_pLibrary->getActiveView();
if (!activeView) {
return;
}
@@ -225,12 +207,9 @@ void LibraryControl::slotLoadSelectedTrackToGroup(QString group, bool play) {
}
void LibraryControl::slotLoadSelectedIntoFirstStopped(double v) {
- if (m_pLibraryWidget == NULL) {
- return;
- }
-
+
if (v > 0) {
- LibraryView* activeView = m_pLibraryWidget->getActiveView();
+ LibraryView* activeView = m_pLibrary->getActiveView();
if (!activeView) {
return;
}
@@ -239,12 +218,8 @@ void LibraryControl::slotLoadSelectedIntoFirstStopped(double v) {
}
void LibraryControl::slotAutoDjAddTop(double v) {
- if (m_pLibraryWidget == NULL) {
- return;
- }
-
if (v > 0) {
- LibraryView* activeView = m_pLibraryWidget->getActiveView();
+ LibraryView* activeView = m_pLibrary->getActiveView();
if (!activeView) {
return;
}
@@ -253,12 +228,8 @@ void LibraryControl::slotAutoDjAddTop(double v) {
}
void LibraryControl::slotAutoDjAddBottom(double v) {
- if (m_pLibraryWidget == NULL) {
- return;
- }
-
if (v > 0) {
- LibraryView* activeView = m_pLibraryWidget->getActiveView();
+ LibraryView* activeView = m_pLibrary->getActiveView();
if (!activeView) {
return;
}
@@ -279,13 +250,9 @@ void LibraryControl::slotSelectPrevTrack(double v) {
}
void LibraryControl::slotSelectTrack(double v) {
- if (m_pLibraryWidget == NULL) {
- return;
- }
-
int i = (int)v;
- LibraryView* activeView = m_pLibraryWidget->getActiveView();
+ LibraryView* activeView = m_pLibrary->getActiveView();
if (!activeView) {
return;
}
diff --git a/src/library/librarycontrol.h b/src/library/librarycontrol.h
index 7b449d9c5a01..2356595e11cc 100644
--- a/src/library/librarycontrol.h
+++ b/src/library/librarycontrol.h
@@ -36,12 +36,10 @@ class LibraryControl : public QObject {
public:
LibraryControl(Library* pLibrary);
virtual ~LibraryControl();
-
- void bindWidget(WLibrary* pLibrary, KeyboardEventFilter* pKeyboard);
+
void bindSidebarWidget(WLibrarySidebar* pLibrarySidebar);
private slots:
- void libraryWidgetDeleted();
void sidebarWidgetDeleted();
void slotLoadSelectedTrackToGroup(QString group, bool play);
void slotSelectNextTrack(double v);
@@ -84,7 +82,6 @@ class LibraryControl : public QObject {
ControlPushButton* m_pFontSizeIncrement;
ControlPushButton* m_pFontSizeDecrement;
- WLibrary* m_pLibraryWidget;
WLibrarySidebar* m_pSidebarWidget;
ControlProxy m_numDecks;
ControlProxy m_numSamplers;
diff --git a/src/library/libraryfeature.cpp b/src/library/libraryfeature.cpp
index 19575cf46235..f35974d0ec53 100644
--- a/src/library/libraryfeature.cpp
+++ b/src/library/libraryfeature.cpp
@@ -1,23 +1,148 @@
// libraryfeature.cpp
// Created 8/17/2009 by RJ Ryan (rryan@mit.edu)
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "library/library.h"
#include "library/libraryfeature.h"
+#include "widget/wbaselibrary.h"
+#include "widget/wlibrarysidebar.h"
+#include "widget/wtracktableview.h"
// KEEP THIS cpp file to tell scons that moc should be called on the class!!!
// The reason for this is that LibraryFeature uses slots/signals and for this
-// to work the code has to be precompiles by moc
-LibraryFeature::LibraryFeature(QObject *parent)
- : QObject(parent) {
+// to work the code has to be precompiled by moc
+LibraryFeature::LibraryFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ TrackCollection* pTrackCollection,
+ QObject* parent)
+ : QObject(parent),
+ m_pConfig(pConfig),
+ m_pLibrary(pLibrary),
+ m_pTrackCollection(pTrackCollection),
+ m_featureFocus(-1) {
+}
+LibraryFeature::~LibraryFeature() {
+
}
-LibraryFeature::LibraryFeature(UserSettingsPointer pConfig, QObject* parent)
- : QObject(parent),
- m_pConfig(pConfig) {
+QWidget* LibraryFeature::createPaneWidget(KeyboardEventFilter* pKeyboard,
+ int paneId) {
+ return createTableWidget(pKeyboard, paneId);
}
-LibraryFeature::~LibraryFeature() {
+QWidget *LibraryFeature::createSidebarWidget(KeyboardEventFilter* pKeyboard) {
+ //qDebug() << "LibraryFeature::bindSidebarWidget";
+ QFrame* pContainer = new QFrame(nullptr);
+ pContainer->setContentsMargins(0,0,0,0);
+
+ QVBoxLayout* pLayout = new QVBoxLayout(pContainer);
+ pLayout->setContentsMargins(0,0,0,0);
+ pLayout->setSpacing(0);
+ pContainer->setLayout(pLayout);
+
+ QLabel* pTitle = new QLabel(title().toString(), pContainer);
+ pLayout->addWidget(pTitle);
+
+ QWidget* pSidebar = createInnerSidebarWidget(pKeyboard);
+ pSidebar->setParent(pContainer);
+ pLayout->addWidget(pSidebar);
+
+ return pContainer;
+}
+
+void LibraryFeature::setFeatureFocus(int focus) {
+ m_featureFocus = focus;
+}
+
+int LibraryFeature::getFeatureFocus() {
+ return m_featureFocus;
+}
+
+void LibraryFeature::setFocusedPane(int paneId) {
+ m_focusedPane = paneId;
+}
+
+WTrackTableView* LibraryFeature::createTableWidget(KeyboardEventFilter* pKeyboard,
+ int paneId) {
+ WTrackTableView* pTrackTableView =
+ new WTrackTableView(nullptr, m_pConfig, m_pTrackCollection);
+
+ pTrackTableView->installEventFilter(pKeyboard);
+
+ connect(pTrackTableView, SIGNAL(loadTrack(TrackPointer)),
+ this, SIGNAL(loadTrack(TrackPointer)));
+ connect(pTrackTableView, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)),
+ this, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)));
+ connect(pTrackTableView, SIGNAL(trackSelected(TrackPointer)),
+ this, SIGNAL(trackSelected(TrackPointer)));
+
+ connect(m_pLibrary, SIGNAL(setTrackTableFont(QFont)),
+ pTrackTableView, SLOT(setTrackTableFont(QFont)));
+ connect(m_pLibrary, SIGNAL(setTrackTableRowHeight(int)),
+ pTrackTableView, SLOT(setTrackTableRowHeight(int)));
+ m_trackTables[paneId] = pTrackTableView;
+
+ return pTrackTableView;
+}
+
+QWidget* LibraryFeature::createInnerSidebarWidget(KeyboardEventFilter *pKeyboard) {
+ return createLibrarySidebarWidget(pKeyboard);
+}
+
+WLibrarySidebar *LibraryFeature::createLibrarySidebarWidget(KeyboardEventFilter *pKeyboard) {
+ WLibrarySidebar* pSidebar = new WLibrarySidebar(nullptr);
+ pSidebar->installEventFilter(pKeyboard);
+ pSidebar->setModel(getChildModel());
+
+ connect(pSidebar, SIGNAL(clicked(const QModelIndex&)),
+ this, SLOT(activateChild(const QModelIndex&)));
+ connect(pSidebar, SIGNAL(doubleClicked(const QModelIndex&)),
+ this, SLOT(onLazyChildExpandation(const QModelIndex&)));
+ connect(pSidebar, SIGNAL(rightClicked(const QPoint&, const QModelIndex&)),
+ this, SLOT(onRightClickChild(const QPoint&, const QModelIndex&)));
+ connect(pSidebar, SIGNAL(expanded(const QModelIndex&)),
+ this, SLOT(onLazyChildExpandation(const QModelIndex&)));
+ return pSidebar;
+}
+
+void LibraryFeature::showTrackModel(QAbstractItemModel *model) {
+ auto it = m_trackTables.find(m_featureFocus);
+ if (it == m_trackTables.end() || it->isNull()) {
+ return;
+ }
+ (*it)->loadTrackModel(model);
+ switchToFeature();
+}
+
+void LibraryFeature::switchToFeature() {
+ m_pLibrary->switchToFeature(this);
+}
+
+void LibraryFeature::restoreSearch(const QString& search) {
+ m_pLibrary->restoreSearch(search);
+}
+
+void LibraryFeature::showBreadCrumb(TreeItem* pTree) {
+ m_pLibrary->showBreadCrumb(pTree);
+}
+WTrackTableView *LibraryFeature::getFocusedTable() {
+ auto it = m_trackTables.find(m_featureFocus);
+ if (it == m_trackTables.end() || it->isNull()) {
+ return nullptr;
+ }
+ return *it;
}
QStringList LibraryFeature::getPlaylistFiles(QFileDialog::FileMode mode) {
@@ -25,15 +150,17 @@ QStringList LibraryFeature::getPlaylistFiles(QFileDialog::FileMode mode) {
ConfigKey("[Library]", "LastImportExportPlaylistDirectory"),
QDesktopServices::storageLocation(QDesktopServices::MusicLocation));
- QFileDialog dialogg(NULL,
- tr("Import Playlist"),
- lastPlaylistDirectory,
- tr("Playlist Files (*.m3u *.m3u8 *.pls *.csv)"));
- dialogg.setAcceptMode(QFileDialog::AcceptOpen);
- dialogg.setFileMode(mode);
- dialogg.setModal(true);
+ QFileDialog dialog(nullptr,
+ tr("Import Playlist"),
+ lastPlaylistDirectory,
+ tr("Playlist Files (*.m3u *.m3u8 *.pls *.csv)"));
+ dialog.setAcceptMode(QFileDialog::AcceptOpen);
+ dialog.setFileMode(mode);
+ dialog.setModal(true);
// If the user refuses return
- if (! dialogg.exec()) return QStringList();
- return dialogg.selectedFiles();
+ if (!dialog.exec()) {
+ return QStringList();
+ }
+ return dialog.selectedFiles();
}
diff --git a/src/library/libraryfeature.h b/src/library/libraryfeature.h
index f750bf6cda16..e9c0b647cf56 100644
--- a/src/library/libraryfeature.h
+++ b/src/library/libraryfeature.h
@@ -4,113 +4,141 @@
#ifndef LIBRARYFEATURE_H
#define LIBRARYFEATURE_H
-#include
-#include
-#include
-#include
+#include
+#include
+#include
#include
-#include
-#include
#include
-#include
-#include
-#include "track/track.h"
-#include "treeitemmodel.h"
+#include "controllers/keyboard/keyboardeventfilter.h"
#include "library/coverartcache.h"
#include "library/dao/trackdao.h"
+#include "preferences/usersettings.h"
+#include "track/track.h"
+#include "treeitemmodel.h"
+class Library;
+class TrackCollection;
class TrackModel;
-class WLibrarySidebar;
+class WBaseLibrary;
class WLibrary;
-class KeyboardEventFilter;
+class WLibrarySidebar;
+class WTrackTableView;
// pure virtual (abstract) class to provide an interface for libraryfeatures
class LibraryFeature : public QObject {
- Q_OBJECT
+ Q_OBJECT
public:
- LibraryFeature(QObject* parent = NULL);
+ // The parent does not necessary be the Library
LibraryFeature(UserSettingsPointer pConfig,
- QObject* parent = NULL);
+ Library* pLibrary, TrackCollection *pTrackCollection,
+ QObject* parent = nullptr);
+
virtual ~LibraryFeature();
virtual QVariant title() = 0;
virtual QIcon getIcon() = 0;
- virtual bool dropAccept(QList urls, QObject* pSource) {
- Q_UNUSED(urls);
- Q_UNUSED(pSource);
+ virtual bool dropAccept(QList /* urls */,
+ QObject* /* pSource */) {
return false;
}
- virtual bool dropAcceptChild(const QModelIndex& index,
- QList urls, QObject* pSource) {
- Q_UNUSED(index);
- Q_UNUSED(urls);
- Q_UNUSED(pSource);
+ virtual bool dropAcceptChild(const QModelIndex& /* index */,
+ QList /* urls */,
+ QObject* /* pSource */) {
return false;
}
- virtual bool dragMoveAccept(QUrl url) {
- Q_UNUSED(url);
+ virtual bool dragMoveAccept(QUrl /* url */) {
return false;
}
- virtual bool dragMoveAcceptChild(const QModelIndex& index, QUrl url) {
- Q_UNUSED(index);
- Q_UNUSED(url);
+ virtual bool dragMoveAcceptChild(const QModelIndex& /* index */,
+ QUrl /* url */) {
return false;
}
-
- // Reimplement this to register custom views with the library widget.
- virtual void bindWidget(WLibrary* /* libraryWidget */,
- KeyboardEventFilter* /* keyboard */) {}
+
+ // Reimplement this to register custom views with the library widget
+ // at the right pane.
+ virtual QWidget* createPaneWidget(KeyboardEventFilter* pKeyboard,
+ int paneId);
+
+ // Reimplement this to register custom views with the library widget,
+ // at the sidebar expanded pane
+ virtual QWidget* createSidebarWidget(KeyboardEventFilter* pKeyboard);
+
virtual TreeItemModel* getChildModel() = 0;
-
- protected:
- inline QStringList getPlaylistFiles() { return getPlaylistFiles(QFileDialog::ExistingFiles); }
- inline QString getPlaylistFile() { return getPlaylistFiles(QFileDialog::ExistingFile).first(); }
- UserSettingsPointer m_pConfig;
+
+ virtual void setFeatureFocus(int focus);
+ virtual int getFeatureFocus();
+
+ virtual void setFocusedPane(int paneId);
public slots:
// called when you single click on the root item
virtual void activate() = 0;
// called when you single click on a child item, e.g., a concrete playlist or crate
- virtual void activateChild(const QModelIndex& index) {
- Q_UNUSED(index);
+ virtual void activateChild(const QModelIndex&) {
}
// called when you right click on the root item
- virtual void onRightClick(const QPoint& globalPos) {
- Q_UNUSED(globalPos);
+ virtual void onRightClick(const QPoint&) {
}
// called when you right click on a child item, e.g., a concrete playlist or crate
- virtual void onRightClickChild(const QPoint& globalPos, QModelIndex index) {
- Q_UNUSED(globalPos);
- Q_UNUSED(index);
+ virtual void onRightClickChild(const QPoint& /* globalPos */,
+ QModelIndex /* index */) {
}
// Only implement this, if using incremental or lazy childmodels, see BrowseFeature.
// This method is executed whenever you **double** click child items
- virtual void onLazyChildExpandation(const QModelIndex& index) {
- Q_UNUSED(index);
+ virtual void onLazyChildExpandation(const QModelIndex&) {
}
+
signals:
- void showTrackModel(QAbstractItemModel* model);
- void switchToView(const QString& view);
- void loadTrack(TrackPointer pTrack);
+
+ void loadTrack(TrackPointer);
void loadTrackToPlayer(TrackPointer pTrack, QString group, bool play = false);
- void restoreSearch(const QString&);
// emit this signal before you parse a large music collection, e.g., iTunes, Traktor.
// The second arg indicates if the feature should be "selected" when loading starts
void featureIsLoading(LibraryFeature*, bool selectFeature);
// emit this signal if the foreign music collection has been imported/parsed.
- void featureLoadingFinished(LibraryFeature*s);
+ void featureLoadingFinished(LibraryFeature*);
// emit this signal to select pFeature
void featureSelect(LibraryFeature* pFeature, const QModelIndex& index);
// emit this signal to enable/disable the cover art widget
void enableCoverArtDisplay(bool);
- void trackSelected(TrackPointer pTrack);
+ void trackSelected(TrackPointer);
+
+ protected:
+ inline QStringList getPlaylistFiles() { return getPlaylistFiles(QFileDialog::ExistingFiles); }
+ inline QString getPlaylistFile() { return getPlaylistFiles(QFileDialog::ExistingFile).first(); }
+
+ // Creates a table widget with no model
+ WTrackTableView* createTableWidget(KeyboardEventFilter* pKeyboard,
+ int paneId);
+
+ // Creates a WLibrarySidebar widget with the getChildModel() function as
+ // model
+ WLibrarySidebar* createLibrarySidebarWidget(KeyboardEventFilter* pKeyboard);
+
+ // Override this function to create a custom inner widget for the sidebar,
+ // the default widget is a WLibrarySidebar widget
+ virtual QWidget* createInnerSidebarWidget(KeyboardEventFilter* pKeyboard);
+
+ void showTrackModel(QAbstractItemModel *model);
+ void switchToFeature();
+ void restoreSearch(const QString& search);
+ void showBreadCrumb(TreeItem *pTree);
+
+ WTrackTableView* getFocusedTable();
+
+ UserSettingsPointer m_pConfig;
+ Library* m_pLibrary;
+ TrackCollection* m_pTrackCollection;
+
+ int m_featureFocus;
+ int m_focusedPane;
private:
QStringList getPlaylistFiles(QFileDialog::FileMode mode);
-
+ QHash > m_trackTables;
};
#endif /* LIBRARYFEATURE_H */
diff --git a/src/library/librarypanemanager.cpp b/src/library/librarypanemanager.cpp
new file mode 100644
index 000000000000..34c59a935700
--- /dev/null
+++ b/src/library/librarypanemanager.cpp
@@ -0,0 +1,155 @@
+#include
+
+#include "library/libraryfeature.h"
+#include "library/library.h"
+#include "library/librarypanemanager.h"
+#include "util/assert.h"
+#include "widget/wbuttonbar.h"
+#include "widget/wlibrarybreadcrumb.h"
+#include "widget/wtracktableview.h"
+
+LibraryPaneManager::LibraryPaneManager(int paneId, Library *pLibrary, QObject* parent)
+ : QObject(parent),
+ m_pPaneWidget(nullptr),
+ m_pBreadCrumb(nullptr),
+ m_paneId(paneId),
+ m_pLibrary(pLibrary) {
+ qApp->installEventFilter(this);
+}
+
+LibraryPaneManager::~LibraryPaneManager() {
+}
+
+void LibraryPaneManager::bindPaneWidget(WBaseLibrary* pLibraryWidget,
+ KeyboardEventFilter* pKeyboard) {
+ //qDebug() << "LibraryPaneManager::bindLibraryWidget" << libraryWidget;
+ m_pPaneWidget = pLibraryWidget;
+
+ connect(m_pPaneWidget, SIGNAL(focused()),
+ this, SLOT(slotPaneFocused()));
+ connect(m_pPaneWidget, SIGNAL(collapsed()),
+ this, SLOT(slotPaneCollapsed()));
+ connect(m_pPaneWidget, SIGNAL(uncollapsed()),
+ this, SLOT(slotPaneUncollapsed()));
+
+ WLibrary* lib = qobject_cast(m_pPaneWidget);
+ if (lib == nullptr) {
+ return;
+ }
+ for (LibraryFeature* f : m_features) {
+ //f->bindPaneWidget(lib, pKeyboard, m_paneId);
+
+ QWidget* pPane = f->createPaneWidget(pKeyboard, m_paneId);
+ if (pPane == nullptr) {
+ continue;
+ }
+ pPane->setParent(lib);
+ lib->registerView(f, pPane);
+ }
+}
+
+void LibraryPaneManager::bindSearchBar(WSearchLineEdit* pSearchBar) {
+ pSearchBar->installEventFilter(this);
+
+ connect(pSearchBar, SIGNAL(search(const QString&)),
+ this, SIGNAL(search(const QString&)));
+ connect(pSearchBar, SIGNAL(searchCleared()),
+ this, SIGNAL(searchCleared()));
+ connect(pSearchBar, SIGNAL(searchStarting()),
+ this, SIGNAL(searchStarting()));
+
+ m_pSearchBar = pSearchBar;
+}
+
+void LibraryPaneManager::setBreadCrumb(WLibraryBreadCrumb *pBreadCrumb) {
+ m_pBreadCrumb = pBreadCrumb;
+}
+
+void LibraryPaneManager::addFeature(LibraryFeature* feature) {
+ DEBUG_ASSERT_AND_HANDLE(feature) {
+ return;
+ }
+
+ m_features.append(feature);
+}
+
+void LibraryPaneManager::addFeatures(const QList& features) {
+ m_features.append(features);
+}
+
+WBaseLibrary* LibraryPaneManager::getPaneWidget() {
+ return m_pPaneWidget;
+}
+
+void LibraryPaneManager::setCurrentFeature(LibraryFeature* pFeature) {
+ m_pCurrentFeature = pFeature;
+}
+
+LibraryFeature *LibraryPaneManager::getCurrentFeature() const {
+ return m_pCurrentFeature;
+}
+
+void LibraryPaneManager::setFocus() {
+ //qDebug() << "LibraryPaneManager::setFocus";
+ DEBUG_ASSERT_AND_HANDLE(m_pPaneWidget) {
+ return;
+ }
+
+ m_pPaneWidget->setProperty("showFocus", 1);
+}
+
+void LibraryPaneManager::clearFocus() {
+ //qDebug() << "LibraryPaneManager::clearFocus";
+ m_pPaneWidget->setProperty("showFocus", 0);
+}
+
+void LibraryPaneManager::switchToFeature(LibraryFeature* pFeature) {
+ DEBUG_ASSERT_AND_HANDLE(!m_pPaneWidget.isNull() && pFeature) {
+ return;
+ }
+
+ m_pCurrentFeature = pFeature;
+ m_pPaneWidget->switchToFeature(pFeature);
+}
+
+void LibraryPaneManager::restoreSearch(const QString& text) {
+ if (!m_pSearchBar.isNull()) {
+ m_pSearchBar->restoreSearch(text);
+ }
+}
+
+void LibraryPaneManager::showBreadCrumb(TreeItem *pTree) {
+ DEBUG_ASSERT_AND_HANDLE(!m_pBreadCrumb.isNull()) {
+ return;
+ }
+
+ m_pBreadCrumb->showBreadCrumb(pTree);
+}
+
+void LibraryPaneManager::slotPaneCollapsed() {
+ m_pLibrary->paneCollapsed(m_paneId);
+}
+
+void LibraryPaneManager::slotPaneUncollapsed() {
+ m_pLibrary->paneUncollapsed(m_paneId);
+}
+
+void LibraryPaneManager::slotPaneFocused() {
+ m_pLibrary->slotPaneFocused(this);
+}
+
+bool LibraryPaneManager::eventFilter(QObject*, QEvent* event) {
+ if (m_pPaneWidget.isNull()) {
+ return false;
+ }
+
+ if (event->type() == QEvent::MouseButtonPress &&
+ m_pPaneWidget->underMouse()) {
+ m_pLibrary->slotPaneFocused(this);
+ }
+
+ // Since this event filter is for the entire application (to handle the
+ // mouse event), NEVER return true. If true is returned I will block all
+ // application events and will block the entire application.
+ return false;
+}
diff --git a/src/library/librarypanemanager.h b/src/library/librarypanemanager.h
new file mode 100644
index 000000000000..f5a6d412ddf2
--- /dev/null
+++ b/src/library/librarypanemanager.h
@@ -0,0 +1,84 @@
+#ifndef LIBRARYVIEWMANAGER_H
+#define LIBRARYVIEWMANAGER_H
+
+#include
+#include
+
+#include "widget/wlibrary.h"
+#include "widget/wsearchlineedit.h"
+#include "widget/wtracktableview.h"
+
+class LibraryFeature;
+class WButtonBar;
+class WLibraryBreadCrumb;
+class TreeItem;
+class Library;
+
+class LibraryPaneManager : public QObject {
+ Q_OBJECT
+
+ public:
+
+ LibraryPaneManager(int paneId, Library* pLibrary, QObject* parent = nullptr);
+
+ ~LibraryPaneManager();
+
+ bool initialize();
+
+ // All features must be added before adding a pane
+ virtual void bindPaneWidget(WBaseLibrary* pLibraryWidget,
+ KeyboardEventFilter* pKeyboard);
+ void bindSearchBar(WSearchLineEdit* pSearchBar);
+ void setBreadCrumb(WLibraryBreadCrumb* pBreadCrumb);
+
+ void addFeature(LibraryFeature* feature);
+ void addFeatures(const QList& features);
+
+ WBaseLibrary* getPaneWidget();
+
+ void setCurrentFeature(LibraryFeature* pFeature);
+ LibraryFeature* getCurrentFeature() const;
+
+ void setFocus();
+ void clearFocus();
+
+ void restoreSearch(const QString& text);
+ void switchToFeature(LibraryFeature* pFeature);
+ void showBreadCrumb(TreeItem* pTree);
+
+ inline int getPaneId() {
+ return m_paneId;
+ }
+
+ signals:
+
+ void search(const QString& text);
+ void searchCleared();
+ void searchStarting();
+
+ public slots:
+
+ void slotPaneCollapsed();
+ void slotPaneUncollapsed();
+ void slotPaneFocused();
+
+ protected:
+
+ QPointer m_pPaneWidget;
+ QList m_features;
+ QPointer m_pBreadCrumb;
+ QPointer m_pSearchBar;
+
+ private:
+
+ LibraryFeature* m_pCurrentFeature;
+ int m_paneId;
+ Library* m_pLibrary;
+
+ private slots:
+
+ // Used to handle focus change
+ bool eventFilter(QObject*, QEvent* event);
+};
+
+#endif // LIBRARYVIEWMANAGER_H
diff --git a/src/library/librarysidebarexpandedmanager.cpp b/src/library/librarysidebarexpandedmanager.cpp
new file mode 100644
index 000000000000..60da9906c79f
--- /dev/null
+++ b/src/library/librarysidebarexpandedmanager.cpp
@@ -0,0 +1,23 @@
+#include "librarysidebarexpandedmanager.h"
+#include "library/libraryfeature.h"
+
+LibrarySidebarExpandedManager::LibrarySidebarExpandedManager(Library *pLibrary,
+ QObject* parent)
+ : LibraryPaneManager(-1, pLibrary, parent) {
+
+}
+
+void LibrarySidebarExpandedManager::bindPaneWidget(WBaseLibrary* sidebarWidget,
+ KeyboardEventFilter* pKeyboard) {
+ m_pPaneWidget = sidebarWidget;
+
+ for (LibraryFeature* f : m_features) {
+ QWidget* pPane = f->createSidebarWidget(pKeyboard);
+ if (pPane == nullptr) {
+ continue;
+ }
+ pPane->setParent(sidebarWidget);
+ sidebarWidget->registerView(f, pPane);
+ }
+}
+
diff --git a/src/library/librarysidebarexpandedmanager.h b/src/library/librarysidebarexpandedmanager.h
new file mode 100644
index 000000000000..7a29eb9ada91
--- /dev/null
+++ b/src/library/librarysidebarexpandedmanager.h
@@ -0,0 +1,14 @@
+#ifndef LIBRARYSIDEBAREXPANDEDMANAGER_H
+#define LIBRARYSIDEBAREXPANDEDMANAGER_H
+#include "library/librarypanemanager.h"
+
+class LibrarySidebarExpandedManager : public LibraryPaneManager
+{
+ public:
+ LibrarySidebarExpandedManager(Library* pLibrary, QObject* parent = nullptr);
+
+ void bindPaneWidget(WBaseLibrary* sidebarWidget,
+ KeyboardEventFilter* pKeyboard) override;
+};
+
+#endif // LIBRARYSIDEBAREXPANDEDMANAGER_H
diff --git a/src/library/libraryview.h b/src/library/libraryview.h
index 5ae34aee2fe6..5eab3c40ec49 100644
--- a/src/library/libraryview.h
+++ b/src/library/libraryview.h
@@ -11,7 +11,7 @@
class LibraryView {
public:
- virtual ~LibraryView() {};
+ virtual ~LibraryView() {}
virtual void onShow() = 0;
// reimplement if LibraryView should be able to search
@@ -19,10 +19,10 @@ class LibraryView {
// If applicable, requests that the LibraryView load the selected
// track. Does nothing otherwise.
- virtual void loadSelectedTrack() {};
+ virtual void loadSelectedTrack() {}
- virtual void slotSendToAutoDJ() {};
- virtual void slotSendToAutoDJTop() {};
+ virtual void slotSendToAutoDJ() {}
+ virtual void slotSendToAutoDJTop() {}
// If applicable, requests that the LibraryView load the selected track to
// the specified group. Does nothing otherwise.
diff --git a/src/library/mixxxlibraryfeature.cpp b/src/library/mixxxlibraryfeature.cpp
index 60271e3a38e0..f485bcafad17 100644
--- a/src/library/mixxxlibraryfeature.cpp
+++ b/src/library/mixxxlibraryfeature.cpp
@@ -13,24 +13,34 @@
#include "library/hiddentablemodel.h"
#include "library/queryutil.h"
#include "library/trackcollection.h"
+#include "library/dlghidden.h"
+#include "library/dlgmissing.h"
#include "treeitem.h"
#include "sources/soundsourceproxy.h"
#include "widget/wlibrary.h"
+#include "widget/wlibrarystack.h"
+#include "widget/wlibrarysidebar.h"
#include "util/dnd.h"
-#include "library/dlghidden.h"
-#include "library/dlgmissing.h"
-MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary,
- TrackCollection* pTrackCollection,
- UserSettingsPointer pConfig)
- : LibraryFeature(pLibrary),
- kMissingTitle(tr("Missing Tracks")),
+MixxxLibraryFeature::MixxxLibraryFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection)
+ : LibraryFeature(pConfig, pLibrary, pTrackCollection, parent),
+ kLibraryTitle(tr("Library")),
kHiddenTitle(tr("Hidden Tracks")),
- m_pLibrary(pLibrary),
- m_pMissingView(NULL),
- m_pHiddenView(NULL),
+ kMissingTitle(tr("Missing Tracks")),
+ m_pHiddenView(nullptr),
+ m_pMissingView(nullptr),
+ m_idExpandedHidden(-1),
+ m_idExpandedMissing(-1),
+ m_idExpandedControls(-1),
+ m_idExpandedTree(-1),
+ m_pHiddenTableModel(nullptr),
+ m_pMissingTableModel(nullptr),
+ m_pExpandedStack(nullptr),
+ m_pSidebarTab(nullptr),
m_trackDao(pTrackCollection->getTrackDAO()),
- m_pConfig(pConfig),
m_pTrackCollection(pTrackCollection) {
QStringList columns;
columns << "library." + LIBRARYTABLE_ID
@@ -109,10 +119,16 @@ MixxxLibraryFeature::MixxxLibraryFeature(Library* pLibrary,
m_pLibraryTableModel = new LibraryTableModel(this, pTrackCollection, "mixxx.db.model.library");
TreeItem* pRootItem = new TreeItem();
+ pRootItem->setLibraryFeature(this);
+
+ TreeItem* pLibraryChildItem = new TreeItem(kLibraryTitle, kLibraryTitle,
+ this, pRootItem);
+ pLibraryChildItem->setIcon(getIcon());
TreeItem* pmissingChildItem = new TreeItem(kMissingTitle, kMissingTitle,
this, pRootItem);
TreeItem* phiddenChildItem = new TreeItem(kHiddenTitle, kHiddenTitle,
this, pRootItem);
+ pRootItem->appendChild(pLibraryChildItem);
pRootItem->appendChild(pmissingChildItem);
pRootItem->appendChild(phiddenChildItem);
@@ -123,23 +139,53 @@ MixxxLibraryFeature::~MixxxLibraryFeature() {
delete m_pLibraryTableModel;
}
-void MixxxLibraryFeature::bindWidget(WLibrary* pLibraryWidget,
- KeyboardEventFilter* pKeyboard) {
- m_pHiddenView = new DlgHidden(pLibraryWidget, m_pConfig, m_pLibrary,
- m_pTrackCollection, pKeyboard);
- pLibraryWidget->registerView(kHiddenTitle, m_pHiddenView);
- connect(m_pHiddenView, SIGNAL(trackSelected(TrackPointer)),
- this, SIGNAL(trackSelected(TrackPointer)));
+QWidget *MixxxLibraryFeature::createPaneWidget(KeyboardEventFilter* pKeyboard,
+ int paneId) {
+ WTrackTableView* pTable = LibraryFeature::createTableWidget(pKeyboard, paneId);
+
+ connect(this, SIGNAL(unhideHidden()), pTable, SLOT(slotUnhide()));
+ connect(this, SIGNAL(purgeHidden()), pTable, SLOT(slotPurge()));
+ connect(this, SIGNAL(purgeMissing()), pTable, SLOT(slotPurge()));
+
+ return pTable;
+}
+
+QWidget* MixxxLibraryFeature::createInnerSidebarWidget(KeyboardEventFilter* pKeyboard) {
+ m_pSidebarTab = new QTabWidget(nullptr);
+
+ // Create tree
+ WLibrarySidebar* pSidebar = createLibrarySidebarWidget(pKeyboard);
+ m_idExpandedTree = m_pSidebarTab->addTab(pSidebar, tr("Tree"));
+
+ // Create tabs
+ m_pExpandedStack = new QStackedWidget(m_pSidebarTab);
+
+ // Create Hidden View controls
+ m_pHiddenView = new DlgHidden(pSidebar);
+ m_pHiddenView->setTableModel(getHiddenTableModel());
+ m_pHiddenView->installEventFilter(pKeyboard);
+
+ connect(m_pHiddenView, SIGNAL(unhide()), this, SIGNAL(unhideHidden()));
+ connect(m_pHiddenView, SIGNAL(purge()), this, SIGNAL(purgeHidden()));
+ connect(m_pHiddenView, SIGNAL(selectAll()), this, SLOT(selectAll()));
+ m_idExpandedHidden = m_pExpandedStack->addWidget(m_pHiddenView);
- m_pMissingView = new DlgMissing(pLibraryWidget, m_pConfig, m_pLibrary,
- m_pTrackCollection, pKeyboard);
- pLibraryWidget->registerView(kMissingTitle, m_pMissingView);
- connect(m_pMissingView, SIGNAL(trackSelected(TrackPointer)),
- this, SIGNAL(trackSelected(TrackPointer)));
+ // Create Missing View controls
+ m_pMissingView = new DlgMissing(pSidebar);
+ m_pMissingView->setTableModel(getMissingTableModel());
+ m_pMissingView->installEventFilter(pKeyboard);
+
+ connect(m_pMissingView, SIGNAL(purge()), this, SIGNAL(purgeMissing()));
+ connect(m_pMissingView, SIGNAL(selectAll()), this, SLOT(selectAll()));
+ m_idExpandedMissing = m_pExpandedStack->addWidget(m_pMissingView);
+
+ m_idExpandedControls = m_pSidebarTab->addTab(m_pExpandedStack, tr("Controls"));
+
+ return m_pSidebarTab;
}
QVariant MixxxLibraryFeature::title() {
- return tr("Library");
+ return kLibraryTitle;
}
QIcon MixxxLibraryFeature::getIcon() {
@@ -154,23 +200,117 @@ void MixxxLibraryFeature::refreshLibraryModels() {
if (m_pLibraryTableModel) {
m_pLibraryTableModel->select();
}
- if (m_pMissingView) {
+ if (!m_pMissingView.isNull()) {
m_pMissingView->onShow();
}
- if (m_pHiddenView) {
+ if (!m_pHiddenView.isNull()) {
m_pHiddenView->onShow();
}
}
+void MixxxLibraryFeature::selectionChanged(const QItemSelection&,
+ const QItemSelection&) {
+ WTrackTableView* pTable = getFocusedTable();
+ if (pTable == nullptr) {
+ return;
+ }
+
+ auto it = m_idPaneCurrent.find(m_featureFocus);
+ if (it == m_idPaneCurrent.end()) {
+ return;
+ }
+
+ const QModelIndexList& selection = pTable->selectionModel()->selectedIndexes();
+ switch (*it) {
+ case Panes::Hidden:
+ m_pHiddenView->setSelectedIndexes(selection);
+ break;
+ case Panes::Missing:
+ m_pMissingView->setSelectedIndexes(selection);
+ break;
+ default:
+ break;
+ }
+}
+
+void MixxxLibraryFeature::selectAll() {
+ QPointer pTable = getFocusedTable();
+ if (!pTable.isNull()) {
+ pTable->selectAll();
+ }
+}
+
+
void MixxxLibraryFeature::activate() {
- qDebug() << "MixxxLibraryFeature::activate()";
- emit(showTrackModel(m_pLibraryTableModel));
+ //qDebug() << "MixxxLibraryFeature::activate()";
+
+ m_idPaneCurrent[m_featureFocus] = Panes::MixxxLibrary;
+ QPointer pTable = getFocusedTable();
+ if (pTable.isNull()) {
+ return;
+ }
+
+ m_pSidebarTab->setTabEnabled(m_idExpandedControls, false);
+ pTable->setSortingEnabled(true);
+ showTrackModel(m_pLibraryTableModel);
+ m_pLibrary->restoreSearch("");
+ m_pLibrary->showBreadCrumb(m_childModel.getItem(QModelIndex()));
+
emit(enableCoverArtDisplay(true));
}
void MixxxLibraryFeature::activateChild(const QModelIndex& index) {
- QString itemName = index.data().toString();
- emit(switchToView(itemName));
+ QString itemName = index.data(TreeItemModel::kDataPathRole).toString();
+ TreeItem* pTree = static_cast (index.internalPointer());
+ QPointer pTable = getFocusedTable();
+
+ if (itemName == kLibraryTitle) {
+ activate();
+ return;
+ }
+
+ DEBUG_ASSERT_AND_HANDLE(!m_pExpandedStack.isNull() && !pTable.isNull()) {
+ return;
+ }
+ pTable->setSortingEnabled(false);
+
+ if (itemName == kHiddenTitle) {
+ DEBUG_ASSERT_AND_HANDLE(!m_pHiddenView.isNull()) {
+ return;
+ }
+
+ m_idPaneCurrent[m_featureFocus] = Panes::Hidden;
+ pTable->loadTrackModel(getHiddenTableModel());
+
+ m_pHiddenView->onShow();
+ m_pExpandedStack->setCurrentIndex(m_idExpandedHidden);
+
+ } else if (itemName == kMissingTitle) {
+ DEBUG_ASSERT_AND_HANDLE(!m_pMissingView.isNull()) {
+ return;
+ }
+
+ m_idPaneCurrent[m_featureFocus] = Panes::Missing;
+ pTable->loadTrackModel(getMissingTableModel());
+
+ m_pMissingView->onShow();
+ m_pExpandedStack->setCurrentIndex(m_idExpandedMissing);
+ } else {
+ return;
+ }
+
+ // This is the only way to get the selection signal changing the track
+ // models, every time the model changes the selection model changes too
+ // so we need to reconnect
+ connect(pTable->selectionModel(),
+ SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)),
+ this,
+ SLOT(selectionChanged(const QItemSelection&, const QItemSelection&)));
+
+ m_pSidebarTab->setTabEnabled(m_idExpandedControls, true);
+ switchToFeature();
+ m_pLibrary->restoreSearch("");
+ m_pLibrary->showBreadCrumb(pTree);
emit(enableCoverArtDisplay(true));
}
@@ -190,3 +330,17 @@ bool MixxxLibraryFeature::dragMoveAccept(QUrl url) {
return SoundSourceProxy::isUrlSupported(url) ||
Parser::isPlaylistFilenameSupported(url.toLocalFile());
}
+
+HiddenTableModel* MixxxLibraryFeature::getHiddenTableModel() {
+ if (m_pHiddenTableModel.isNull()) {
+ m_pHiddenTableModel = new HiddenTableModel(this, m_pTrackCollection);
+ }
+ return m_pHiddenTableModel;
+}
+
+MissingTableModel* MixxxLibraryFeature::getMissingTableModel() {
+ if (m_pMissingTableModel.isNull()) {
+ m_pMissingTableModel = new MissingTableModel(this, m_pTrackCollection);
+ }
+ return m_pMissingTableModel;
+}
diff --git a/src/library/mixxxlibraryfeature.h b/src/library/mixxxlibraryfeature.h
index 54d0a14f51e8..460e8b5a0b6f 100644
--- a/src/library/mixxxlibraryfeature.h
+++ b/src/library/mixxxlibraryfeature.h
@@ -10,9 +10,10 @@
#include
#include
#include
-#include
#include
-#include
+#include
+#include
+#include
#include "library/libraryfeature.h"
#include "library/dao/trackdao.h"
@@ -25,39 +26,78 @@ class Library;
class BaseTrackCache;
class LibraryTableModel;
class TrackCollection;
+class WTrackTableView;
+class HiddenTableModel;
+class MissingTableModel;
class MixxxLibraryFeature : public LibraryFeature {
Q_OBJECT
- public:
- MixxxLibraryFeature(Library* pLibrary,
- TrackCollection* pTrackCollection,
- UserSettingsPointer pConfig);
+
+ public:
+ MixxxLibraryFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection);
virtual ~MixxxLibraryFeature();
QVariant title();
QIcon getIcon();
+
bool dropAccept(QList urls, QObject* pSource);
bool dragMoveAccept(QUrl url);
TreeItemModel* getChildModel();
- void bindWidget(WLibrary* pLibrary,
- KeyboardEventFilter* pKeyboard);
+
+ QWidget* createPaneWidget(KeyboardEventFilter*pKeyboard, int paneId) override;
+ QWidget* createInnerSidebarWidget(KeyboardEventFilter* pKeyboard) override;
public slots:
void activate();
void activateChild(const QModelIndex& index);
void refreshLibraryModels();
+
+ void selectionChanged(const QItemSelection&, const QItemSelection&);
+
+ void selectAll();
+
+
+ signals:
+ void unhideHidden();
+ void purgeHidden();
+ void purgeMissing();
private:
- const QString kMissingTitle;
+ enum Panes {
+ MixxxLibrary = 1,
+ Hidden = 2,
+ Missing = 3
+ };
+
+ HiddenTableModel* getHiddenTableModel();
+ MissingTableModel* getMissingTableModel();
+
+ const QString kLibraryTitle;
const QString kHiddenTitle;
- Library* m_pLibrary;
+ const QString kMissingTitle;
+ QPointer m_pHiddenView;
+ QPointer m_pMissingView;
+ QHash m_idPaneCurrent;
+
+ // SidebarExpanded pane's ids
+ int m_idExpandedHidden;
+ int m_idExpandedMissing;
+ int m_idExpandedControls;
+ int m_idExpandedTree;
+
+ QPointer m_pHiddenTableModel;
+ QPointer m_pMissingTableModel;
+
+ QPointer m_pExpandedStack;
+ QPointer m_pSidebarTab;
+
QSharedPointer m_pBaseTrackCache;
LibraryTableModel* m_pLibraryTableModel;
- DlgMissing* m_pMissingView;
- DlgHidden* m_pHiddenView;
TreeItemModel m_childModel;
TrackDAO& m_trackDao;
- UserSettingsPointer m_pConfig;
TrackCollection* m_pTrackCollection;
};
diff --git a/src/library/playlistfeature.cpp b/src/library/playlistfeature.cpp
index fff0ed5bfbb9..2d99850a8e4c 100644
--- a/src/library/playlistfeature.cpp
+++ b/src/library/playlistfeature.cpp
@@ -18,14 +18,11 @@
#include "util/dnd.h"
#include "util/duration.h"
-PlaylistFeature::PlaylistFeature(QObject* parent,
- TrackCollection* pTrackCollection,
- UserSettingsPointer pConfig)
- : BasePlaylistFeature(parent, pConfig, pTrackCollection,
- "PLAYLISTHOME") {
- m_pPlaylistTableModel = new PlaylistTableModel(this, pTrackCollection,
- "mixxx.db.model.playlist");
-
+PlaylistFeature::PlaylistFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection)
+ : BasePlaylistFeature(pConfig, pLibrary, parent, pTrackCollection) {
//construct child model
TreeItem *rootItem = new TreeItem();
m_childModel.setRootItem(rootItem);
@@ -47,7 +44,7 @@ void PlaylistFeature::onRightClick(const QPoint& globalPos) {
m_lastRightClickedIndex = QModelIndex();
//Create the right-click menu
- QMenu menu(NULL);
+ QMenu menu(nullptr);
menu.addAction(m_pCreatePlaylistAction);
menu.addSeparator();
menu.addAction(m_pCreateImportPlaylistAction);
@@ -85,6 +82,13 @@ void PlaylistFeature::onRightClickChild(const QPoint& globalPos, QModelIndex ind
menu.exec(globalPos);
}
+
+bool PlaylistFeature::dragMoveAccept(QUrl url) {
+ return SoundSourceProxy::isUrlSupported(url) ||
+ Parser::isPlaylistFilenameSupported(url.toLocalFile());
+}
+
+
bool PlaylistFeature::dropAcceptChild(const QModelIndex& index, QList urls,
QObject* pSource) {
int playlistId = playlistIdFromIndex(index);
@@ -182,6 +186,10 @@ void PlaylistFeature::decorateChild(TreeItem* item, int playlist_id) {
}
}
+PlaylistTableModel* PlaylistFeature::constructTableModel() {
+ return new PlaylistTableModel(this, m_pTrackCollection, "mixxx.db.model.playlist");
+}
+
void PlaylistFeature::slotPlaylistTableChanged(int playlistId) {
if (!m_pPlaylistTableModel) {
return;
diff --git a/src/library/playlistfeature.h b/src/library/playlistfeature.h
index 0d129eff74b3..a049d9c0987b 100644
--- a/src/library/playlistfeature.h
+++ b/src/library/playlistfeature.h
@@ -20,13 +20,16 @@ class TreeItem;
class PlaylistFeature : public BasePlaylistFeature {
Q_OBJECT
public:
- PlaylistFeature(QObject* parent, TrackCollection* pTrackCollection,
- UserSettingsPointer pConfig);
+ PlaylistFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection);
virtual ~PlaylistFeature();
QVariant title();
QIcon getIcon();
+ bool dragMoveAccept(QUrl url);
bool dropAcceptChild(const QModelIndex& index, QList urls, QObject* pSource);
bool dragMoveAcceptChild(const QModelIndex& index, QUrl url);
@@ -42,6 +45,7 @@ class PlaylistFeature : public BasePlaylistFeature {
protected:
void buildPlaylistList();
void decorateChild(TreeItem *pChild, int playlist_id);
+ PlaylistTableModel* constructTableModel();
private:
QString getRootViewHtml() const;
diff --git a/src/library/recording/dlgrecording.cpp b/src/library/recording/dlgrecording.cpp
index 019a4c32b186..77c22d42d945 100644
--- a/src/library/recording/dlgrecording.cpp
+++ b/src/library/recording/dlgrecording.cpp
@@ -8,29 +8,16 @@
#include "widget/wtracktableview.h"
#include "util/assert.h"
-DlgRecording::DlgRecording(QWidget* parent, UserSettingsPointer pConfig,
- Library* pLibrary, TrackCollection* pTrackCollection,
- RecordingManager* pRecordingManager, KeyboardEventFilter* pKeyboard)
- : QWidget(parent),
- m_pConfig(pConfig),
+DlgRecording::DlgRecording(QWidget* parent, TrackCollection* pTrackCollection,
+ RecordingManager* pRecordingManager)
+ : QFrame(parent),
m_pTrackCollection(pTrackCollection),
- m_browseModel(this, m_pTrackCollection, pRecordingManager),
- m_proxyModel(&m_browseModel),
+ m_pBrowseModel(nullptr),
+ m_pProxyModel(nullptr),
m_bytesRecordedStr("--"),
m_durationRecordedStr("--:--"),
m_pRecordingManager(pRecordingManager) {
setupUi(this);
- m_pTrackTableView = new WTrackTableView(this, pConfig, m_pTrackCollection, false); // No sorting
- m_pTrackTableView->installEventFilter(pKeyboard);
-
- connect(m_pTrackTableView, SIGNAL(loadTrack(TrackPointer)),
- this, SIGNAL(loadTrack(TrackPointer)));
- connect(m_pTrackTableView, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)),
- this, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)));
- connect(pLibrary, SIGNAL(setTrackTableFont(QFont)),
- m_pTrackTableView, SLOT(setTrackTableFont(QFont)));
- connect(pLibrary, SIGNAL(setTrackTableRowHeight(int)),
- m_pTrackTableView, SLOT(setTrackTableRowHeight(int)));
connect(m_pRecordingManager, SIGNAL(isRecording(bool)),
this, SLOT(slotRecordingEnabled(bool)));
@@ -39,22 +26,8 @@ DlgRecording::DlgRecording(QWidget* parent, UserSettingsPointer pConfig,
connect(m_pRecordingManager, SIGNAL(durationRecorded(QString)),
this, SLOT(slotDurationRecorded(QString)));
- QBoxLayout* box = dynamic_cast(layout());
- DEBUG_ASSERT_AND_HANDLE(box) { //Assumes the form layout is a QVBox/QHBoxLayout!
- } else {
- box->removeWidget(m_pTrackTablePlaceholder);
- m_pTrackTablePlaceholder->hide();
- box->insertWidget(1, m_pTrackTableView);
- }
-
m_recordingDir = m_pRecordingManager->getRecordingDir();
- m_proxyModel.setFilterCaseSensitivity(Qt::CaseInsensitive);
- m_proxyModel.setSortCaseSensitivity(Qt::CaseInsensitive);
-
- m_browseModel.setPath(m_recordingDir);
- m_pTrackTableView->loadTrackModel(&m_proxyModel);
-
connect(pushButtonRecording, SIGNAL(toggled(bool)),
this, SLOT(toggleRecording(bool)));
label->setText("");
@@ -66,39 +39,23 @@ DlgRecording::~DlgRecording() {
void DlgRecording::onShow() {
m_recordingDir = m_pRecordingManager->getRecordingDir();
- m_browseModel.setPath(m_recordingDir);
-}
-
-void DlgRecording::refreshBrowseModel() {
- m_browseModel.setPath(m_recordingDir);
-}
-
-void DlgRecording::onSearch(const QString& text) {
- m_proxyModel.search(text);
+ m_pBrowseModel->setPath(m_recordingDir);
}
-void DlgRecording::slotRestoreSearch() {
- emit(restoreSearch(currentSearch()));
+void DlgRecording::setProxyTrackModel(ProxyTrackModel* pProxyModel) {
+ m_pProxyModel = pProxyModel;
+
+ m_pProxyModel->setFilterCaseSensitivity(Qt::CaseInsensitive);
+ m_pProxyModel->setSortCaseSensitivity(Qt::CaseInsensitive);
}
-void DlgRecording::loadSelectedTrack() {
- m_pTrackTableView->loadSelectedTrack();
+void DlgRecording::setBrowseTableModel(BrowseTableModel* pBrowseModel) {
+ m_pBrowseModel = pBrowseModel;
+ m_pBrowseModel->setPath(m_recordingDir);
}
-void DlgRecording::slotSendToAutoDJ() {
- m_pTrackTableView->slotSendToAutoDJ();
-}
-
-void DlgRecording::slotSendToAutoDJTop() {
- m_pTrackTableView->slotSendToAutoDJTop();
-}
-
-void DlgRecording::loadSelectedTrackToGroup(QString group, bool play) {
- m_pTrackTableView->loadSelectedTrackToGroup(group, play);
-}
-
-void DlgRecording::moveSelection(int delta) {
- m_pTrackTableView->moveSelection(delta);
+void DlgRecording::refreshBrowseModel() {
+ m_pBrowseModel->setPath(m_recordingDir);
}
void DlgRecording::toggleRecording(bool toggle) {
@@ -125,7 +82,7 @@ void DlgRecording::slotRecordingEnabled(bool isRecording) {
label->setEnabled(false);
}
//This will update the recorded track table view
- m_browseModel.setPath(m_recordingDir);
+ m_pBrowseModel->setPath(m_recordingDir);
}
// gets number of recorded bytes and update label
@@ -149,11 +106,3 @@ void DlgRecording::refreshLabel() {
.arg(m_durationRecordedStr);
label->setText(text);
}
-
-void DlgRecording::setTrackTableFont(const QFont& font) {
- m_pTrackTableView->setTrackTableFont(font);
-}
-
-void DlgRecording::setTrackTableRowHeight(int rowHeight) {
- m_pTrackTableView->setTrackTableRowHeight(rowHeight);
-}
diff --git a/src/library/recording/dlgrecording.h b/src/library/recording/dlgrecording.h
index 0f8db1f42ade..cd9c1c05d78c 100644
--- a/src/library/recording/dlgrecording.h
+++ b/src/library/recording/dlgrecording.h
@@ -16,47 +16,32 @@ class PlaylistTableModel;
class QSqlTableModel;
class WTrackTableView;
-class DlgRecording : public QWidget, public Ui::DlgRecording, public virtual LibraryView {
+class DlgRecording : public QFrame, public Ui::DlgRecording {
Q_OBJECT
public:
- DlgRecording(QWidget *parent, UserSettingsPointer pConfig,
- Library* pLibrary, TrackCollection* pTrackCollection,
- RecordingManager* pRecManager, KeyboardEventFilter* pKeyboard);
+ DlgRecording(QWidget *parent, TrackCollection* pTrackCollection,
+ RecordingManager* pRecManager);
virtual ~DlgRecording();
- virtual void onSearch(const QString& text);
virtual void onShow();
- virtual void loadSelectedTrack();
- virtual void slotSendToAutoDJ();
- virtual void slotSendToAutoDJTop();
- virtual void loadSelectedTrackToGroup(QString group, bool play);
- virtual void moveSelection(int delta);
- inline const QString currentSearch() { return m_proxyModel.currentSearch(); }
+ void setProxyTrackModel(ProxyTrackModel* pProxyModel);
+ void setBrowseTableModel(BrowseTableModel* pBrowseModel);
public slots:
void toggleRecording(bool toggle);
void slotRecordingEnabled(bool);
void slotBytesRecorded(long);
void refreshBrowseModel();
- void slotRestoreSearch();
void slotDurationRecorded(QString durationRecorded);
- void setTrackTableFont(const QFont& font);
- void setTrackTableRowHeight(int rowHeight);
-
- signals:
- void loadTrack(TrackPointer tio);
- void loadTrackToPlayer(TrackPointer tio, QString group, bool play);
- void restoreSearch(QString search);
-
+
private:
- UserSettingsPointer m_pConfig;
+ void refreshLabel();
+
TrackCollection* m_pTrackCollection;
- WTrackTableView* m_pTrackTableView;
- BrowseTableModel m_browseModel;
- ProxyTrackModel m_proxyModel;
+ BrowseTableModel* m_pBrowseModel;
+ ProxyTrackModel* m_pProxyModel;
QString m_recordingDir;
- void refreshLabel();
QString m_bytesRecordedStr;
QString m_durationRecordedStr;
diff --git a/src/library/recording/dlgrecording.ui b/src/library/recording/dlgrecording.ui
index b94205936376..895adc9ac486 100644
--- a/src/library/recording/dlgrecording.ui
+++ b/src/library/recording/dlgrecording.ui
@@ -6,85 +6,47 @@
0
0
- 582
- 399
+ 391
+ 322
Recordings
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
-
-
-
-
- 0
+
+
+ Start Recording
-
- 0
-
-
- 0
-
-
- 0
-
-
- 0
+
+ true
-
-
-
-
- Qt::Horizontal
-
-
-
- 40
- 20
-
-
-
-
- -
-
-
- Status:
-
-
-
- -
-
-
- Start Recording
-
-
- true
-
-
-
-
+
-
-
-
+
+
+ Status:
+
+
true
+ -
+
+
+ Qt::Vertical
+
+
+
+ 20
+ 247
+
+
+
+
diff --git a/src/library/recording/recordingfeature.cpp b/src/library/recording/recordingfeature.cpp
index e3a3c0d8c3aa..7b3b369d3939 100644
--- a/src/library/recording/recordingfeature.cpp
+++ b/src/library/recording/recordingfeature.cpp
@@ -10,17 +10,21 @@
#include "widget/wlibrary.h"
#include "controllers/keyboard/keyboardeventfilter.h"
-const QString RecordingFeature::m_sRecordingViewName = QString("Recording");
-
-RecordingFeature::RecordingFeature(Library* pLibrary,
- UserSettingsPointer pConfig,
+RecordingFeature::RecordingFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
TrackCollection* pTrackCollection,
RecordingManager* pRecordingManager)
- : LibraryFeature(pLibrary),
- m_pConfig(pConfig),
- m_pLibrary(pLibrary),
+ : LibraryFeature(pConfig, pLibrary, pTrackCollection, parent),
m_pTrackCollection(pTrackCollection),
- m_pRecordingManager(pRecordingManager) {
+ m_pRecordingManager(pRecordingManager),
+ m_pRecordingView(nullptr),
+ m_pBrowseModel(nullptr),
+ m_pProxyModel(nullptr) {
+
+ TreeItem* pRoot = new TreeItem();
+ pRoot->setLibraryFeature(this);
+ m_childModel.setRootItem(pRoot);
}
RecordingFeature::~RecordingFeature() {
@@ -38,35 +42,60 @@ QIcon RecordingFeature::getIcon() {
TreeItemModel* RecordingFeature::getChildModel() {
return &m_childModel;
}
-void RecordingFeature::bindWidget(WLibrary* pLibraryWidget,
- KeyboardEventFilter *keyboard) {
- //The view will be deleted by LibraryWidget
- DlgRecording* pRecordingView = new DlgRecording(pLibraryWidget,
- m_pConfig,
- m_pLibrary,
- m_pTrackCollection,
- m_pRecordingManager,
- keyboard);
- pRecordingView->installEventFilter(keyboard);
- pLibraryWidget->registerView(m_sRecordingViewName, pRecordingView);
- connect(pRecordingView, SIGNAL(loadTrack(TrackPointer)),
- this, SIGNAL(loadTrack(TrackPointer)));
- connect(pRecordingView, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)),
- this, SIGNAL(loadTrackToPlayer(TrackPointer, QString, bool)));
- connect(this, SIGNAL(refreshBrowseModel()),
- pRecordingView, SLOT(refreshBrowseModel()));
- connect(this, SIGNAL(requestRestoreSearch()),
- pRecordingView, SLOT(slotRestoreSearch()));
- connect(pRecordingView, SIGNAL(restoreSearch(QString)),
- this, SIGNAL(restoreSearch(QString)));
+QWidget* RecordingFeature::createPaneWidget(KeyboardEventFilter* pKeyboard, int) {
+ WTrackTableView* pTrackTableView = new WTrackTableView(nullptr,
+ m_pConfig,
+ m_pTrackCollection,
+ false); // No sorting
+ pTrackTableView->installEventFilter(pKeyboard);
+
+ connect(m_pLibrary, SIGNAL(setTrackTableFont(QFont)),
+ pTrackTableView, SLOT(setTrackTableFont(QFont)));
+ connect(m_pLibrary, SIGNAL(setTrackTableRowHeight(int)),
+ pTrackTableView, SLOT(setTrackTableRowHeight(int)));
+ pTrackTableView->loadTrackModel(getProxyTrackModel());
+
+ return pTrackTableView;
+}
+
+QWidget *RecordingFeature::createInnerSidebarWidget(KeyboardEventFilter* pKeyboard) {
+ m_pRecordingView = new DlgRecording(nullptr,
+ m_pTrackCollection,
+ m_pRecordingManager);
+ m_pRecordingView->installEventFilter(pKeyboard);
+ m_pRecordingView->setBrowseTableModel(getBrowseTableModel());
+ m_pRecordingView->setProxyTrackModel(getProxyTrackModel());
+
+ return m_pRecordingView;
}
void RecordingFeature::activate() {
- emit(refreshBrowseModel());
- emit(switchToView(m_sRecordingViewName));
- // Ask the view to emit a restoreSearch signal.
- emit(requestRestoreSearch());
+ DEBUG_ASSERT_AND_HANDLE(!m_pRecordingView.isNull()) {
+ return;
+ }
+
+ m_pRecordingView->refreshBrowseModel();
+ m_pLibrary->switchToFeature(this);
+ m_pLibrary->showBreadCrumb(m_childModel.getItem(QModelIndex()));
+ m_pLibrary->restoreSearch("");
+
emit(enableCoverArtDisplay(false));
}
+
+BrowseTableModel* RecordingFeature::getBrowseTableModel() {
+ if (m_pBrowseModel.isNull()) {
+ m_pBrowseModel = new BrowseTableModel(this, m_pTrackCollection, m_pRecordingManager);
+ }
+
+ return m_pBrowseModel;
+}
+
+ProxyTrackModel* RecordingFeature::getProxyTrackModel() {
+ if (m_pProxyModel.isNull()) {
+ m_pProxyModel = new ProxyTrackModel(getBrowseTableModel());
+ }
+
+ return m_pProxyModel;
+}
diff --git a/src/library/recording/recordingfeature.h b/src/library/recording/recordingfeature.h
index 7ff7e43ac469..01e241092a35 100644
--- a/src/library/recording/recordingfeature.h
+++ b/src/library/recording/recordingfeature.h
@@ -14,14 +14,16 @@
#include "library/proxytrackmodel.h"
#include "recording/recordingmanager.h"
-class Library;
class TrackCollection;
+class WTrackTableView;
+class DlgRecording;
class RecordingFeature : public LibraryFeature {
Q_OBJECT
public:
- RecordingFeature(Library* parent,
- UserSettingsPointer pConfig,
+ RecordingFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
TrackCollection* pTrackCollection,
RecordingManager* pRecordingManager);
virtual ~RecordingFeature();
@@ -29,8 +31,8 @@ class RecordingFeature : public LibraryFeature {
QVariant title();
QIcon getIcon();
- void bindWidget(WLibrary* libraryWidget,
- KeyboardEventFilter* keyboard);
+ QWidget* createPaneWidget(KeyboardEventFilter *pKeyboard, int) override;
+ QWidget* createInnerSidebarWidget(KeyboardEventFilter* pKeyboard) override;
TreeItemModel* getChildModel();
@@ -39,16 +41,19 @@ class RecordingFeature : public LibraryFeature {
signals:
void setRootIndex(const QModelIndex&);
- void requestRestoreSearch();
- void refreshBrowseModel();
private:
- UserSettingsPointer m_pConfig;
- Library* m_pLibrary;
+
+ BrowseTableModel* getBrowseTableModel();
+ ProxyTrackModel* getProxyTrackModel();
+
TrackCollection* m_pTrackCollection;
FolderTreeModel m_childModel;
- const static QString m_sRecordingViewName;
RecordingManager* m_pRecordingManager;
+
+ QPointer m_pRecordingView;
+ QPointer m_pBrowseModel;
+ QPointer m_pProxyModel;
};
#endif
diff --git a/src/library/rhythmbox/rhythmboxfeature.cpp b/src/library/rhythmbox/rhythmboxfeature.cpp
index 9d9f7d331d2c..25f7f4ff6263 100644
--- a/src/library/rhythmbox/rhythmboxfeature.cpp
+++ b/src/library/rhythmbox/rhythmboxfeature.cpp
@@ -7,11 +7,15 @@
#include "library/baseexternaltrackmodel.h"
#include "library/baseexternalplaylistmodel.h"
-#include "library/treeitem.h"
+#include "library/library.h"
#include "library/queryutil.h"
+#include "library/treeitem.h"
-RhythmboxFeature::RhythmboxFeature(QObject* parent, TrackCollection* pTrackCollection)
- : BaseExternalLibraryFeature(parent, pTrackCollection),
+RhythmboxFeature::RhythmboxFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection)
+ : BaseExternalLibraryFeature(pConfig, pLibrary, parent, pTrackCollection),
m_pTrackCollection(pTrackCollection),
m_cancelImport(false) {
QString tableName = "rhythmbox_library";
@@ -108,7 +112,7 @@ TreeItemModel* RhythmboxFeature::getChildModel() {
}
void RhythmboxFeature::activate() {
- qDebug() << "RhythmboxFeature::activate()";
+ //qDebug() << "RhythmboxFeature::activate()";
if (!m_isActivated) {
m_isActivated = true;
@@ -127,8 +131,9 @@ void RhythmboxFeature::activate() {
//calls a slot in the sidebar model such that 'Rhythmbox (isLoading)' is displayed.
emit (featureIsLoading(this, true));
}
-
- emit(showTrackModel(m_pRhythmboxTrackModel));
+
+ showTrackModel(m_pRhythmboxTrackModel);
+ m_pLibrary->showBreadCrumb(m_childModel.getItem(QModelIndex()));
emit(enableCoverArtDisplay(false));
}
@@ -137,7 +142,9 @@ void RhythmboxFeature::activateChild(const QModelIndex& index) {
QString playlist = index.data().toString();
qDebug() << "Activating " << playlist;
m_pRhythmboxPlaylistModel->setPlaylist(playlist);
- emit(showTrackModel(m_pRhythmboxPlaylistModel));
+
+ showTrackModel(m_pRhythmboxPlaylistModel);
+ m_pLibrary->showBreadCrumb(static_cast(index.internalPointer()));
emit(enableCoverArtDisplay(false));
}
@@ -149,12 +156,12 @@ TreeItem* RhythmboxFeature::importMusicCollection() {
if (!db.exists()) {
db.setFileName(QDir::homePath() + "/.local/share/rhythmbox/rhythmdb.xml");
if (!db.exists()) {
- return NULL;
+ return nullptr;
}
}
if (!db.open(QIODevice::ReadOnly | QIODevice::Text))
- return NULL;
+ return nullptr;
//Delete all table entries of Traktor feature
ScopedTransaction transaction(m_database);
@@ -436,6 +443,7 @@ void RhythmboxFeature::clearTable(QString table_name) {
void RhythmboxFeature::onTrackCollectionLoaded() {
TreeItem* root = m_track_future.result();
+ root->setLibraryFeature(this);
if (root) {
m_childModel.setRootItem(root);
diff --git a/src/library/rhythmbox/rhythmboxfeature.h b/src/library/rhythmbox/rhythmboxfeature.h
index b2649959b525..4ea8a6601bd6 100644
--- a/src/library/rhythmbox/rhythmboxfeature.h
+++ b/src/library/rhythmbox/rhythmboxfeature.h
@@ -21,7 +21,10 @@ class BaseExternalPlaylistModel;
class RhythmboxFeature : public BaseExternalLibraryFeature {
Q_OBJECT
public:
- RhythmboxFeature(QObject* parent, TrackCollection*);
+ RhythmboxFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection);
virtual ~RhythmboxFeature();
static bool isSupported();
diff --git a/src/library/traktor/traktorfeature.cpp b/src/library/traktor/traktorfeature.cpp
index 2cf48b224edc..3b3b697f88e7 100644
--- a/src/library/traktor/traktorfeature.cpp
+++ b/src/library/traktor/traktorfeature.cpp
@@ -10,6 +10,7 @@
#include "library/traktor/traktorfeature.h"
+#include "library/library.h"
#include "library/librarytablemodel.h"
#include "library/missingtablemodel.h"
#include "library/queryutil.h"
@@ -50,8 +51,10 @@ bool TraktorPlaylistModel::isColumnHiddenByDefault(int column) {
return BaseSqlTableModel::isColumnHiddenByDefault(column);
}
-TraktorFeature::TraktorFeature(QObject* parent, TrackCollection* pTrackCollection)
- : BaseExternalLibraryFeature(parent, pTrackCollection),
+TraktorFeature::TraktorFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent, TrackCollection* pTrackCollection)
+ : BaseExternalLibraryFeature(pConfig, pLibrary, parent, pTrackCollection),
m_pTrackCollection(pTrackCollection),
m_cancelImport(false) {
QString tableName = "traktor_library";
@@ -135,7 +138,7 @@ void TraktorFeature::refreshLibraryModels() {
}
void TraktorFeature::activate() {
- qDebug() << "TraktorFeature::activate()";
+ //qDebug() << "TraktorFeature::activate()";
if (!m_isActivated) {
m_isActivated = true;
@@ -156,8 +159,9 @@ void TraktorFeature::activate() {
//calls a slot in the sidebar model such that 'iTunes (isLoading)' is displayed.
emit (featureIsLoading(this, true));
}
-
- emit(showTrackModel(m_pTraktorTableModel));
+
+ showTrackModel(m_pTraktorTableModel);
+ m_pLibrary->showBreadCrumb(m_childModel.getItem(QModelIndex()));
emit(enableCoverArtDisplay(false));
}
@@ -171,7 +175,9 @@ void TraktorFeature::activateChild(const QModelIndex& index) {
if (item->isPlaylist()) {
qDebug() << "Activate Traktor Playlist: " << item->dataPath().toString();
m_pTraktorPlaylistModel->setPlaylist(item->dataPath().toString());
- emit(showTrackModel(m_pTraktorPlaylistModel));
+
+ showTrackModel(m_pTraktorPlaylistModel);
+ m_pLibrary->showBreadCrumb(item);
emit(enableCoverArtDisplay(false));
}
}
@@ -602,17 +608,19 @@ QString TraktorFeature::getTraktorMusicDatabase() {
void TraktorFeature::onTrackCollectionLoaded() {
TreeItem* root = m_future.result();
+ root->setLibraryFeature(this);
if (root) {
m_childModel.setRootItem(root);
// Tell the traktor track source that it should re-build its index.
m_trackSource->buildIndex();
//m_pTraktorTableModel->select();
- emit(showTrackModel(m_pTraktorTableModel));
+ showTrackModel(m_pTraktorTableModel);
+ m_pLibrary->showBreadCrumb(root);
qDebug() << "Traktor library loaded successfully";
} else {
QMessageBox::warning(
- NULL,
+ nullptr,
tr("Error Loading Traktor Library"),
tr("There was an error loading your Traktor library. Some of "
"your Traktor tracks or playlists may not have loaded."));
diff --git a/src/library/traktor/traktorfeature.h b/src/library/traktor/traktorfeature.h
index edf04e426646..d210ae335eb1 100644
--- a/src/library/traktor/traktorfeature.h
+++ b/src/library/traktor/traktorfeature.h
@@ -38,7 +38,10 @@ class TraktorPlaylistModel : public BaseExternalPlaylistModel {
class TraktorFeature : public BaseExternalLibraryFeature {
Q_OBJECT
public:
- TraktorFeature(QObject* parent, TrackCollection*);
+ TraktorFeature(UserSettingsPointer pConfig,
+ Library* pLibrary,
+ QObject* parent,
+ TrackCollection* pTrackCollection);
virtual ~TraktorFeature();
QVariant title();
diff --git a/src/library/treeitem.cpp b/src/library/treeitem.cpp
index 2985373fcb92..dc4575579e0b 100644
--- a/src/library/treeitem.cpp
+++ b/src/library/treeitem.cpp
@@ -34,15 +34,15 @@ TreeItem::TreeItem(const QString &data, const QString &data_path,
m_data = data;
m_dataPath = data_path;
m_parentItem = parent;
- m_feature = feature;
+ m_pFeature = feature;
m_bold = false;
}
TreeItem::TreeItem() {
m_data = "$root";
m_dataPath = "$root";
- m_parentItem = NULL;
- m_feature = NULL;
+ m_parentItem = nullptr;
+ m_pFeature = nullptr;
m_bold = false;
}
@@ -95,7 +95,11 @@ int TreeItem::row() const {
}
LibraryFeature* TreeItem::getFeature() {
- return m_feature;
+ return m_pFeature;
+}
+
+void TreeItem::setLibraryFeature(LibraryFeature *pFeature) {
+ m_pFeature = pFeature;
}
bool TreeItem::insertChildren(QList &data, int position, int count) {
diff --git a/src/library/treeitem.h b/src/library/treeitem.h
index d56c38cc243d..6b7be0594a64 100644
--- a/src/library/treeitem.h
+++ b/src/library/treeitem.h
@@ -7,6 +7,7 @@
#include
#include
#include
+#include
#include "library/libraryfeature.h"
@@ -22,7 +23,7 @@ class TreeItem {
void appendChild(TreeItem *child);
/** remove a child item at the given index **/
void removeChild(int index);
- /** returns the tree item at position 'row' in the childlist **/
+ /** returns the tree item at position 'row' in the child list **/
TreeItem *child(int row);
/** returns the number of childs of this tree item **/
int childCount() const;
@@ -48,6 +49,8 @@ class TreeItem {
bool isFolder() const;
/* Returns the Library feature object to which an item belongs to */
LibraryFeature* getFeature();
+
+ void setLibraryFeature(LibraryFeature* pFeature);
void setBold(bool bold) {
m_bold = bold;
@@ -64,7 +67,7 @@ class TreeItem {
QList m_childItems;
QString m_dataPath;
QString m_data;
- LibraryFeature* m_feature;
+ LibraryFeature* m_pFeature;
bool m_bold;
TreeItem *m_parentItem;
diff --git a/src/library/treeitemmodel.cpp b/src/library/treeitemmodel.cpp
index cd9824c3a67e..3270c598a0c5 100644
--- a/src/library/treeitemmodel.cpp
+++ b/src/library/treeitemmodel.cpp
@@ -45,8 +45,10 @@ QVariant TreeItemModel::data(const QModelIndex &index, int role) const {
if (!index.isValid())
return QVariant();
- if (role != Qt::DisplayRole && role != kDataPathRole && role != kBoldRole)
+ if (role != Qt::DisplayRole && role != kDataPathRole &&
+ role != kBoldRole && role != Qt::DecorationRole) {
return QVariant();
+ }
TreeItem *item = static_cast(index.internalPointer());
@@ -55,6 +57,8 @@ QVariant TreeItemModel::data(const QModelIndex &index, int role) const {
return item->dataPath();
} else if (role == kBoldRole) {
return item->isBold();
+ } else if (role == Qt::DecorationRole) {
+ return item->getIcon();
}
return item->data();
}
@@ -204,3 +208,43 @@ void TreeItemModel::triggerRepaint() {
QModelIndex right = index(rowCount() - 1, columnCount() - 1);
emit(dataChanged(left, right));
}
+
+bool TreeItemModel::dropAccept(const QModelIndex& index, QList urls,
+ QObject* pSource) {
+ //qDebug() << "TreeItemModel::dropAccept() index=" << index << urls;
+ bool result = false;
+ if (index.isValid()) {
+ LibraryFeature* pFeature;
+ if (index.internalPointer() == this) {
+ pFeature = m_pRootItem->getFeature();
+ } else {
+ TreeItem* treeItem = (TreeItem*) index.internalPointer();
+ if (!treeItem) {
+ return false;
+ }
+ pFeature = treeItem->getFeature();
+ }
+
+ result = pFeature->dropAcceptChild(index, urls, pSource);
+ }
+ return result;
+}
+
+bool TreeItemModel::dragMoveAccept(const QModelIndex& index, QUrl url) {
+ //qDebug() << "TreeItemModel::dragMoveAccept() index=" << index << url;
+ bool result = false;
+ if (index.isValid()) {
+ LibraryFeature* pFeature;
+ if (index.internalPointer() == this) {
+ pFeature = m_pRootItem->getFeature();
+ } else {
+ TreeItem* treeItem = (TreeItem*) index.internalPointer();
+ if (treeItem) {
+ pFeature = treeItem->getFeature();
+ }
+ }
+
+ result = pFeature->dragMoveAcceptChild(index, url);
+ }
+ return result;
+}
diff --git a/src/library/treeitemmodel.h b/src/library/treeitemmodel.h
index 3aa28de27bf2..f67ba9e2014c 100644
--- a/src/library/treeitemmodel.h
+++ b/src/library/treeitemmodel.h
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
class TreeItem;
@@ -36,6 +37,9 @@ class TreeItemModel : public QAbstractItemModel {
TreeItem* getItem(const QModelIndex &index) const;
void triggerRepaint();
+
+ bool dropAccept(const QModelIndex& index, QList urls, QObject* pSource);
+ bool dragMoveAccept(const QModelIndex& index, QUrl url);
private:
TreeItem *m_pRootItem;
diff --git a/src/mixer/basetrackplayer.cpp b/src/mixer/basetrackplayer.cpp
index cc49de5c852d..4fbcac3b4cc4 100644
--- a/src/mixer/basetrackplayer.cpp
+++ b/src/mixer/basetrackplayer.cpp
@@ -242,13 +242,6 @@ void BaseTrackPlayerImpl::slotTrackLoaded(TrackPointer pNewTrack,
m_pKey->set(m_pLoadedTrack->getKey());
setReplayGain(m_pLoadedTrack->getReplayGain().getRatio());
- // Clear loop
- // It seems that the trick is to first clear the loop out point, and then
- // the loop in point. If we first clear the loop in point, the loop out point
- // does not get cleared.
- m_pLoopOutPoint->set(-1);
- m_pLoopInPoint->set(-1);
-
const QList trackCues(pNewTrack->getCuePoints());
QListIterator it(trackCues);
while (it.hasNext()) {
diff --git a/src/mixxx.cpp b/src/mixxx.cpp
index d7511d7d4780..58713548f181 100644
--- a/src/mixxx.cpp
+++ b/src/mixxx.cpp
@@ -267,7 +267,7 @@ void MixxxMainWindow::initialize(QApplication* pApp, const CmdlineArgs& args) {
m_pPlayerManager,
m_pRecordingManager);
m_pPlayerManager->bindToLibrary(m_pLibrary);
-
+
launchProgress(35);
// Get Music dir
@@ -1043,6 +1043,7 @@ void MixxxMainWindow::rebootMixxxView() {
// that need to be deleted -- otherwise we can't tell what features the skin
// supports since the controls from the previous skin will be left over.
m_pMenuBar->onNewSkinAboutToLoad();
+ m_pLibrary->destroyInterface();
if (m_pWidgetParent) {
m_pWidgetParent->hide();
diff --git a/src/mixxx.h b/src/mixxx.h
index a1793d56b541..5ca96f3b4b08 100644
--- a/src/mixxx.h
+++ b/src/mixxx.h
@@ -37,6 +37,7 @@ class EngineMaster;
class GuiTick;
class LaunchImage;
class Library;
+class LibraryPaneManager;
class KeyboardEventFilter;
class PlayerManager;
class RecordingManager;
diff --git a/src/skin/legacyskinparser.cpp b/src/skin/legacyskinparser.cpp
index 9fabb0cc05e0..76db23eefe63 100644
--- a/src/skin/legacyskinparser.cpp
+++ b/src/skin/legacyskinparser.cpp
@@ -9,6 +9,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -65,6 +66,8 @@
#include "widget/wsearchlineedit.h"
#include "widget/wlibrary.h"
#include "widget/wlibrarysidebar.h"
+#include "widget/wlibrarybreadcrumb.h"
+#include "widget/wbuttonbar.h"
#include "widget/wskincolor.h"
#include "widget/wpixmapstore.h"
#include "widget/wwidgetstack.h"
@@ -143,7 +146,8 @@ LegacySkinParser::LegacySkinParser()
m_pVCManager(NULL),
m_pEffectsManager(NULL),
m_pParent(NULL),
- m_pContext(NULL) {
+ m_pContext(NULL),
+ m_paneId(0) {
}
LegacySkinParser::LegacySkinParser(UserSettingsPointer pConfig,
@@ -161,7 +165,8 @@ LegacySkinParser::LegacySkinParser(UserSettingsPointer pConfig,
m_pVCManager(pVCMan),
m_pEffectsManager(pEffectsManager),
m_pParent(NULL),
- m_pContext(NULL) {
+ m_pContext(NULL),
+ m_paneId(0) {
}
LegacySkinParser::~LegacySkinParser() {
@@ -551,10 +556,18 @@ QList LegacySkinParser::parseNode(const QDomElement& node) {
result = wrapWidget(parseLabelWidget(node));
} else if (nodeName == "Splitter") {
result = wrapWidget(parseSplitter(node));
+ } else if (nodeName == "LibrarySidebarButtons") {
+ result = wrapWidget(parseLibrarySidebarButtons(node));
} else if (nodeName == "LibrarySidebar") {
result = wrapWidget(parseLibrarySidebar(node));
+ } else if (nodeName == "LibrarySidebarExpanded") {
+ result = wrapWidget(parseLibrarySidebarExpanded(node));
+ } else if (nodeName == "LibraryPane") {
+ result = wrapWidget(parseLibraryPane(node));
+ } else if (nodeName == "LibraryBreadCrumb") {
+ result = wrapWidget(parseLibraryBreadCrumb(node));
} else if (nodeName == "Library") {
- result = wrapWidget(parseLibrary(node));
+ result = wrapWidget(parseLibrary(node));
} else if (nodeName == "Key") {
result = wrapWidget(parseEngineKey(node));
} else if (nodeName == "Battery") {
@@ -1135,21 +1148,20 @@ QWidget* LegacySkinParser::parseSpinny(const QDomElement& node) {
}
QWidget* LegacySkinParser::parseSearchBox(const QDomElement& node) {
- WSearchLineEdit* pLineEditSearch = new WSearchLineEdit(m_pParent);
- commonWidgetSetup(node, pLineEditSearch, false);
- pLineEditSearch->setup(node, *m_pContext);
-
- // Connect search box signals to the library
- connect(pLineEditSearch, SIGNAL(search(const QString&)),
- m_pLibrary, SIGNAL(search(const QString&)));
- connect(pLineEditSearch, SIGNAL(searchCleared()),
- m_pLibrary, SIGNAL(searchCleared()));
- connect(pLineEditSearch, SIGNAL(searchStarting()),
- m_pLibrary, SIGNAL(searchStarting()));
- connect(m_pLibrary, SIGNAL(restoreSearch(const QString&)),
- pLineEditSearch, SLOT(restoreSearch(const QString&)));
-
- return pLineEditSearch;
+ WSearchLineEdit* pSearchLineEdit = new WSearchLineEdit(m_pParent);
+
+ int id = -1;
+ if (m_pContext->hasNodeSelectInt(node, "Id", &id)) {
+ //qDebug() << "SearchBox ID:" << id;
+ m_pLibrary->bindSearchBar(pSearchLineEdit, id);
+ }
+ else {
+ SKIN_WARNING(node, *m_pContext) << "SearchBox Id not found";
+ }
+ pSearchLineEdit->setup(node, *m_pContext);
+ commonWidgetSetup(node, pSearchLineEdit, false);
+
+ return pSearchLineEdit;
}
QWidget* LegacySkinParser::parseCoverArt(const QDomElement& node) {
@@ -1163,8 +1175,6 @@ QWidget* LegacySkinParser::parseCoverArt(const QDomElement& node) {
// If no group was provided, hook the widget up to the Library.
if (channel.isEmpty()) {
// Connect cover art signals to the library
- connect(m_pLibrary, SIGNAL(switchToView(const QString&)),
- pCoverArt, SLOT(slotReset()));
connect(m_pLibrary, SIGNAL(enableCoverArtDisplay(bool)),
pCoverArt, SLOT(slotEnable(bool)));
connect(m_pLibrary, SIGNAL(trackSelected(TrackPointer)),
@@ -1237,31 +1247,122 @@ void LegacySkinParser::parseSingletonDefinition(const QDomElement& node) {
pChild->hide();
}
-QWidget* LegacySkinParser::parseLibrary(const QDomElement& node) {
+QWidget* LegacySkinParser::parseLibraryPane(const QDomElement& node) {
WLibrary* pLibraryWidget = new WLibrary(m_pParent);
pLibraryWidget->installEventFilter(m_pKeyboard);
pLibraryWidget->installEventFilter(m_pControllerManager->getControllerLearningEventFilter());
- // Connect Library search signals to the WLibrary
- connect(m_pLibrary, SIGNAL(search(const QString&)),
- pLibraryWidget, SLOT(search(const QString&)));
-
- m_pLibrary->bindWidget(pLibraryWidget, m_pKeyboard);
-
+ int id = -1;
+ if (m_pContext->hasNodeSelectInt(node, "Id", &id)) {
+ //qDebug() << "LegacySkinParser::parseLibrary:ID" << id;
+ m_pLibrary->bindPaneWidget(pLibraryWidget, m_pKeyboard, id);
+ }
+ else {
+ SKIN_WARNING(node, *m_pContext) << "No Id found";
+ }
+
// This must come after the bindWidget or we will not style any of the
// LibraryView's because they have not been added yet.
commonWidgetSetup(node, pLibraryWidget, false);
-
return pLibraryWidget;
}
-QWidget* LegacySkinParser::parseLibrarySidebar(const QDomElement& node) {
- WLibrarySidebar* pLibrarySidebar = new WLibrarySidebar(m_pParent);
+QWidget* LegacySkinParser::parseLibrary(const QDomElement& node) {
+ // Must add both a SearchBox and a LibraryPane
+ QFrame* pContainer = new QFrame(m_pParent);
+ QVBoxLayout* pLayout = new QVBoxLayout(pContainer);
+ pContainer->setLayout(pLayout);
+
+ WSearchLineEdit* pSearchBox = new WSearchLineEdit(pContainer);
+ pSearchBox->setup(node, *m_pContext);
+ m_pLibrary->bindSearchBar(pSearchBox, m_paneId);
+ commonWidgetSetup(node, pSearchBox);
+ pLayout->addWidget(pSearchBox);
+
+ WLibraryBreadCrumb* pBreadCrumb = new WLibraryBreadCrumb(pContainer);
+ m_pLibrary->bindBreadCrumb(pBreadCrumb, m_paneId);
+ setupWidget(node, pBreadCrumb);
+ pLayout->addWidget(pBreadCrumb);
+
+ WLibrary* pLibraryWidget = new WLibrary(pContainer);
+ pLibraryWidget->installEventFilter(m_pKeyboard);
+ pLibraryWidget->installEventFilter(m_pControllerManager->getControllerLearningEventFilter());
+ pLayout->addWidget(pLibraryWidget);
+
+ m_pLibrary->bindPaneWidget(pLibraryWidget, m_pKeyboard, m_paneId);
+ commonWidgetSetup(node, pLibraryWidget, false);
+ qDebug() << "LegacySkinParser::parseLibrary";
+
+ ++m_paneId;
+ return pContainer;
+}
+
+
+QWidget *LegacySkinParser::parseLibrarySidebar(const QDomElement& node) {
+ // We must create both LibrarySidebarButtons and LibrarySidebarExpanded
+ // to allow support for old skins
+ QFrame* pContainer = new QFrame(m_pParent);
+ QHBoxLayout* pLayout = new QHBoxLayout(pContainer);
+ pContainer->setLayout(pLayout);
+
+ QScrollArea* scroll = new QScrollArea(pContainer);
+ scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ scroll->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+ WButtonBar* pLibrarySidebar = new WButtonBar(pContainer);
+ pLibrarySidebar->installEventFilter(m_pKeyboard);
+ m_pLibrary->bindSidebarWidget(pLibrarySidebar);
+ scroll->setWidget(pLibrarySidebar);
+ pLayout->addWidget(scroll);
+
+ WBaseLibrary* pLibrarySidebarExpanded = new WBaseLibrary(pContainer);
+ pLibrarySidebarExpanded->installEventFilter(m_pKeyboard);
+ pLibrarySidebarExpanded->installEventFilter(m_pControllerManager->getControllerLearningEventFilter());
+ m_pLibrary->bindSidebarExpanded(pLibrarySidebarExpanded, m_pKeyboard);
+ pLayout->addWidget(pLibrarySidebarExpanded);
+
+ setupWidget(node, pLibrarySidebar);
+ commonWidgetSetup(node, pLibrarySidebarExpanded, false);
+ return pContainer;
+}
+
+QWidget* LegacySkinParser::parseLibrarySidebarButtons(const QDomElement& node) {
+ QScrollArea* scroll = new QScrollArea(m_pParent);
+ scroll->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ scroll->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+
+ WButtonBar* pLibrarySidebar = new WButtonBar(scroll);
pLibrarySidebar->installEventFilter(m_pKeyboard);
- pLibrarySidebar->installEventFilter(m_pControllerManager->getControllerLearningEventFilter());
m_pLibrary->bindSidebarWidget(pLibrarySidebar);
- commonWidgetSetup(node, pLibrarySidebar, false);
- return pLibrarySidebar;
+ scroll->setWidget(pLibrarySidebar);
+
+ setupWidget(node, scroll);
+ return scroll;
+}
+
+QWidget *LegacySkinParser::parseLibrarySidebarExpanded(const QDomElement &node) {
+ WBaseLibrary* pLibrarySidebarExpanded = new WBaseLibrary(m_pParent);
+ pLibrarySidebarExpanded->installEventFilter(m_pKeyboard);
+ pLibrarySidebarExpanded->installEventFilter(m_pControllerManager->getControllerLearningEventFilter());
+ m_pLibrary->bindSidebarExpanded(pLibrarySidebarExpanded, m_pKeyboard);
+ commonWidgetSetup(node, pLibrarySidebarExpanded, false);
+ return pLibrarySidebarExpanded;
+}
+
+QWidget* LegacySkinParser::parseLibraryBreadCrumb(const QDomElement& node) {
+ WLibraryBreadCrumb* pLibraryBreacrumb = new WLibraryBreadCrumb(m_pParent);
+
+ int id = -1;
+ if (m_pContext->hasNodeSelectInt(node, "Id", &id)) {
+ //qDebug() << "LegacySkinParser::parseLibrary:ID" << id;
+ m_pLibrary->bindBreadCrumb(pLibraryBreacrumb, id);
+ }
+ else {
+ SKIN_WARNING(node, *m_pContext) << "No Id found";
+ }
+ setupWidget(node, pLibraryBreacrumb);
+
+ return pLibraryBreacrumb;
}
QWidget* LegacySkinParser::parseTableView(const QDomElement& node) {
@@ -1289,11 +1390,11 @@ QWidget* LegacySkinParser::parseTableView(const QDomElement& node) {
QWidget* oldParent = m_pParent;
m_pParent = pSplitter;
- QWidget* pLibraryWidget = parseLibrary(node);
+ QWidget* pLibraryWidget = parseLibraryPane(node);
QWidget* pLibrarySidebarPage = new QWidget(pSplitter);
m_pParent = pLibrarySidebarPage;
- QWidget* pLibrarySidebar = parseLibrarySidebar(node);
+ QWidget* pLibrarySidebar = parseLibrarySidebarButtons(node);
QWidget* pLineEditSearch = parseSearchBox(node);
m_pParent = oldParent;
diff --git a/src/skin/legacyskinparser.h b/src/skin/legacyskinparser.h
index bd7d4b2eaa51..a05ef2e5264e 100644
--- a/src/skin/legacyskinparser.h
+++ b/src/skin/legacyskinparser.h
@@ -15,6 +15,7 @@
class WBaseWidget;
class Library;
+class LibraryPaneManager;
class KeyboardEventFilter;
class PlayerManager;
class EffectsManager;
@@ -98,8 +99,12 @@ class LegacySkinParser : public QObject, public SkinParser {
// Library widgets.
QWidget* parseTableView(const QDomElement& node);
QWidget* parseSearchBox(const QDomElement& node);
- QWidget* parseLibrary(const QDomElement& node);
+ QWidget* parseLibraryPane(const QDomElement& node);
QWidget* parseLibrarySidebar(const QDomElement& node);
+ QWidget* parseLibrarySidebarButtons(const QDomElement& node);
+ QWidget* parseLibrarySidebarExpanded(const QDomElement& node);
+ QWidget* parseLibraryBreadCrumb(const QDomElement& node);
+ QWidget* parseLibrary(const QDomElement& node);
QWidget* parseBattery(const QDomElement& node);
QWidget* parseCoverArt(const QDomElement& node);
@@ -139,6 +144,7 @@ class LegacySkinParser : public QObject, public SkinParser {
QHash m_templateCache;
static QList s_channelStrs;
static QMutex s_safeStringMutex;
+ int m_paneId;
};
diff --git a/src/skin/skinloader.cpp b/src/skin/skinloader.cpp
index 2cc4bb3bf1de..426a19dfe984 100644
--- a/src/skin/skinloader.cpp
+++ b/src/skin/skinloader.cpp
@@ -125,7 +125,7 @@ QWidget* SkinLoader::loadDefaultSkin(QWidget* pParent,
}
LegacySkinParser legacy(m_pConfig, pKeyboard, pPlayerManager,
- pControllerManager, pLibrary, pVCMan,
+ pControllerManager, pLibrary, pVCMan,
pEffectsManager);
return legacy.parseSkin(skinPath, pParent);
}
diff --git a/src/skin/skinloader.h b/src/skin/skinloader.h
index ac76b0c99785..0f594eb80527 100644
--- a/src/skin/skinloader.h
+++ b/src/skin/skinloader.h
@@ -11,6 +11,7 @@ class KeyboardEventFilter;
class PlayerManager;
class ControllerManager;
class Library;
+class LibraryPaneManager;
class VinylControlManager;
class EffectsManager;
class LaunchImage;
diff --git a/src/util/dnd.h b/src/util/dnd.h
index 542b0ecdf6d0..8cab28e375c8 100644
--- a/src/util/dnd.h
+++ b/src/util/dnd.h
@@ -26,6 +26,7 @@ class DragAndDropHelper {
bool firstOnly,
bool acceptPlaylists) {
QList fileLocations;
+ qDebug() << urls;
foreach (const QUrl& url, urls) {
// XXX: Possible WTF alert - Previously we thought we needed
diff --git a/src/widget/wbaselibrary.cpp b/src/widget/wbaselibrary.cpp
new file mode 100644
index 000000000000..92bfe51b8b94
--- /dev/null
+++ b/src/widget/wbaselibrary.cpp
@@ -0,0 +1,84 @@
+#include
+#include
+#include
+#include
+#include
+
+#include "library/libraryfeature.h"
+#include "widget/wbaselibrary.h"
+
+WBaseLibrary::WBaseLibrary(QWidget* parent)
+ : QStackedWidget(parent),
+ WBaseWidget(this),
+ m_mutex(QMutex::Recursive),
+ m_showFocus(0) {
+
+}
+
+bool WBaseLibrary::registerView(LibraryFeature *pFeature, QWidget *view) {
+ QMutexLocker lock(&m_mutex);
+ if (m_featureMap.contains(pFeature)) {
+ return false;
+ }
+
+ view->installEventFilter(this);
+ int index = addWidget(view);
+ setCurrentIndex(index);
+ m_pCurrentFeature = pFeature;
+ m_featureMap[pFeature] = view;
+ return true;
+}
+
+LibraryFeature *WBaseLibrary::getCurrentFeature() {
+ return m_pCurrentFeature;
+}
+
+int WBaseLibrary::getShowFocus() {
+ return m_showFocus;
+}
+
+void WBaseLibrary::setShowFocus(int sFocus) {
+ //qDebug() << "WBaseLibrary::setShowFocus" << sFocus << this;
+ m_showFocus = sFocus;
+
+ style()->unpolish(this);
+ style()->polish(this);
+ update();
+}
+
+void WBaseLibrary::switchToFeature(LibraryFeature *pFeature) {
+ auto it = m_featureMap.find(pFeature);
+ if (it != m_featureMap.end() && currentWidget() != (*it)) {
+ m_pCurrentFeature = pFeature;
+ setCurrentWidget(*it);
+ }
+}
+
+bool WBaseLibrary::eventFilter(QObject*, QEvent* pEvent) {
+ if (pEvent->type() == QEvent::FocusIn) {
+ //qDebug() << "WBaseLibrary::eventFilter FocusIn";
+ emit(focused());
+ }
+ return false;
+}
+
+bool WBaseLibrary::event(QEvent* pEvent) {
+ if (pEvent->type() == QEvent::ToolTip) {
+ updateTooltip();
+ }
+
+ return QStackedWidget::event(pEvent);
+}
+
+void WBaseLibrary::resizeEvent(QResizeEvent *pEvent) {
+
+ // Detect whether the library is collapsed to change the focus behaviour
+ if (pEvent->size().isEmpty()) {
+ m_isCollapsed = true;
+ emit(collapsed());
+ } else if (m_isCollapsed) {
+ m_isCollapsed = false;
+ emit(uncollapsed());
+ }
+}
+
diff --git a/src/widget/wbaselibrary.h b/src/widget/wbaselibrary.h
new file mode 100644
index 000000000000..9975aa324b7b
--- /dev/null
+++ b/src/widget/wbaselibrary.h
@@ -0,0 +1,55 @@
+#ifndef WLIBRARYSIDEBAREXPANDED_H
+#define WLIBRARYSIDEBAREXPANDED_H
+#include
+#include
+#include
+
+#include "widget/wbasewidget.h"
+
+class LibraryFeature;
+
+class WBaseLibrary : public QStackedWidget, public WBaseWidget
+{
+ Q_OBJECT
+ public:
+
+ WBaseLibrary(QWidget* parent = nullptr);
+
+ virtual bool registerView(LibraryFeature* pFeature, QWidget* view);
+
+ LibraryFeature* getCurrentFeature();
+
+ Q_PROPERTY(int showFocus READ getShowFocus WRITE setShowFocus)
+
+ int getShowFocus();
+
+ // Sets the widget to the focused state, it's not the same as Qt focus
+ void setShowFocus(int sFocus);
+
+ signals:
+
+ void focused();
+ void collapsed();
+ void uncollapsed();
+
+ public slots:
+
+ virtual void switchToFeature(LibraryFeature* pFeature);
+
+ protected:
+
+ bool eventFilter(QObject*, QEvent* pEvent);
+ bool event(QEvent* pEvent) override;
+ void resizeEvent(QResizeEvent* pEvent);
+
+ QHash m_featureMap;
+
+ private:
+
+ LibraryFeature* m_pCurrentFeature;
+ QMutex m_mutex;
+ int m_showFocus;
+ bool m_isCollapsed;
+};
+
+#endif // WLIBRARYSIDEBAREXPANDED_H
diff --git a/src/widget/wbuttonbar.cpp b/src/widget/wbuttonbar.cpp
new file mode 100644
index 000000000000..24a38d9c46eb
--- /dev/null
+++ b/src/widget/wbuttonbar.cpp
@@ -0,0 +1,24 @@
+#include
+
+#include "wbuttonbar.h"
+#include "library/libraryfeature.h"
+
+WButtonBar::WButtonBar(QWidget* parent)
+ : QFrame(parent) {
+
+ m_pLayout = new QVBoxLayout(this);
+ m_pLayout->setContentsMargins(0,0,0,0);
+ m_pLayout->setSpacing(0);
+ setLayout(m_pLayout);
+ setFocusPolicy(Qt::NoFocus);
+}
+
+WFeatureClickButton* WButtonBar::addButton(LibraryFeature* pFeature) {
+ WFeatureClickButton* button = new WFeatureClickButton(pFeature, this);
+ button->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+ button->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Minimum);
+
+ m_pLayout->addWidget(button);
+ return button;
+}
+
diff --git a/src/widget/wbuttonbar.h b/src/widget/wbuttonbar.h
new file mode 100644
index 000000000000..35c5908357d0
--- /dev/null
+++ b/src/widget/wbuttonbar.h
@@ -0,0 +1,25 @@
+#ifndef WBUTTONBAR_H
+#define WBUTTONBAR_H
+
+#include
+#include
+#include
+#include
+#include
+
+#include "widget/wfeatureclickbutton.h"
+
+class WButtonBar : public QFrame
+{
+ Q_OBJECT
+ public:
+ WButtonBar(QWidget* parent = nullptr);
+
+ WFeatureClickButton* addButton(LibraryFeature *pFeature);
+
+ private:
+
+ QLayout* m_pLayout;
+};
+
+#endif // WBUTTONBAR_H
diff --git a/src/widget/wfeatureclickbutton.cpp b/src/widget/wfeatureclickbutton.cpp
new file mode 100644
index 000000000000..8b94eff7f14a
--- /dev/null
+++ b/src/widget/wfeatureclickbutton.cpp
@@ -0,0 +1,67 @@
+#include "wfeatureclickbutton.h"
+#include "util/assert.h"
+
+const int WFeatureClickButton::kHoverTime = 250; // milliseconds
+
+WFeatureClickButton::WFeatureClickButton(LibraryFeature* pFeature, QWidget* parent)
+ : QToolButton(parent),
+ m_pFeature(pFeature) {
+ DEBUG_ASSERT_AND_HANDLE(pFeature != nullptr) {
+ return;
+ }
+
+ setIcon(m_pFeature->getIcon());
+ setText(m_pFeature->title().toString());
+
+ connect(this, SIGNAL(clicked()), this, SLOT(slotClicked()));
+ setAcceptDrops(true);
+}
+
+void WFeatureClickButton::mousePressEvent(QMouseEvent* event) {
+ if (event->button() == Qt::RightButton) {
+ emit(rightClicked(event->globalPos()));
+ }
+ QToolButton::mousePressEvent(event);
+}
+
+void WFeatureClickButton::dragEnterEvent(QDragEnterEvent* event) {
+ qDebug() << "WFeatureClickButton::dragEnterEvent" << event;
+ if (!event->mimeData()->hasUrls() || event->source() == this) {
+ event->ignore();
+ return;
+ }
+ if (m_pFeature->dragMoveAccept(event->mimeData()->urls().first())) {
+ event->acceptProposedAction();
+ m_hoverTimer.start(kHoverTime, this);
+ }
+}
+
+void WFeatureClickButton::dragLeaveEvent(QDragLeaveEvent*) {
+ m_hoverTimer.stop();
+}
+
+void WFeatureClickButton::dropEvent(QDropEvent* event) {
+ m_hoverTimer.stop();
+ event->acceptProposedAction();
+ if (!event->mimeData()->hasUrls() || event->source() == this) {
+ event->ignore();
+ return;
+ }
+
+ if (m_pFeature->dropAccept(event->mimeData()->urls(), event->source())) {
+ event->acceptProposedAction();
+ }
+}
+
+void WFeatureClickButton::timerEvent(QTimerEvent* event) {
+ if (event->timerId() != m_hoverTimer.timerId()) {
+ QToolButton::timerEvent(event);
+ return;
+ }
+ emit(hoverShow(m_pFeature));
+}
+
+void WFeatureClickButton::slotClicked() {
+ emit(clicked(m_pFeature));
+}
+
diff --git a/src/widget/wfeatureclickbutton.h b/src/widget/wfeatureclickbutton.h
new file mode 100644
index 000000000000..110e8984661b
--- /dev/null
+++ b/src/widget/wfeatureclickbutton.h
@@ -0,0 +1,45 @@
+#ifndef WRIGHTCLICKBUTTON_H
+#define WRIGHTCLICKBUTTON_H
+
+#include
+#include
+#include
+#include
+
+class WFeatureClickButton : public QToolButton
+{
+ Q_OBJECT
+
+public:
+ WFeatureClickButton(LibraryFeature* pFeature = nullptr,
+ QWidget* parent = nullptr);
+
+signals:
+
+ void clicked(LibraryFeature*);
+ void rightClicked(const QPoint&);
+ void hoverShow(LibraryFeature*);
+
+protected:
+
+ void mousePressEvent(QMouseEvent* event);
+
+ void dragEnterEvent(QDragEnterEvent* event);
+ void dragLeaveEvent(QDragLeaveEvent*);
+ void dropEvent(QDropEvent* event);
+
+ void timerEvent(QTimerEvent* event);
+
+private slots:
+
+ void slotClicked();
+
+private:
+
+ static const int kHoverTime;
+
+ LibraryFeature* m_pFeature;
+ QBasicTimer m_hoverTimer;
+};
+
+#endif // WRIGHTCLICKBUTTON_H
diff --git a/src/widget/wlibrary.cpp b/src/widget/wlibrary.cpp
index bcd01d52edd9..238632a1a4da 100644
--- a/src/widget/wlibrary.cpp
+++ b/src/widget/wlibrary.cpp
@@ -9,44 +9,35 @@
#include "controllers/keyboard/keyboardeventfilter.h"
WLibrary::WLibrary(QWidget* parent)
- : QStackedWidget(parent),
- WBaseWidget(this),
+ : WBaseLibrary(parent),
m_mutex(QMutex::Recursive) {
+
}
-bool WLibrary::registerView(QString name, QWidget* view) {
+bool WLibrary::registerView(LibraryFeature *pFeature, QWidget* pView) {
QMutexLocker lock(&m_mutex);
- if (m_viewMap.contains(name)) {
- return false;
- }
- if (dynamic_cast(view) == nullptr) {
+ if (pFeature == nullptr || dynamic_cast(pView) == nullptr) {
qDebug() << "WARNING: Attempted to register a view with WLibrary "
<< "that does not implement the LibraryView interface. "
<< "Ignoring.";
return false;
}
- addWidget(view);
- m_viewMap[name] = view;
- return true;
+ return WBaseLibrary::registerView(pFeature, pView);
}
-void WLibrary::switchToView(const QString& name) {
+void WLibrary::switchToFeature(LibraryFeature *pFeature) {
QMutexLocker lock(&m_mutex);
- //qDebug() << "WLibrary::switchToView" << name;
- QWidget* widget = m_viewMap.value(name, nullptr);
- if (widget != nullptr) {
- LibraryView * lview = dynamic_cast(widget);
- if (lview == nullptr) {
+ auto it = m_featureMap.find(pFeature);
+ if (it != m_featureMap.end()) {
+ LibraryView* pView = dynamic_cast(*it);
+ if (pView == nullptr) {
qDebug() << "WARNING: Attempted to register a view with WLibrary "
<< "that does not implement the LibraryView interface. "
<< "Ignoring.";
return;
}
- if (currentWidget() != widget) {
- //qDebug() << "WLibrary::setCurrentWidget" << name;
- setCurrentWidget(widget);
- lview->onShow();
- }
+ WBaseLibrary::switchToFeature(pFeature);
+ pView->onShow();
}
}
@@ -66,10 +57,3 @@ void WLibrary::search(const QString& name) {
LibraryView* WLibrary::getActiveView() const {
return dynamic_cast(currentWidget());
}
-
-bool WLibrary::event(QEvent* pEvent) {
- if (pEvent->type() == QEvent::ToolTip) {
- updateTooltip();
- }
- return QStackedWidget::event(pEvent);
-}
diff --git a/src/widget/wlibrary.h b/src/widget/wlibrary.h
index 6c6ccb943ff9..7115b3933e06 100644
--- a/src/widget/wlibrary.h
+++ b/src/widget/wlibrary.h
@@ -11,11 +11,11 @@
#include
#include "library/libraryview.h"
-#include "widget/wbasewidget.h"
+#include "widget/wbaselibrary.h"
class KeyboardEventFilter;
-class WLibrary : public QStackedWidget, public WBaseWidget {
+class WLibrary : public WBaseLibrary {
Q_OBJECT
public:
explicit WLibrary(QWidget* parent);
@@ -26,24 +26,20 @@ class WLibrary : public QStackedWidget, public WBaseWidget {
// the view and is in charge of deleting it. Returns whether or not the
// registration was successful. Registered widget must implement the
// LibraryView interface.
- bool registerView(QString name, QWidget* view);
+ bool registerView(LibraryFeature* pFeature, QWidget *pView);
LibraryView* getActiveView() const;
-
+
public slots:
// Show the view registered with the given name. Does nothing if the current
// view is the specified view, or if the name does not specify any
// registered view.
- void switchToView(const QString& name);
+ void switchToFeature(LibraryFeature* pFeature);
void search(const QString&);
- protected:
- bool event(QEvent* pEvent) override;
-
private:
QMutex m_mutex;
- QMap m_viewMap;
};
#endif /* WLIBRARY_H */
diff --git a/src/widget/wlibrarybreadcrumb.cpp b/src/widget/wlibrarybreadcrumb.cpp
new file mode 100644
index 000000000000..d76d334b3d06
--- /dev/null
+++ b/src/widget/wlibrarybreadcrumb.cpp
@@ -0,0 +1,54 @@
+#include
+
+#include
+
+namespace {
+
+QString getPathString(TreeItem* pTree) {
+ // Base case
+ if (pTree == nullptr || pTree->getFeature() == nullptr) {
+ return QString();
+ }
+ else if (pTree->parent() == nullptr) {
+ return pTree->getFeature()->title().toString();
+ }
+
+ // Recursive case
+ QString text = pTree->data().toString();
+ QString next = getPathString(pTree->parent());
+ return next % QLatin1Literal(" > ") % text;
+}
+
+} // NAMESPACE
+
+
+WLibraryBreadCrumb::WLibraryBreadCrumb(QWidget* parent)
+ : QLabel(parent) {
+ setText("I'm a BreadCrumb");
+}
+
+void WLibraryBreadCrumb::setText(const QString &text) {
+ m_longText = text;
+ QFontMetrics metrics(font());
+
+ // Measure the text for the label width
+ QString elidedText = metrics.elidedText(m_longText, Qt::ElideRight, width() - 10);
+ QLabel::setText(elidedText);
+}
+
+QString WLibraryBreadCrumb::text() const {
+ return m_longText;
+}
+
+QSize WLibraryBreadCrumb::minimumSizeHint() const {
+ return QSize(0, height());
+}
+
+void WLibraryBreadCrumb::showBreadCrumb(TreeItem *pTree) {
+ setText(getPathString(pTree));
+}
+
+void WLibraryBreadCrumb::resizeEvent(QResizeEvent *pEvent) {
+ QLabel::resizeEvent(pEvent);
+ setText(m_longText);
+}
diff --git a/src/widget/wlibrarybreadcrumb.h b/src/widget/wlibrarybreadcrumb.h
new file mode 100644
index 000000000000..f22fb801e3e3
--- /dev/null
+++ b/src/widget/wlibrarybreadcrumb.h
@@ -0,0 +1,32 @@
+#ifndef SRC_WIDGET_WBREADCRUMB_H_
+#define SRC_WIDGET_WBREADCRUMB_H_
+
+#include
+#include "library/treeitem.h"
+
+class WLibraryBreadCrumb : public QLabel {
+ Q_OBJECT
+
+ public:
+
+ WLibraryBreadCrumb(QWidget* parent = nullptr);
+
+ void setText(const QString& text);
+ QString text() const;
+
+ virtual QSize minimumSizeHint() const;
+
+ public slots:
+
+ void showBreadCrumb(TreeItem* pTree);
+
+ protected:
+
+ virtual void resizeEvent(QResizeEvent* pEvent);
+
+ private:
+
+ QString m_longText;
+};
+
+#endif /* SRC_WIDGET_WBREADCRUMB_H_ */
diff --git a/src/widget/wlibrarysidebar.cpp b/src/widget/wlibrarysidebar.cpp
index 5a3c6b16c4f1..3638159466c7 100644
--- a/src/widget/wlibrarysidebar.cpp
+++ b/src/widget/wlibrarysidebar.cpp
@@ -7,6 +7,7 @@
#include
#include "library/sidebarmodel.h"
+#include "library/treeitemmodel.h"
#include "util/dnd.h"
const int expand_time = 250;
@@ -38,7 +39,7 @@ void WLibrarySidebar::contextMenuEvent(QContextMenuEvent *event) {
// Drag enter event, happens when a dragged item enters the track sources view
void WLibrarySidebar::dragEnterEvent(QDragEnterEvent * event) {
- qDebug() << "WLibrarySidebar::dragEnterEvent" << event->mimeData()->formats();
+ //qDebug() << "WLibrarySidebar::dragEnterEvent" << event->mimeData()->formats();
if (event->mimeData()->hasUrls()) {
// We don't have a way to ask the LibraryFeatures whether to accept a
// drag so for now we accept all drags. Since almost every
@@ -94,6 +95,20 @@ void WLibrarySidebar::dragMoveEvent(QDragMoveEvent * event) {
break;
}
}
+ } else {
+ TreeItemModel* treeModel = dynamic_cast(model());
+ if (treeModel) {
+ accepted = false;
+
+ for (const QUrl& url : urls) {
+ QModelIndex destIndex = this->indexAt(event->pos());
+ if (treeModel->dragMoveAccept(destIndex, url)) {
+ accepted = true;
+ break;
+ }
+ }
+
+ }
}
if (accepted) {
event->acceptProposedAction();
@@ -135,6 +150,7 @@ void WLibrarySidebar::dropEvent(QDropEvent * event) {
//Drag-and-drop from an external application or the track table widget
//eg. dragging a track from Windows Explorer onto the sidebar
SidebarModel* sidebarModel = dynamic_cast(model());
+
if (sidebarModel) {
QModelIndex destIndex = indexAt(event->pos());
// event->source() will return NULL if something is droped from
@@ -145,6 +161,17 @@ void WLibrarySidebar::dropEvent(QDropEvent * event) {
} else {
event->ignore();
}
+ } else {
+ TreeItemModel* pTreeModel = dynamic_cast(model());
+ if (pTreeModel) {
+ QModelIndex destIndex = indexAt(event->pos());
+ QList urls(event->mimeData()->urls());
+ if (pTreeModel->dropAccept(destIndex, urls, event->source())) {
+ event->acceptProposedAction();
+ } else {
+ event->ignore();
+ }
+ }
}
}
//emit(trackDropped(name));
diff --git a/src/widget/wlibrarysidebar.h b/src/widget/wlibrarysidebar.h
index 68490afa3d81..07ce76915929 100644
--- a/src/widget/wlibrarysidebar.h
+++ b/src/widget/wlibrarysidebar.h
@@ -13,6 +13,7 @@
#include
#include "widget/wbasewidget.h"
+#include "library/libraryview.h"
class WLibrarySidebar : public QTreeView, public WBaseWidget {
Q_OBJECT
diff --git a/src/widget/wlibrarystack.cpp b/src/widget/wlibrarystack.cpp
new file mode 100644
index 000000000000..1a7c431990a5
--- /dev/null
+++ b/src/widget/wlibrarystack.cpp
@@ -0,0 +1,69 @@
+#include
+
+#include "widget/wlibrarystack.h"
+
+WLibraryStack::WLibraryStack(QWidget* parent)
+ : QStackedWidget(parent) {
+ // TODO Auto-generated constructor stub
+
+}
+
+WLibraryStack::~WLibraryStack() {
+ // TODO Auto-generated destructor stub
+}
+
+int WLibraryStack::addWidget(QWidget* w) {
+ //qDebug() << "WLibraryStack::addWidget" << w;
+ checkAndWarning(w);
+ return QStackedWidget::addWidget(w);
+}
+
+int WLibraryStack::insertWidget(int index, QWidget* w) {
+ checkAndWarning(w);
+ return QStackedWidget::insertWidget(index, w);
+}
+
+void WLibraryStack::onShow() {
+
+}
+
+void WLibraryStack::onSearch(const QString& text) {
+ LibraryView* pView = dynamic_cast(currentWidget());
+
+ if (pView) {
+ pView->onSearch(text);
+ }
+}
+
+void WLibraryStack::loadSelectedTrack() {
+ LibraryView* pView = dynamic_cast(currentWidget());
+
+ if (pView) {
+ pView->loadSelectedTrack();
+ }
+}
+
+void WLibraryStack::slotSendToAutoDJ() {
+ LibraryView* pView = dynamic_cast(currentWidget());
+
+ if (pView) {
+ pView->slotSendToAutoDJ();
+ }
+}
+
+void WLibraryStack::slotSendToAutoDJTop() {
+ LibraryView* pView = dynamic_cast(currentWidget());
+
+ if (pView) {
+ pView->slotSendToAutoDJTop();
+ }
+}
+
+bool WLibraryStack::checkAndWarning(QWidget* w) {
+ if (!dynamic_cast