Merge lp:~mhaulo/mixxx/crate-and-playlist-lock into lp:~mixxxdevelopers/mixxx/trunk
- crate-and-playlist-lock
- Merge into trunk
Status: | Merged | ||||
---|---|---|---|---|---|
Merged at revision: | 2644 | ||||
Proposed branch: | lp:~mhaulo/mixxx/crate-and-playlist-lock | ||||
Merge into: | lp:~mixxxdevelopers/mixxx/trunk | ||||
Diff against target: |
1011 lines (+458/-79) (has conflicts) 20 files modified
mixxx/res/images/templates/ic_template_library_and_preferences.svg (+30/-7) mixxx/res/mixxx.qrc (+1/-0) mixxx/res/schema.xml (+9/-0) mixxx/src/library/cratefeature.cpp (+96/-6) mixxx/src/library/cratefeature.h (+2/-0) mixxx/src/library/cratetablemodel.cpp (+41/-20) mixxx/src/library/dao/cratedao.cpp (+45/-0) mixxx/src/library/dao/cratedao.h (+2/-0) mixxx/src/library/dao/playlistdao.cpp (+45/-0) mixxx/src/library/dao/playlistdao.h (+4/-0) mixxx/src/library/playlistfeature.cpp (+98/-6) mixxx/src/library/playlistfeature.h (+4/-2) mixxx/src/library/playlisttablemodel.cpp (+34/-21) mixxx/src/library/sidebarmodel.cpp (+6/-2) mixxx/src/library/trackcollection.cpp (+1/-1) mixxx/src/library/trackmodel.h (+1/-0) mixxx/src/library/treeitem.cpp (+12/-0) mixxx/src/library/treeitem.h (+7/-0) mixxx/src/library/treeitemmodel.cpp (+2/-2) mixxx/src/widget/wtracktableview.cpp (+18/-12) Text conflict in mixxx/src/library/cratefeature.cpp Text conflict in mixxx/src/library/playlistfeature.cpp Text conflict in mixxx/src/library/treeitem.h |
||||
To merge this branch: | bzr merge lp:~mhaulo/mixxx/crate-and-playlist-lock | ||||
Related bugs: |
|
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
RJ Skerry-Ryan | Approve | ||
Phillip Whelan | code review | Needs Fixing | |
Review via email: mp+47554@code.launchpad.net |
Commit message
Description of the change
An implementation for wishlist issue #661466 (https:/
Phillip Whelan (pwhelan) wrote : | # |
- 2633. By Mika Haulo
-
A fix to prevent compiler switching the order of boolean expressions.
Mika Haulo (mhaulo) wrote : | # |
Yep, you're right about that. r2633 should fix it.
RJ Skerry-Ryan (rryan) wrote : | # |
@Phil The && operator isn't associative, so the compiler should never violate the evaluation order. Tons of code out there relies on short-circuiting for evaluation. Is this documented somewhere? I'd be pretty shocked if there was an optimizing compiler out there that would do that.
@Mika This all looks very good. I think we should keep the 'Remove' option in the context menu for the crate and playlist table models though and just make it not enabled. Ideally we could add a lock icon to the QAction so that there is some feedback that the option is locked. Also, as for drag-and-dropping onto the playlist or crate I think it would be more natural to just deny the drag-and-drop so it shows up as an 'X' as they hover over it instead of showing the "+" and then popping up a dialog box. What do you think?
Thanks!
RJ
RJ Skerry-Ryan (rryan) wrote : | # |
Here are my thoughts on what needs fixing:
- Since you've worked on this (I'm guessing you based it on Mixxx 1.9) a feature to rename crates and playlists was added to trunk. The locking should affect renaming of the crates and playlists too.
- As I mentioned above, to reject drags to locked Playlists/Crates, just implement Crate/PlaylistF
- I think the 'Remove' option for Crates and Playlists should be grayed out instead of omitted so that people don't wonder where it went.
- Similarly, the Remove option in the track-table view should be grayed out instead of omitted.
- Crates and playlists that are locked should be grayed out in the 'Add to Crate' and 'Add to Playlist' context menu's in the TrackTableView.
I'm totally up for helping fix these minor things if you're short on time. When it's ready we can merge it to trunk and it'll be part of the Mixxx 1.10 release. Thanks again for your work, Mika. Finally, sorry it took me so long to get a review done for this -- life changes were afoot :).
Cheers,
RJ
Mika Haulo (mhaulo) wrote : | # |
On Friday 11 February 2011 05:02:54 RJ Ryan wrote:
> @Mika This all looks very good. I think we should keep the 'Remove' option
> in the context menu for the crate and playlist table models though and
> just make it not enabled. Ideally we could add a lock icon to the QAction
> so that there is some feedback that the option is locked. Also, as for
> drag-and-dropping onto the playlist or crate I think it would be more
> natural to just deny the drag-and-drop so it shows up as an 'X' as they
> hover over it instead of showing the "+" and then popping up a dialog box.
> What do you think?
Sure, that makes sense. I'll make some fixes soon.
> - Since you've worked on this (I'm guessing you based it on Mixxx 1.9) a
> feature to rename crates and playlists was added to trunk. The locking
> should affect renaming of the crates and playlists too.
>
There was some discussion if locking should affect renaming (and deleting) or
not. I decided to leave renaming enabled and wait for comments. But I guess it
makes more sense that locking really prevents all modifications, including
renaming.
--
MH
- 2634. By Mika Haulo
-
Review fixes
Mika Haulo (mhaulo) wrote : | # |
On Feb 11, 2011, at 5:27 AM, RJ Ryan wrote:
>
> I'm totally up for helping fix these minor things if you're short on time.
Thanks RJ, I would actually appreciate some help at least on testing. I started in a new job on monday and the next couple of weeks feel a little bit hectic. I pushed some changes you proposed to my branch. Seems to be working on my machine, but if there's anything else to do or fix, go ahead and take control if you want.
--
MH
RJ Skerry-Ryan (rryan) wrote : | # |
Hey Mika,
I tested everything out and merged your branch into the Mixxx trunk after fixing a couple minor issues.
Thanks so much for your work on this! I've credited you in the credits as "Mika Haulo". Please let me know if you'd like me to change it to something different. This code will see its first release in Mixxx 1.10.0.
RJ Ryan
Preview Diff
1 | === added file 'mixxx/res/images/library/ic_library_locked.png' |
2 | Binary files mixxx/res/images/library/ic_library_locked.png 1970-01-01 00:00:00 +0000 and mixxx/res/images/library/ic_library_locked.png 2011-02-15 19:56:49 +0000 differ |
3 | === modified file 'mixxx/res/images/templates/ic_template_library_and_preferences.svg' |
4 | --- mixxx/res/images/templates/ic_template_library_and_preferences.svg 2010-11-22 15:24:51 +0000 |
5 | +++ mixxx/res/images/templates/ic_template_library_and_preferences.svg 2011-02-15 19:56:49 +0000 |
6 | @@ -13,7 +13,7 @@ |
7 | inkscape:export-filename="" |
8 | style="display:inline" |
9 | sodipodi:docname="ic_template_library_and_preferences.svg" |
10 | - inkscape:version="0.48.0 r9654" |
11 | + inkscape:version="0.48+devel r9889" |
12 | id="svg2" |
13 | height="32" |
14 | width="32" |
15 | @@ -32,7 +32,7 @@ |
16 | id="namedview26" |
17 | showgrid="true" |
18 | inkscape:zoom="10" |
19 | - inkscape:cx="30.145312" |
20 | + inkscape:cx="11.595312" |
21 | inkscape:cy="29.45" |
22 | inkscape:window-x="1280" |
23 | inkscape:window-y="0" |
24 | @@ -781,9 +781,9 @@ |
25 | <rdf:RDF> |
26 | <rdf:Description |
27 | rdf:about=""> |
28 | - <dc:title></dc:title> |
29 | - <dc:creator></dc:creator> |
30 | - <dc:rights></dc:rights> |
31 | + <dc:title /> |
32 | + <dc:creator /> |
33 | + <dc:rights /> |
34 | <dc:description /> |
35 | <dc:format>image/svg+xml</dc:format> |
36 | <dc:language>en</dc:language> |
37 | @@ -933,6 +933,29 @@ |
38 | </g> |
39 | <g |
40 | inkscape:groupmode="layer" |
41 | + id="layer5" |
42 | + inkscape:label="locked.png" |
43 | + style="display:none" |
44 | + sodipodi:insensitive="true"> |
45 | + <path |
46 | + style="fill:none;stroke:#000000;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none" |
47 | + d="m 9.5,14 c 0,0 0.012953,-3 0,-4.5 -0.012957,-1.5004487 0.4612148,-5.9608363 6.5,-6 6,-0.038912 6.495685,4.4997009 6.5,7 0.0026,1.5 0,3.5 0,3.5" |
48 | + id="path8889" |
49 | + inkscape:connector-curvature="0" |
50 | + sodipodi:nodetypes="csssc" /> |
51 | + <path |
52 | + style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#000000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans" |
53 | + d="m 6,14 c -1,0 -2,1 -2,2 l 0,12 c 0,1 1,2 2,2 l 20,0 c 1,0 2,-1 2,-2 l 0,-12 c 0,-1 -1,-2 -2,-2 z M 9.03125,18 23,18 c 0.522127,0 0.997189,0.476401 0.997189,1 0,0.523599 -0.475062,1 -0.997189,1 L 9.03125,20 C 8.4410263,20 8,19.478827 8,19 8,18.521173 8.4261918,18 9.03125,18 z m 0,4 L 23,22 c 0.522127,0 0.997189,0.476401 0.997189,1 0,0.523599 -0.475062,1 -0.997189,1 L 9.03125,24 C 8.4896665,24 8,23.478827 8,23 8,22.521173 8.4836539,22 9.03125,22 z m 0,4 L 23,26 c 0.522127,0 0.997189,0.476401 0.997189,1 0,0.523599 -0.475062,1 -0.997189,1 L 9.03125,28 C 8.4799385,28 8,27.478827 8,27 8,26.521173 8.4473629,26 9.03125,26 z" |
54 | + id="rect8885" |
55 | + inkscape:connector-curvature="0" |
56 | + sodipodi:nodetypes="ssssssssscssscaccssscaccssscac" /> |
57 | + <g |
58 | + id="g8895" |
59 | + style="fill:#0e232e;stroke:#0e232e;stroke-width:0.99776536" |
60 | + transform="matrix(1.0044843,0,0,1,26.044843,18)" /> |
61 | + </g> |
62 | + <g |
63 | + inkscape:groupmode="layer" |
64 | id="layer39" |
65 | inkscape:label="library.png" |
66 | style="display:none" |
67 | @@ -1225,7 +1248,7 @@ |
68 | sodipodi:cy="7" |
69 | sodipodi:rx="5" |
70 | sodipodi:ry="5" |
71 | - d="M 12,7 A 5,5 0 1 1 2,7 5,5 0 1 1 12,7 z" |
72 | + d="M 12,7 C 12,9.7614237 9.7614237,12 7,12 4.2385763,12 2,9.7614237 2,7 2,4.2385763 4.2385763,2 7,2 c 2.7614237,0 5,2.2385763 5,5 z" |
73 | transform="matrix(1.9222927,0,0,1.9222927,0.5439511,-13.456048)" /> |
74 | <path |
75 | sodipodi:type="arc" |
76 | @@ -1235,7 +1258,7 @@ |
77 | sodipodi:cy="6" |
78 | sodipodi:rx="1.4933327" |
79 | sodipodi:ry="1.4933327" |
80 | - d="M 7.4933327,6 A 1.4933327,1.4933327 0 1 1 4.5066673,6 1.4933327,1.4933327 0 1 1 7.4933327,6 z" |
81 | + d="M 7.4933327,6 C 7.4933327,6.8247449 6.8247449,7.4933327 6,7.4933327 5.1752551,7.4933327 4.5066673,6.8247449 4.5066673,6 4.5066673,5.1752551 5.1752551,4.5066673 6,4.5066673 6.8247449,4.5066673 7.4933327,5.1752551 7.4933327,6 z" |
82 | transform="matrix(1.3392862,0,0,1.3392862,5.9642827,-8.0357171)" /> |
83 | </g> |
84 | </g> |
85 | |
86 | === modified file 'mixxx/res/mixxx.qrc' |
87 | --- mixxx/res/mixxx.qrc 2010-12-22 21:42:46 +0000 |
88 | +++ mixxx/res/mixxx.qrc 2011-02-15 19:56:49 +0000 |
89 | @@ -24,6 +24,7 @@ |
90 | <file>images/library/ic_library_crates.png</file> |
91 | <file>images/library/ic_library_itunes.png</file> |
92 | <file>images/library/ic_library_library.png</file> |
93 | + <file>images/library/ic_library_locked.png</file> |
94 | <file>images/library/ic_library_playlist.png</file> |
95 | <file>images/library/ic_library_prepare.png</file> |
96 | <file>images/library/ic_library_promotracks.png</file> |
97 | |
98 | === modified file 'mixxx/res/schema.xml' |
99 | --- mixxx/res/schema.xml 2011-01-06 13:53:48 +0000 |
100 | +++ mixxx/res/schema.xml 2011-02-15 19:56:49 +0000 |
101 | @@ -228,4 +228,13 @@ |
102 | ); |
103 | </sql> |
104 | </revision> |
105 | + <revision version="10" min_compatible="3"> |
106 | + <description> |
107 | + Playlist and crate locks |
108 | + </description> |
109 | + <sql> |
110 | + ALTER TABLE crates ADD COLUMN locked integer DEFAULT 0; |
111 | + ALTER TABLE playlists ADD COLUMN locked integer DEFAULT 0; |
112 | + </sql> |
113 | + </revision> |
114 | </schema> |
115 | |
116 | === modified file 'mixxx/src/library/cratefeature.cpp' |
117 | --- mixxx/src/library/cratefeature.cpp 2011-01-13 18:40:56 +0000 |
118 | +++ mixxx/src/library/cratefeature.cpp 2011-02-15 19:56:49 +0000 |
119 | @@ -33,7 +33,11 @@ |
120 | |
121 | m_pRenameCrateAction = new QAction(tr("Rename"),this); |
122 | connect(m_pRenameCrateAction, SIGNAL(triggered()), |
123 | - this, SLOT(slotRenameCrate())); |
124 | + this, SLOT(slotRenameCrate())); |
125 | + |
126 | + m_pLockCrateAction = new QAction(tr("Lock"),this); |
127 | + connect(m_pLockCrateAction, SIGNAL(triggered()), |
128 | + this, SLOT(slotToggleCrateLock())); |
129 | |
130 | m_pImportPlaylistAction = new QAction(tr("Import Playlist"),this); |
131 | connect(m_pImportPlaylistAction, SIGNAL(triggered()), |
132 | @@ -55,8 +59,18 @@ |
133 | QModelIndex ind = m_crateListTableModel.index(row, idColumn); |
134 | QString crate_name = m_crateListTableModel.data(ind).toString(); |
135 | TreeItem *playlist_item = new TreeItem(crate_name, crate_name, this, rootItem); |
136 | + CrateDAO crateDao = m_pTrackCollection->getCrateDAO(); |
137 | + int crateID = crateDao.getCrateIdByName(crate_name); |
138 | + bool locked = crateDao.isCrateLocked(crateID); |
139 | + |
140 | + if (locked) { |
141 | + playlist_item->setIcon(QIcon(":/images/library/ic_library_locked.png")); |
142 | + } |
143 | + else { |
144 | + playlist_item->setIcon(QIcon()); |
145 | + } |
146 | + |
147 | rootItem->appendChild(playlist_item); |
148 | - |
149 | } |
150 | m_childModel.setRootItem(rootItem); |
151 | |
152 | @@ -67,6 +81,7 @@ |
153 | delete m_pCreateCrateAction; |
154 | delete m_pDeleteCrateAction; |
155 | delete m_pRenameCrateAction; |
156 | + delete m_pLockCrateAction; |
157 | delete m_pImportPlaylistAction; |
158 | |
159 | } |
160 | @@ -101,8 +116,10 @@ |
161 | qDebug() << "CrateFeature::dropAcceptChild adding track" |
162 | << trackId << "to crate" << crateId; |
163 | |
164 | + CrateDAO& crateDao = m_pTrackCollection->getCrateDAO(); |
165 | + |
166 | if (trackId >= 0) |
167 | - return m_pTrackCollection->getCrateDAO().addTrackToCrate(trackId, crateId); |
168 | + return crateDao.addTrackToCrate(trackId, crateId); |
169 | return false; |
170 | } |
171 | |
172 | @@ -112,7 +129,12 @@ |
173 | |
174 | bool CrateFeature::dragMoveAcceptChild(const QModelIndex& index, QUrl url) { |
175 | //TODO: Filter by supported formats regex and reject anything that doesn't match. |
176 | - return true; |
177 | + QString crateName = index.data().toString(); |
178 | + CrateDAO& crateDao = m_pTrackCollection->getCrateDAO(); |
179 | + int crateId = crateDao.getCrateIdByName(crateName); |
180 | + bool locked = crateDao.isCrateLocked(crateId); |
181 | + |
182 | + return !locked; |
183 | } |
184 | |
185 | void CrateFeature::bindWidget(WLibrarySidebar* sidebarWidget, |
186 | @@ -152,12 +174,27 @@ |
187 | void CrateFeature::onRightClickChild(const QPoint& globalPos, QModelIndex index) { |
188 | //Save the model index so we can get it in the action slots... |
189 | m_lastRightClickedIndex = index; |
190 | + QString crateName = index.data().toString(); |
191 | + CrateDAO& crateDAO = m_pTrackCollection->getCrateDAO(); |
192 | + int crateId = crateDAO.getCrateIdByName(crateName); |
193 | + bool locked = crateDAO.isCrateLocked(crateId); |
194 | + m_pDeleteCrateAction->setEnabled(!locked); |
195 | + m_pRenameCrateAction->setEnabled(!locked); |
196 | + |
197 | + if (locked) { |
198 | + m_pLockCrateAction->setText(tr("Unlock")); |
199 | + |
200 | + } |
201 | + else { |
202 | + m_pLockCrateAction->setText(tr("Lock")); |
203 | + } |
204 | |
205 | QMenu menu(NULL); |
206 | menu.addAction(m_pCreateCrateAction); |
207 | menu.addSeparator(); |
208 | menu.addAction(m_pRenameCrateAction); |
209 | menu.addAction(m_pDeleteCrateAction); |
210 | + menu.addAction(m_pLockCrateAction); |
211 | menu.addSeparator(); |
212 | menu.addAction(m_pImportPlaylistAction); |
213 | menu.exec(globalPos); |
214 | @@ -222,9 +259,12 @@ |
215 | |
216 | void CrateFeature::slotDeleteCrate() { |
217 | QString crateName = m_lastRightClickedIndex.data().toString(); |
218 | - int crateId = m_pTrackCollection->getCrateDAO().getCrateIdByName(crateName); |
219 | + CrateDAO crateDao = m_pTrackCollection->getCrateDAO(); |
220 | + int crateId = crateDao.getCrateIdByName(crateName); |
221 | + bool locked = crateDao.isCrateLocked(crateId); |
222 | + bool deleted = crateDao.deleteCrate(crateId); |
223 | |
224 | - if (m_pTrackCollection->getCrateDAO().deleteCrate(crateId)) { |
225 | + if (deleted) { |
226 | clearChildModel(); |
227 | m_crateListTableModel.select(); |
228 | constructChildModel(); |
229 | @@ -282,6 +322,29 @@ |
230 | qDebug() << "Failed to rename crateId" << crateId; |
231 | } |
232 | } |
233 | + |
234 | +void CrateFeature::slotToggleCrateLock() |
235 | +{ |
236 | + QString crateName = m_lastRightClickedIndex.data().toString(); |
237 | + CrateDAO& crateDAO = m_pTrackCollection->getCrateDAO(); |
238 | + int crateId = crateDAO.getCrateIdByName(crateName); |
239 | + bool locked = !crateDAO.isCrateLocked(crateId); |
240 | + |
241 | + if (!crateDAO.setCrateLocked(crateId, locked)) { |
242 | + qDebug() << "Failed to toggle lock of crateId " << crateId; |
243 | + } |
244 | + |
245 | + TreeItem* crateItem = m_childModel.getItem(m_lastRightClickedIndex); |
246 | + |
247 | + if (locked) { |
248 | + crateItem->setIcon(QIcon(":/images/library/ic_library_locked.png")); |
249 | + } |
250 | + else { |
251 | + crateItem->setIcon(QIcon()); |
252 | + } |
253 | +} |
254 | + |
255 | + |
256 | /** |
257 | * Purpose: When inserting or removing playlists, |
258 | * we require the sidebar model not to reset. |
259 | @@ -291,18 +354,45 @@ |
260 | { |
261 | QList<TreeItem*> data_list; |
262 | int idColumn = m_crateListTableModel.record().indexOf("name"); |
263 | +<<<<<<< TREE |
264 | //Access the invisible root item |
265 | TreeItem* root = m_childModel.getItem(QModelIndex()); |
266 | |
267 | +======= |
268 | + CrateDAO crateDao = m_pTrackCollection->getCrateDAO(); |
269 | + |
270 | +>>>>>>> MERGE-SOURCE |
271 | for (int row = 0; row < m_crateListTableModel.rowCount(); ++row) { |
272 | QModelIndex ind = m_crateListTableModel.index(row, idColumn); |
273 | QString crate_name = m_crateListTableModel.data(ind).toString(); |
274 | +<<<<<<< TREE |
275 | //Create the TreeItem whose parent is the invisible root item |
276 | TreeItem* item = new TreeItem(crate_name, crate_name, this, root); |
277 | data_list.append(item); |
278 | } |
279 | //Append all the newly created TreeItems in a dynamic way to the childmodel |
280 | m_childModel.insertRows(data_list, 0, m_crateListTableModel.rowCount()); |
281 | +======= |
282 | + data_list.append(crate_name); |
283 | + } |
284 | + |
285 | + m_childModel.insertRows(data_list, 0, m_crateListTableModel.rowCount()); |
286 | + |
287 | + for (int row = 0; row < m_childModel.rowCount(); ++row) { |
288 | + QModelIndex ind = m_childModel.index(row, 0); |
289 | + QString crate_name = m_childModel.data(ind, Qt::DisplayRole).toString(); |
290 | + int crateID = crateDao.getCrateIdByName(crate_name); |
291 | + bool locked = crateDao.isCrateLocked(crateID); |
292 | + TreeItem* playlist_item = m_childModel.getItem(ind); |
293 | + |
294 | + if (locked) { |
295 | + playlist_item->setIcon(QIcon(":/images/library/ic_library_locked.png")); |
296 | + } |
297 | + else { |
298 | + playlist_item->setIcon(QIcon()); |
299 | + } |
300 | + } |
301 | +>>>>>>> MERGE-SOURCE |
302 | } |
303 | /** |
304 | * Clears the child model dynamically |
305 | |
306 | === modified file 'mixxx/src/library/cratefeature.h' |
307 | --- mixxx/src/library/cratefeature.h 2011-01-01 14:49:21 +0000 |
308 | +++ mixxx/src/library/cratefeature.h 2011-02-15 19:56:49 +0000 |
309 | @@ -43,6 +43,7 @@ |
310 | void slotCreateCrate(); |
311 | void slotDeleteCrate(); |
312 | void slotRenameCrate(); |
313 | + void slotToggleCrateLock(); |
314 | void slotImportPlaylist(); |
315 | |
316 | private: |
317 | @@ -53,6 +54,7 @@ |
318 | QAction *m_pCreateCrateAction; |
319 | QAction *m_pDeleteCrateAction; |
320 | QAction *m_pRenameCrateAction; |
321 | + QAction *m_pLockCrateAction; |
322 | QAction *m_pImportPlaylistAction; |
323 | QSqlTableModel m_crateListTableModel; |
324 | CrateTableModel m_crateTableModel; |
325 | |
326 | === modified file 'mixxx/src/library/cratetablemodel.cpp' |
327 | --- mixxx/src/library/cratetablemodel.cpp 2010-11-16 22:08:45 +0000 |
328 | +++ mixxx/src/library/cratetablemodel.cpp 2011-02-15 19:56:49 +0000 |
329 | @@ -117,29 +117,38 @@ |
330 | } |
331 | |
332 | void CrateTableModel::removeTracks(const QModelIndexList& indices) { |
333 | - const int trackIdIndex = fieldIndex(LIBRARYTABLE_ID); |
334 | - |
335 | - QList<int> trackIds; |
336 | - foreach (QModelIndex index, indices) { |
337 | - int trackId = index.sibling(index.row(), fieldIndex(LIBRARYTABLE_ID)).data().toInt(); |
338 | - trackIds.append(trackId); |
339 | - } |
340 | - |
341 | CrateDAO& crateDao = m_pTrackCollection->getCrateDAO(); |
342 | - foreach (int trackId, trackIds) { |
343 | - crateDao.removeTrackFromCrate(trackId, m_iCrateId); |
344 | + bool locked = crateDao.isCrateLocked(m_iCrateId); |
345 | + |
346 | + if (!locked) { |
347 | + const int trackIdIndex = fieldIndex(LIBRARYTABLE_ID); |
348 | + |
349 | + QList<int> trackIds; |
350 | + foreach (QModelIndex index, indices) { |
351 | + int trackId = index.sibling(index.row(), fieldIndex(LIBRARYTABLE_ID)).data().toInt(); |
352 | + trackIds.append(trackId); |
353 | + } |
354 | + |
355 | + foreach (int trackId, trackIds) { |
356 | + crateDao.removeTrackFromCrate(trackId, m_iCrateId); |
357 | + } |
358 | + |
359 | + select(); |
360 | } |
361 | - |
362 | - select(); |
363 | } |
364 | |
365 | void CrateTableModel::removeTrack(const QModelIndex& index) { |
366 | - const int trackIdIndex = fieldIndex(LIBRARYTABLE_ID); |
367 | - int trackId = index.sibling(index.row(), trackIdIndex).data().toInt(); |
368 | - if (m_pTrackCollection->getCrateDAO().removeTrackFromCrate(trackId, m_iCrateId)) { |
369 | - select(); |
370 | - } else { |
371 | - // TODO(XXX) feedback |
372 | + CrateDAO& crateDao = m_pTrackCollection->getCrateDAO(); |
373 | + bool locked = crateDao.isCrateLocked(m_iCrateId); |
374 | + |
375 | + if (!locked) { |
376 | + const int trackIdIndex = fieldIndex(LIBRARYTABLE_ID); |
377 | + int trackId = index.sibling(index.row(), trackIdIndex).data().toInt(); |
378 | + if (m_pTrackCollection->getCrateDAO().removeTrackFromCrate(trackId, m_iCrateId)) { |
379 | + select(); |
380 | + } else { |
381 | + // TODO(XXX) feedback |
382 | + } |
383 | } |
384 | } |
385 | |
386 | @@ -235,6 +244,18 @@ |
387 | } |
388 | |
389 | TrackModel::CapabilitiesFlags CrateTableModel::getCapabilities() const { |
390 | - return TRACKMODELCAPS_RECEIVEDROPS | TRACKMODELCAPS_ADDTOPLAYLIST | |
391 | - TRACKMODELCAPS_ADDTOCRATE | TRACKMODELCAPS_ADDTOAUTODJ; |
392 | + |
393 | + CapabilitiesFlags caps = TRACKMODELCAPS_RECEIVEDROPS | |
394 | + TRACKMODELCAPS_ADDTOPLAYLIST | |
395 | + TRACKMODELCAPS_ADDTOCRATE | |
396 | + TRACKMODELCAPS_ADDTOAUTODJ; |
397 | + |
398 | + CrateDAO& crateDao = m_pTrackCollection->getCrateDAO(); |
399 | + bool locked = crateDao.isCrateLocked(m_iCrateId); |
400 | + |
401 | + if (locked) { |
402 | + caps |= TRACKMODELCAPS_LOCKED; |
403 | + } |
404 | + |
405 | + return caps; |
406 | } |
407 | |
408 | === modified file 'mixxx/src/library/dao/cratedao.cpp' |
409 | --- mixxx/src/library/dao/cratedao.cpp 2010-12-27 10:08:14 +0000 |
410 | +++ mixxx/src/library/dao/cratedao.cpp 2011-02-15 19:56:49 +0000 |
411 | @@ -70,6 +70,51 @@ |
412 | return true; |
413 | } |
414 | |
415 | +bool CrateDAO::setCrateLocked(int crateId, bool locked) { |
416 | + qDebug() << "setCrateLocked()"; |
417 | + |
418 | + // SQLite3 doesn't support boolean value. Using integer instead. |
419 | + int lock = 0; |
420 | + |
421 | + if (locked) { |
422 | + lock = 1; |
423 | + } |
424 | + |
425 | + Q_ASSERT(m_database.transaction()); |
426 | + QSqlQuery query; |
427 | + query.prepare("UPDATE " CRATE_TABLE " SET locked = :lock WHERE id = :id"); |
428 | + query.bindValue(":lock", lock); |
429 | + query.bindValue(":id", crateId); |
430 | + |
431 | + if (!query.exec()) { |
432 | + qDebug() << query.executedQuery() << query.lastError(); |
433 | + Q_ASSERT(m_database.rollback()); |
434 | + return false; |
435 | + } |
436 | + |
437 | + Q_ASSERT(m_database.commit()); |
438 | + return true; |
439 | +} |
440 | + |
441 | +bool CrateDAO::isCrateLocked(int crateId) { |
442 | + qDebug() << "isCrateLocked()"; |
443 | + |
444 | + QSqlQuery query; |
445 | + query.prepare("SELECT locked FROM " CRATE_TABLE " WHERE id = :id"); |
446 | + query.bindValue(":id", crateId); |
447 | + |
448 | + if (query.exec()) { |
449 | + if (query.next()) { |
450 | + int lockValue = query.value(0).toInt(); |
451 | + return lockValue == 1; |
452 | + } |
453 | + } else { |
454 | + qDebug() << query.lastError(); |
455 | + } |
456 | + |
457 | + return false; |
458 | +} |
459 | + |
460 | bool CrateDAO::deleteCrate(int crateId) { |
461 | Q_ASSERT(m_database.transaction()); |
462 | |
463 | |
464 | === modified file 'mixxx/src/library/dao/cratedao.h' |
465 | --- mixxx/src/library/dao/cratedao.h 2010-12-27 10:08:14 +0000 |
466 | +++ mixxx/src/library/dao/cratedao.h 2011-02-15 19:56:49 +0000 |
467 | @@ -24,6 +24,8 @@ |
468 | bool createCrate(const QString& name); |
469 | bool deleteCrate(int crateId); |
470 | bool renameCrate(int crateId, const QString& newName); |
471 | + bool setCrateLocked(int crateId, bool locked); |
472 | + bool isCrateLocked(int crateId); |
473 | int getCrateIdByName(const QString& name); |
474 | int getCrateId(int position); |
475 | QString crateName(int crateId); |
476 | |
477 | === modified file 'mixxx/src/library/dao/playlistdao.cpp' |
478 | --- mixxx/src/library/dao/playlistdao.cpp 2010-12-27 10:08:14 +0000 |
479 | +++ mixxx/src/library/dao/playlistdao.cpp 2011-02-15 19:56:49 +0000 |
480 | @@ -166,6 +166,51 @@ |
481 | } |
482 | |
483 | |
484 | +bool PlaylistDAO::setPlaylistLocked(int playlistId, bool locked) { |
485 | + qDebug() << "setPlaylistLocked()"; |
486 | + |
487 | + // SQLite3 doesn't support boolean value. Using integer instead. |
488 | + int lock = 0; |
489 | + |
490 | + if (locked) { |
491 | + lock = 1; |
492 | + } |
493 | + |
494 | + Q_ASSERT(m_database.transaction()); |
495 | + QSqlQuery query; |
496 | + query.prepare("UPDATE Playlists SET locked = :lock WHERE id = :id"); |
497 | + query.bindValue(":lock", lock); |
498 | + query.bindValue(":id", playlistId); |
499 | + |
500 | + if (!query.exec()) { |
501 | + qDebug() << query.executedQuery() << query.lastError(); |
502 | + Q_ASSERT(m_database.rollback()); |
503 | + return false; |
504 | + } |
505 | + |
506 | + Q_ASSERT(m_database.commit()); |
507 | + return true; |
508 | +} |
509 | + |
510 | +bool PlaylistDAO::isPlaylistLocked(int playlistId) { |
511 | + qDebug() << "isPlaylistLocked()"; |
512 | + |
513 | + QSqlQuery query; |
514 | + query.prepare("SELECT locked FROM Playlists WHERE id = :id"); |
515 | + query.bindValue(":id", playlistId); |
516 | + |
517 | + if (query.exec()) { |
518 | + if (query.next()) { |
519 | + int lockValue = query.value(0).toInt(); |
520 | + return lockValue == 1; |
521 | + } |
522 | + } else { |
523 | + qDebug() << query.lastError(); |
524 | + } |
525 | + |
526 | + return false; |
527 | +} |
528 | + |
529 | /** Append a track to a playlist */ |
530 | void PlaylistDAO::appendTrackToPlaylist(int trackId, int playlistId) |
531 | { |
532 | |
533 | === modified file 'mixxx/src/library/dao/playlistdao.h' |
534 | --- mixxx/src/library/dao/playlistdao.h 2010-12-27 10:08:14 +0000 |
535 | +++ mixxx/src/library/dao/playlistdao.h 2011-02-15 19:56:49 +0000 |
536 | @@ -19,6 +19,10 @@ |
537 | void deletePlaylist(int playlistId); |
538 | /** Rename a playlist */ |
539 | void renamePlaylist(int playlistId, const QString& newName); |
540 | + /** Lock or unlock a playlist */ |
541 | + bool setPlaylistLocked(int playlistId, bool locked); |
542 | + /** Find out the state of a playlist lock */ |
543 | + bool isPlaylistLocked(int playlistId); |
544 | /** Append a track to a playlist */ |
545 | void appendTrackToPlaylist(int trackId, int playlistId); |
546 | /** Find out how many playlists exist. */ |
547 | |
548 | === modified file 'mixxx/src/library/playlistfeature.cpp' |
549 | --- mixxx/src/library/playlistfeature.cpp 2011-01-13 18:40:56 +0000 |
550 | +++ mixxx/src/library/playlistfeature.cpp 2011-02-15 19:56:49 +0000 |
551 | @@ -38,6 +38,10 @@ |
552 | connect(m_pRenamePlaylistAction, SIGNAL(triggered()), |
553 | this, SLOT(slotRenamePlaylist())); |
554 | |
555 | + m_pLockPlaylistAction = new QAction(tr("Lock"),this); |
556 | + connect(m_pLockPlaylistAction, SIGNAL(triggered()), |
557 | + this, SLOT(slotTogglePlaylistLock())); |
558 | + |
559 | m_pImportPlaylistAction = new QAction(tr("Import Playlist"),this); |
560 | connect(m_pImportPlaylistAction, SIGNAL(triggered()), |
561 | this, SLOT(slotImportPlaylist())); |
562 | @@ -61,6 +65,17 @@ |
563 | QModelIndex ind = m_playlistTableModel.index(row, idColumn); |
564 | QString playlist_name = m_playlistTableModel.data(ind).toString(); |
565 | TreeItem *playlist_item = new TreeItem(playlist_name, playlist_name, this, rootItem); |
566 | + int playlistID = m_playlistDao.getPlaylistIdFromName(playlist_name); |
567 | + bool locked = m_playlistDao.isPlaylistLocked(playlistID); |
568 | + |
569 | + if (locked) { |
570 | + playlist_item->setIcon(QIcon(":/images/library/ic_library_locked.png")); |
571 | + } |
572 | + else { |
573 | + playlist_item->setIcon(QIcon()); |
574 | + } |
575 | + |
576 | + |
577 | rootItem->appendChild(playlist_item); |
578 | |
579 | } |
580 | @@ -73,6 +88,7 @@ |
581 | delete m_pDeletePlaylistAction; |
582 | delete m_pImportPlaylistAction; |
583 | delete m_pRenamePlaylistAction; |
584 | + delete m_pLockPlaylistAction; |
585 | } |
586 | |
587 | QVariant PlaylistFeature::title() { |
588 | @@ -120,13 +136,26 @@ |
589 | void PlaylistFeature::onRightClickChild(const QPoint& globalPos, QModelIndex index) { |
590 | //Save the model index so we can get it in the action slots... |
591 | m_lastRightClickedIndex = index; |
592 | - |
593 | + QString playlistName = index.data().toString(); |
594 | + int playlistId = m_playlistDao.getPlaylistIdFromName(playlistName); |
595 | + bool locked = m_playlistDao.isPlaylistLocked(playlistId); |
596 | + m_pDeletePlaylistAction->setEnabled(!locked); |
597 | + m_pRenamePlaylistAction->setEnabled(!locked); |
598 | + |
599 | + if (locked) { |
600 | + m_pLockPlaylistAction->setText(tr("Unlock")); |
601 | + } |
602 | + else { |
603 | + m_pLockPlaylistAction->setText(tr("Lock")); |
604 | + } |
605 | + |
606 | //Create the right-click menu |
607 | QMenu menu(NULL); |
608 | menu.addAction(m_pCreatePlaylistAction); |
609 | menu.addSeparator(); |
610 | menu.addAction(m_pRenamePlaylistAction); |
611 | menu.addAction(m_pDeletePlaylistAction); |
612 | + menu.addAction(m_pLockPlaylistAction); |
613 | menu.addSeparator(); |
614 | menu.addAction(m_pImportPlaylistAction); |
615 | menu.exec(globalPos); |
616 | @@ -235,20 +264,43 @@ |
617 | m_pPlaylistTableModel->setPlaylist(playlistId); |
618 | } |
619 | |
620 | + |
621 | +void PlaylistFeature::slotTogglePlaylistLock() |
622 | +{ |
623 | + QString playlistName = m_lastRightClickedIndex.data().toString(); |
624 | + int playlistId = m_playlistDao.getPlaylistIdFromName(playlistName); |
625 | + bool locked = !m_playlistDao.isPlaylistLocked(playlistId); |
626 | + |
627 | + if (!m_playlistDao.setPlaylistLocked(playlistId, locked)) { |
628 | + qDebug() << "Failed to toggle lock of playlistId " << playlistId; |
629 | + } |
630 | + |
631 | + TreeItem* playlistItem = m_childModel.getItem(m_lastRightClickedIndex); |
632 | + |
633 | + if (locked) { |
634 | + playlistItem->setIcon(QIcon(":/images/library/ic_library_locked.png")); |
635 | + } |
636 | + else { |
637 | + playlistItem->setIcon(QIcon()); |
638 | + } |
639 | +} |
640 | + |
641 | void PlaylistFeature::slotDeletePlaylist() |
642 | { |
643 | //qDebug() << "slotDeletePlaylist() row:" << m_lastRightClickedIndex.data(); |
644 | - if (m_lastRightClickedIndex.isValid()) { |
645 | - int playlistId = m_playlistDao.getPlaylistIdFromName(m_lastRightClickedIndex.data().toString()); |
646 | + int playlistId = m_playlistDao.getPlaylistIdFromName(m_lastRightClickedIndex.data().toString()); |
647 | + |
648 | + if (m_lastRightClickedIndex.isValid() && |
649 | + !m_playlistDao.isPlaylistLocked(playlistId)) { |
650 | Q_ASSERT(playlistId >= 0); |
651 | |
652 | clearChildModel(); |
653 | m_playlistDao.deletePlaylist(playlistId); |
654 | m_playlistTableModel.select(); |
655 | constructChildModel(); |
656 | + emit(featureUpdated()); |
657 | } |
658 | - |
659 | - emit(featureUpdated()); |
660 | + |
661 | } |
662 | |
663 | bool PlaylistFeature::dropAccept(QUrl url) { |
664 | @@ -295,7 +347,12 @@ |
665 | |
666 | bool PlaylistFeature::dragMoveAcceptChild(const QModelIndex& index, QUrl url) { |
667 | //TODO: Filter by supported formats regex and reject anything that doesn't match. |
668 | - return true; |
669 | + |
670 | + QString playlistName = index.data().toString(); |
671 | + int playlistId = m_playlistDao.getPlaylistIdFromName(playlistName); |
672 | + bool locked = m_playlistDao.isPlaylistLocked(playlistId); |
673 | + |
674 | + return !locked; |
675 | } |
676 | |
677 | TreeItemModel* PlaylistFeature::getChildModel() { |
678 | @@ -316,12 +373,47 @@ |
679 | for (int row = 0; row < m_playlistTableModel.rowCount(); ++row) { |
680 | QModelIndex ind = m_playlistTableModel.index(row, idColumn); |
681 | QString playlist_name = m_playlistTableModel.data(ind).toString(); |
682 | +<<<<<<< TREE |
683 | //Create the TreeItem whose parent is the invisible root item |
684 | TreeItem* item = new TreeItem(playlist_name, playlist_name, this, root ); |
685 | data_list.append(item); |
686 | +======= |
687 | + data_list.insert(row,playlist_name); |
688 | + |
689 | + int playlistID = m_playlistDao.getPlaylistIdFromName(playlist_name); |
690 | + bool locked = m_playlistDao.isPlaylistLocked(playlistID); |
691 | + TreeItem* playlist_item = m_childModel.getItem(ind); |
692 | + |
693 | + if (locked) { |
694 | + playlist_item->setIcon(QIcon(":/images/library/ic_library_locked.png")); |
695 | + } |
696 | + else { |
697 | + playlist_item->setIcon(QIcon()); |
698 | + } |
699 | +>>>>>>> MERGE-SOURCE |
700 | } |
701 | +<<<<<<< TREE |
702 | //Append all the newly created TreeItems in a dynamic way to the childmodel |
703 | m_childModel.insertRows(data_list, 0, m_playlistTableModel.rowCount()); |
704 | +======= |
705 | + |
706 | + m_childModel.insertRows(data_list, 0, m_playlistTableModel.rowCount()); |
707 | + |
708 | + for (int row = 0; row < m_childModel.rowCount(); ++row) { |
709 | + QModelIndex ind = m_childModel.index(row, 0); |
710 | + QString playlist_name = m_childModel.data(ind, Qt::DisplayRole).toString(); |
711 | + int playlistID = m_playlistDao.getPlaylistIdFromName(playlist_name); |
712 | + bool locked = m_playlistDao.isPlaylistLocked(playlistID); |
713 | + TreeItem* playlist_item = m_childModel.getItem(ind); |
714 | + |
715 | + if (locked) { |
716 | + playlist_item->setIcon(QIcon(":/images/library/ic_library_locked.png")); |
717 | + } |
718 | + else { |
719 | + playlist_item->setIcon(QIcon()); |
720 | + } |
721 | + } |
722 | +>>>>>>> MERGE-SOURCE |
723 | } |
724 | /** |
725 | * Clears the child model dynamically, but the invisible root item remains |
726 | |
727 | === modified file 'mixxx/src/library/playlistfeature.h' |
728 | --- mixxx/src/library/playlistfeature.h 2010-12-31 15:31:04 +0000 |
729 | +++ mixxx/src/library/playlistfeature.h 2011-02-15 19:56:49 +0000 |
730 | @@ -47,11 +47,12 @@ |
731 | |
732 | void slotCreatePlaylist(); |
733 | void slotDeletePlaylist(); |
734 | - void slotRenamePlaylist(); |
735 | + void slotRenamePlaylist(); |
736 | + void slotTogglePlaylistLock(); |
737 | void slotImportPlaylist(); |
738 | |
739 | private: |
740 | - void constructChildModel(); |
741 | + void constructChildModel(); |
742 | void clearChildModel(); |
743 | |
744 | PlaylistTableModel* m_pPlaylistTableModel; |
745 | @@ -60,6 +61,7 @@ |
746 | QAction *m_pCreatePlaylistAction; |
747 | QAction *m_pDeletePlaylistAction; |
748 | QAction *m_pRenamePlaylistAction; |
749 | + QAction *m_pLockPlaylistAction; |
750 | QAction *m_pImportPlaylistAction; |
751 | QSqlTableModel m_playlistTableModel; |
752 | QModelIndex m_lastRightClickedIndex; |
753 | |
754 | === modified file 'mixxx/src/library/playlisttablemodel.cpp' |
755 | --- mixxx/src/library/playlisttablemodel.cpp 2010-11-17 21:04:30 +0000 |
756 | +++ mixxx/src/library/playlisttablemodel.cpp 2011-02-15 19:56:49 +0000 |
757 | @@ -139,30 +139,38 @@ |
758 | |
759 | void PlaylistTableModel::removeTrack(const QModelIndex& index) |
760 | { |
761 | - const int positionColumnIndex = fieldIndex(PLAYLISTTRACKSTABLE_POSITION); |
762 | - int position = index.sibling(index.row(), positionColumnIndex).data().toInt(); |
763 | - m_playlistDao.removeTrackFromPlaylist(m_iPlaylistId, position); |
764 | - select(); //Repopulate the data model. |
765 | + bool locked = m_playlistDao.isPlaylistLocked(m_iPlaylistId); |
766 | + |
767 | + if (!locked) { |
768 | + const int positionColumnIndex = fieldIndex(PLAYLISTTRACKSTABLE_POSITION); |
769 | + int position = index.sibling(index.row(), positionColumnIndex).data().toInt(); |
770 | + m_playlistDao.removeTrackFromPlaylist(m_iPlaylistId, position); |
771 | + select(); //Repopulate the data model. |
772 | + } |
773 | } |
774 | |
775 | void PlaylistTableModel::removeTracks(const QModelIndexList& indices) { |
776 | - const int positionColumnIndex = fieldIndex(PLAYLISTTRACKSTABLE_POSITION); |
777 | - |
778 | - QList<int> trackPositions; |
779 | - foreach (QModelIndex index, indices) { |
780 | - int trackPosition = index.sibling(index.row(), positionColumnIndex).data().toInt(); |
781 | - trackPositions.append(trackPosition); |
782 | - } |
783 | - |
784 | - qSort(trackPositions); |
785 | - QListIterator<int> iterator(trackPositions); |
786 | - iterator.toBack(); |
787 | - |
788 | - while (iterator.hasPrevious()) { |
789 | - m_playlistDao.removeTrackFromPlaylist(m_iPlaylistId, iterator.previous()); |
790 | - } |
791 | - |
792 | - select(); |
793 | + bool locked = m_playlistDao.isPlaylistLocked(m_iPlaylistId); |
794 | + |
795 | + if (!locked) { |
796 | + const int positionColumnIndex = fieldIndex(PLAYLISTTRACKSTABLE_POSITION); |
797 | + |
798 | + QList<int> trackPositions; |
799 | + foreach (QModelIndex index, indices) { |
800 | + int trackPosition = index.sibling(index.row(), positionColumnIndex).data().toInt(); |
801 | + trackPositions.append(trackPosition); |
802 | + } |
803 | + |
804 | + qSort(trackPositions); |
805 | + QListIterator<int> iterator(trackPositions); |
806 | + iterator.toBack(); |
807 | + |
808 | + while (iterator.hasPrevious()) { |
809 | + m_playlistDao.removeTrackFromPlaylist(m_iPlaylistId, iterator.previous()); |
810 | + } |
811 | + |
812 | + select(); |
813 | + } |
814 | } |
815 | |
816 | void PlaylistTableModel::moveTrack(const QModelIndex& sourceIndex, const QModelIndex& destIndex) |
817 | @@ -352,5 +360,10 @@ |
818 | if (m_iPlaylistId != m_playlistDao.getPlaylistIdFromName(AUTODJ_TABLE)) |
819 | caps |= TRACKMODELCAPS_ADDTOAUTODJ; |
820 | |
821 | + bool locked = m_playlistDao.isPlaylistLocked(m_iPlaylistId); |
822 | + |
823 | + if (locked) |
824 | + caps |= TRACKMODELCAPS_LOCKED; |
825 | + |
826 | return caps; |
827 | } |
828 | |
829 | === modified file 'mixxx/src/library/sidebarmodel.cpp' |
830 | --- mixxx/src/library/sidebarmodel.cpp 2011-02-12 19:25:05 +0000 |
831 | +++ mixxx/src/library/sidebarmodel.cpp 2011-02-15 19:56:49 +0000 |
832 | @@ -188,10 +188,14 @@ |
833 | } |
834 | } |
835 | else { |
836 | + TreeItem* tree_item = (TreeItem*)index.internalPointer(); |
837 | + |
838 | if (role == Qt::DisplayRole) { |
839 | - TreeItem* tree_item = (TreeItem*)index.internalPointer(); |
840 | return tree_item->data(); |
841 | - } |
842 | + } |
843 | + else if (role == Qt::DecorationRole) { |
844 | + return tree_item->getIcon(); |
845 | + } |
846 | |
847 | } |
848 | } |
849 | |
850 | === modified file 'mixxx/src/library/trackcollection.cpp' |
851 | --- mixxx/src/library/trackcollection.cpp 2010-12-22 21:23:09 +0000 |
852 | +++ mixxx/src/library/trackcollection.cpp 2011-02-15 19:56:49 +0000 |
853 | @@ -68,7 +68,7 @@ |
854 | return false; |
855 | } |
856 | |
857 | - int requiredSchemaVersion = 9; |
858 | + int requiredSchemaVersion = 10; |
859 | if (!SchemaManager::upgradeToSchemaVersion(m_pConfig, m_db, |
860 | requiredSchemaVersion)) { |
861 | QMessageBox::warning(0, tr("Cannot upgrade database schema"), |
862 | |
863 | === modified file 'mixxx/src/library/trackmodel.h' |
864 | --- mixxx/src/library/trackmodel.h 2010-11-16 21:01:45 +0000 |
865 | +++ mixxx/src/library/trackmodel.h 2011-02-15 19:56:49 +0000 |
866 | @@ -29,6 +29,7 @@ |
867 | TRACKMODELCAPS_ADDTOPLAYLIST = 0x0004, |
868 | TRACKMODELCAPS_ADDTOCRATE = 0x0008, |
869 | TRACKMODELCAPS_ADDTOAUTODJ = 0x0010, |
870 | + TRACKMODELCAPS_LOCKED = 0x0020, |
871 | //0x0004 |
872 | }; |
873 | |
874 | |
875 | === modified file 'mixxx/src/library/treeitem.cpp' |
876 | --- mixxx/src/library/treeitem.cpp 2011-01-13 18:40:56 +0000 |
877 | +++ mixxx/src/library/treeitem.cpp 2011-02-15 19:56:49 +0000 |
878 | @@ -126,3 +126,15 @@ |
879 | m_dataPath = data_path.toString(); |
880 | return true; |
881 | } |
882 | + |
883 | + |
884 | +QIcon TreeItem::getIcon() |
885 | +{ |
886 | + return m_icon; |
887 | +} |
888 | + |
889 | + |
890 | +void TreeItem::setIcon(const QIcon& icon) |
891 | +{ |
892 | + m_icon = icon; |
893 | +} |
894 | |
895 | === modified file 'mixxx/src/library/treeitem.h' |
896 | --- mixxx/src/library/treeitem.h 2011-02-11 18:35:24 +0000 |
897 | +++ mixxx/src/library/treeitem.h 2011-02-15 19:56:49 +0000 |
898 | @@ -44,10 +44,16 @@ |
899 | bool isPlaylist() const; |
900 | /** returns true if we have an inner node **/ |
901 | bool isFolder() const; |
902 | +<<<<<<< TREE |
903 | |
904 | +======= |
905 | +>>>>>>> MERGE-SOURCE |
906 | /* Returns the Library feature object to which an item belongs to */ |
907 | LibraryFeature* getFeature(); |
908 | |
909 | + void setIcon(const QIcon& icon); |
910 | + QIcon getIcon(); |
911 | + |
912 | private: |
913 | QList<TreeItem*> m_childItems; |
914 | QString m_dataPath; |
915 | @@ -55,6 +61,7 @@ |
916 | LibraryFeature* m_feature; |
917 | |
918 | TreeItem *m_parentItem; |
919 | + QIcon m_icon; |
920 | }; |
921 | |
922 | #endif |
923 | |
924 | === modified file 'mixxx/src/library/treeitemmodel.cpp' |
925 | --- mixxx/src/library/treeitemmodel.cpp 2011-01-19 17:47:08 +0000 |
926 | +++ mixxx/src/library/treeitemmodel.cpp 2011-02-15 19:56:49 +0000 |
927 | @@ -45,7 +45,7 @@ |
928 | } |
929 | |
930 | QVariant TreeItemModel::data(const QModelIndex &index, int role) const |
931 | - { |
932 | + { |
933 | if (!index.isValid()) |
934 | return QVariant(); |
935 | |
936 | @@ -53,7 +53,7 @@ |
937 | return QVariant(); |
938 | |
939 | TreeItem *item = static_cast<TreeItem*>(index.internalPointer()); |
940 | - |
941 | + |
942 | return item->data(); |
943 | } |
944 | |
945 | |
946 | === modified file 'mixxx/src/widget/wtracktableview.cpp' |
947 | --- mixxx/src/widget/wtracktableview.cpp 2011-02-11 18:35:24 +0000 |
948 | +++ mixxx/src/widget/wtracktableview.cpp 2011-02-15 19:56:49 +0000 |
949 | @@ -338,20 +338,24 @@ |
950 | |
951 | if (modelHasCapabilities(TrackModel::TRACKMODELCAPS_ADDTOPLAYLIST)) { |
952 | m_pPlaylistMenu->clear(); |
953 | - |
954 | PlaylistDAO& playlistDao = m_pTrackCollection->getPlaylistDAO(); |
955 | int numPlaylists = playlistDao.playlistCount(); |
956 | + |
957 | for (int i = 0; i < numPlaylists; ++i) { |
958 | int iPlaylistId = playlistDao.getPlaylistId(i); |
959 | - if (playlistDao.isHidden(iPlaylistId)) |
960 | - continue; |
961 | - QString playlistName = playlistDao.getPlaylistName(iPlaylistId); |
962 | - // No leak because making the menu the parent means they will be |
963 | - // auto-deleted |
964 | - QAction* pAction = new QAction(playlistName, m_pPlaylistMenu); |
965 | - m_pPlaylistMenu->addAction(pAction); |
966 | - m_playlistMapper.setMapping(pAction, iPlaylistId); |
967 | - connect(pAction, SIGNAL(triggered()), &m_playlistMapper, SLOT(map())); |
968 | + |
969 | + if (!playlistDao.isHidden(iPlaylistId)) { |
970 | + |
971 | + QString playlistName = playlistDao.getPlaylistName(iPlaylistId); |
972 | + // No leak because making the menu the parent means they will be |
973 | + // auto-deleted |
974 | + QAction* pAction = new QAction(playlistName, m_pPlaylistMenu); |
975 | + bool locked = playlistDao.isPlaylistLocked(iPlaylistId); |
976 | + pAction->setEnabled(!locked); |
977 | + m_pPlaylistMenu->addAction(pAction); |
978 | + m_playlistMapper.setMapping(pAction, iPlaylistId); |
979 | + connect(pAction, SIGNAL(triggered()), &m_playlistMapper, SLOT(map())); |
980 | + } |
981 | } |
982 | |
983 | m_pMenu->addMenu(m_pPlaylistMenu); |
984 | @@ -359,7 +363,6 @@ |
985 | |
986 | if (modelHasCapabilities(TrackModel::TRACKMODELCAPS_ADDTOCRATE)) { |
987 | m_pCrateMenu->clear(); |
988 | - |
989 | CrateDAO& crateDao = m_pTrackCollection->getCrateDAO(); |
990 | int numCrates = crateDao.crateCount(); |
991 | for (int i = 0; i < numCrates; ++i) { |
992 | @@ -367,6 +370,8 @@ |
993 | // No leak because making the menu the parent means they will be |
994 | // auto-deleted |
995 | QAction* pAction = new QAction(crateDao.crateName(iCrateId), m_pCrateMenu); |
996 | + bool locked = crateDao.isCrateLocked(iCrateId); |
997 | + pAction->setEnabled(!locked); |
998 | m_pCrateMenu->addAction(pAction); |
999 | m_crateMapper.setMapping(pAction, iCrateId); |
1000 | connect(pAction, SIGNAL(triggered()), &m_crateMapper, SLOT(map())); |
1001 | @@ -375,9 +380,10 @@ |
1002 | m_pMenu->addMenu(m_pCrateMenu); |
1003 | } |
1004 | |
1005 | + bool locked = modelHasCapabilities(TrackModel::TRACKMODELCAPS_LOCKED); |
1006 | + m_pRemoveAct->setEnabled(!locked); |
1007 | m_pMenu->addSeparator(); |
1008 | m_pMenu->addAction(m_pRemoveAct); |
1009 | - |
1010 | m_pPropertiesAct->setEnabled(oneSongSelected); |
1011 | m_pMenu->addAction(m_pPropertiesAct); |
1012 |
Line 217 could be problematic. Different optimization levels and/or compilers can switch the order of boolean expressions.