~neon/juk/master

56 by Scott Wheeler
More of the architecture cleanups -- added files.
1
/***************************************************************************
2
    begin                : Sat Feb 16 2002
1003 by Scott Wheeler
It's 2004 now. Update copyrights.
3
    copyright            : (C) 2002 - 2004 by Scott Wheeler
75 by Scott Wheeler
scott@slackorama.net -> wheeler@kde.org
4
    email                : wheeler@kde.org
56 by Scott Wheeler
More of the architecture cleanups -- added files.
5
***************************************************************************/
6
7
/***************************************************************************
8
 *                                                                         *
9
 *   This program is free software; you can redistribute it and/or modify  *
10
 *   it under the terms of the GNU General Public License as published by  *
11
 *   the Free Software Foundation; either version 2 of the License, or     *
12
 *   (at your option) any later version.                                   *
13
 *                                                                         *
14
 ***************************************************************************/
15
411 by Scott Wheeler
fix includes
16
#include <kconfig.h>
56 by Scott Wheeler
More of the architecture cleanups -- added files.
17
#include <kmessagebox.h>
61 by Scott Wheeler
More updates including drag and drop support between playlists, from one
18
#include <kurldrag.h>
19
#include <kiconloader.h>
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
20
#include <klineedit.h>
160 by Scott Wheeler
Fix include for KDE 3.1.
21
#include <kaction.h>
297 by Nadeem Hasan
Include file cleanup
22
#include <kpopupmenu.h>
411 by Scott Wheeler
fix includes
23
#include <klocale.h>
56 by Scott Wheeler
More of the architecture cleanups -- added files.
24
#include <kdebug.h>
1144 by Michael Pyne
Fix Create Playlist from Selected Items to actually ask the user for the
25
#include <kinputdialog.h>
1299 by Scott Wheeler
Ok, huge patch from Nathan Toone to add a cover manager and such. There
26
#include <kfiledialog.h>
1189 by Michael Pyne
Fix bug 83495 by making JuK move deleted music to the Trash instead of removing them immediately. This also caught a poor KDE developer whom I'll leave nameless, so I figured it was time to hurry up and fix this. =D
27
#include <kglobalsettings.h>
28
#include <kurl.h>
29
#include <kio/netaccess.h>
1229 by Michael Pyne
Fix bug 90606 (Trashing files no longer works). I had been planning to use trash:/ anyways, but forgot to change it.
30
#include <kio/job.h>
56 by Scott Wheeler
More of the architecture cleanups -- added files.
31
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
32
#include <qheader.h>
33
#include <qcursor.h>
411 by Scott Wheeler
fix includes
34
#include <qdir.h>
491 by Scott Wheeler
Make it possible to reload multiple playlists at once.
35
#include <qeventloop.h>
903 by Scott Wheeler
Only show the "short" file name (i.e. not the path) in the column by default
36
#include <qtooltip.h>
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
37
#include <qwidgetstack.h>
1299 by Scott Wheeler
Ok, huge patch from Nathan Toone to add a cover manager and such. There
38
#include <qfile.h>
56 by Scott Wheeler
More of the architecture cleanups -- added files.
39
724 by Scott Wheeler
Another 10 files sacrificed to TagLib. Yay for removing code! :-) (TagLib
40
#include <id3v1genres.h>
41
63 by Scott Wheeler
Uhh. Fixed stuff. Added features.
42
#include <time.h>
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
43
#include <math.h>
1083 by Scott Wheeler
Move away from QDir::listEntries() to using ::readdir() since at some point
44
#include <dirent.h>
63 by Scott Wheeler
Uhh. Fixed stuff. Added features.
45
56 by Scott Wheeler
More of the architecture cleanups -- added files.
46
#include "playlist.h"
446 by Scott Wheeler
* Cleaned up some includes
47
#include "playlistitem.h"
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
48
#include "playlistcollection.h"
446 by Scott Wheeler
* Cleaned up some includes
49
#include "playlistsearch.h"
591 by Scott Wheeler
Ok, the last step in adding "history playlist" support. I implemented
50
#include "mediafiles.h"
411 by Scott Wheeler
fix includes
51
#include "collectionlist.h"
635 by Frerich Raabe
- Almost going live with the file renamer
52
#include "filerenamer.h"
837 by Scott Wheeler
Ah, this feels good. I was using the "find the mainwindow" hack several
53
#include "actioncollection.h"
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
54
#include "tracksequencemanager.h"
919 by Scott Wheeler
A bit of a dirty hack to diable the directory scanner while renaming of files
55
#include "juk.h"
887 by Scott Wheeler
PlaylistItem and CollectionListItem are no longer QObject. This meant moving
56
#include "tag.h"
984 by Michael Pyne
Add "export to K3b" support to JuK.
57
#include "k3bexporter.h"
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
58
#include "painteater.h"
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
59
#include "upcomingplaylist.h"
1195 by Michael Pyne
Add new file removal dialog, with the major feature being that the Delete button is no longer the default.
60
#include "deletedialog.h"
1299 by Scott Wheeler
Ok, huge patch from Nathan Toone to add a cover manager and such. There
61
#include "googlefetcher.h"
1310 by Michael Pyne
Remove the unnecessary dependency of filehandle.h on coveritem.h, and correct the files that broke because of this.
62
#include "coverinfo.h"
1222 by Michael Pyne
Implement bug 61340 (Add undo support for multi-tagging).
63
#include "tagtransactionmanager.h"
56 by Scott Wheeler
More of the architecture cleanups -- added files.
64
923 by Scott Wheeler
Use the global KActions here rather than new items.
65
using namespace ActionCollection;
66
903 by Scott Wheeler
Only show the "short" file name (i.e. not the path) in the column by default
67
/**
1244 by Scott Wheeler
Make sure that we don't resize the columns on events that would normally trigger
68
 * Just a shortcut of sorts.
69
 */
70
71
static bool manualResize()
72
{
73
    return action<KToggleAction>("resizeColumnsManually")->isChecked();
74
}
75
76
/**
903 by Scott Wheeler
Only show the "short" file name (i.e. not the path) in the column by default
77
 * A tooltip specialized to show full filenames over the file name column.
78
 */
79
80
class PlaylistToolTip : public QToolTip
81
{
82
public:
83
    PlaylistToolTip(QWidget *parent, Playlist *playlist) :
84
	QToolTip(parent), m_playlist(playlist) {}
85
86
    virtual void maybeTip(const QPoint &p)
87
    {
88
	PlaylistItem *item = static_cast<PlaylistItem *>(m_playlist->itemAt(p));
89
90
	if(!item)
91
	    return;
92
93
	QPoint contentsPosition = m_playlist->viewportToContents(p);
94
95
	int column = m_playlist->header()->sectionAt(contentsPosition.x());
96
97
	if(column == m_playlist->columnOffset() + PlaylistItem::FileNameColumn ||
1299 by Scott Wheeler
Ok, huge patch from Nathan Toone to add a cover manager and such. There
98
	   item->cachedWidths()[column] > m_playlist->columnWidth(column) ||
99
	   (column == m_playlist->columnOffset() + PlaylistItem::CoverColumn &&
100
	    item->file().coverInfo()->hasCover()))
903 by Scott Wheeler
Only show the "short" file name (i.e. not the path) in the column by default
101
	{
102
	    QRect r = m_playlist->itemRect(item);
103
	    int headerPosition = m_playlist->header()->sectionPos(column);
104
	    r.setLeft(headerPosition);
105
	    r.setRight(headerPosition + m_playlist->header()->sectionSize(column));
1315 by Scott Wheeler
Leak less memory. Don't use QPixmap pointers, but rather pass by value.
106
1329 by Scott Wheeler
Clean up from my last commit and also in general -- this make sure that
107
	    if(column == m_playlist->columnOffset() + PlaylistItem::FileNameColumn)
903 by Scott Wheeler
Only show the "short" file name (i.e. not the path) in the column by default
108
		tip(r, item->file().absFilePath());
1315 by Scott Wheeler
Leak less memory. Don't use QPixmap pointers, but rather pass by value.
109
	    else if(column == m_playlist->columnOffset() + PlaylistItem::CoverColumn) {
110
		QMimeSourceFactory *f = QMimeSourceFactory::defaultFactory();
1327 by Scott Wheeler
Put the CoverInfo API on a diet; there's no need duplicating this stuff over
111
	        f->setImage("coverThumb",
112
			    QImage(item->file().coverInfo()->pixmap(CoverInfo::Thumbnail).convertToImage()));
1299 by Scott Wheeler
Ok, huge patch from Nathan Toone to add a cover manager and such. There
113
	        tip(r, "<center><img source=\"coverThumb\"/></center>");
114
	    }
903 by Scott Wheeler
Only show the "short" file name (i.e. not the path) in the column by default
115
	    else
116
		tip(r, item->text(column));
117
	}
118
    }
119
120
private:
121
    Playlist *m_playlist;
122
};
123
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
124
////////////////////////////////////////////////////////////////////////////////
125
// Playlist::SharedSettings definition
126
////////////////////////////////////////////////////////////////////////////////
127
439 by Scott Wheeler
fix warning
128
bool Playlist::m_visibleChanged = false;
389 by Zack Rusin
Implementing the random play as in other modern players - meaning that although
129
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
130
/**
131
 * Shared settings between the playlists.
132
 */
133
134
class Playlist::SharedSettings
135
{
136
public:
137
    static SharedSettings *instance();
138
    /**
139
     * Sets the default column order to that of Playlist @param p.
140
     */
141
    void setColumnOrder(const Playlist *l);
142
    void toggleColumnVisible(int column);
673 by Scott Wheeler
Save / restore the "completion mode" for the inline tag editor in JuK's
143
    void setInlineCompletionMode(KGlobalSettings::Completion mode);
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
144
145
    /**
146
     * Apply the settings.
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
147
     */
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
148
    void apply(Playlist *l) const;
1242 by Scott Wheeler
Make sure that the column resize settings are shared across playlists and
149
    void sync() { writeConfig(); }
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
150
151
protected:
152
    SharedSettings();
153
    ~SharedSettings() {}
154
155
private:
156
    void writeConfig();
157
158
    static SharedSettings *m_instance;
159
    QValueList<int> m_columnOrder;
160
    QValueVector<bool> m_columnsVisible;
673 by Scott Wheeler
Save / restore the "completion mode" for the inline tag editor in JuK's
161
    KGlobalSettings::Completion m_inlineCompletion;
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
162
};
163
277 by Scott Wheeler
Save and restore column order.
164
Playlist::SharedSettings *Playlist::SharedSettings::m_instance = 0;
165
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
166
////////////////////////////////////////////////////////////////////////////////
167
// Playlist::SharedSettings public members
168
////////////////////////////////////////////////////////////////////////////////
169
277 by Scott Wheeler
Save and restore column order.
170
Playlist::SharedSettings *Playlist::SharedSettings::instance()
171
{
172
    if(!m_instance)
173
	m_instance = new SharedSettings;
174
    return m_instance;
175
}
176
177
void Playlist::SharedSettings::setColumnOrder(const Playlist *l)
178
{
179
    if(!l)
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
180
	return;
181
277 by Scott Wheeler
Save and restore column order.
182
    m_columnOrder.clear();
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
183
559 by Scott Wheeler
More adjustments to make use of "columnOffset()". Now hiding columns in
184
    for(int i = l->columnOffset(); i < l->columns(); ++i)
277 by Scott Wheeler
Save and restore column order.
185
	m_columnOrder.append(l->header()->mapToIndex(i));
186
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
187
    writeConfig();
188
}
189
190
void Playlist::SharedSettings::toggleColumnVisible(int column)
191
{
192
    if(column >= int(m_columnsVisible.size()))
193
	m_columnsVisible.resize(column + 1, true);
194
195
    m_columnsVisible[column] = !m_columnsVisible[column];
196
197
    writeConfig();
198
}
199
673 by Scott Wheeler
Save / restore the "completion mode" for the inline tag editor in JuK's
200
void Playlist::SharedSettings::setInlineCompletionMode(KGlobalSettings::Completion mode)
201
{
202
    m_inlineCompletion = mode;
203
    writeConfig();
204
}
205
206
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
207
void Playlist::SharedSettings::apply(Playlist *l) const
277 by Scott Wheeler
Save and restore column order.
208
{
209
    if(!l)
210
	return;
211
559 by Scott Wheeler
More adjustments to make use of "columnOffset()". Now hiding columns in
212
    int offset = l->columnOffset();
277 by Scott Wheeler
Save and restore column order.
213
    int i = 0;
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
214
    for(QValueListConstIterator<int> it = m_columnOrder.begin(); it != m_columnOrder.end(); ++it)
559 by Scott Wheeler
More adjustments to make use of "columnOffset()". Now hiding columns in
215
	l->header()->moveSection(i++ + offset, *it + offset);
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
216
217
    for(uint i = 0; i < m_columnsVisible.size(); i++) {
559 by Scott Wheeler
More adjustments to make use of "columnOffset()". Now hiding columns in
218
	if(m_columnsVisible[i] && !l->isColumnVisible(i + offset))
676 by Scott Wheeler
Don't refresh the search so often (i.e. every time that a column is shown
219
	    l->showColumn(i + offset, false);
559 by Scott Wheeler
More adjustments to make use of "columnOffset()". Now hiding columns in
220
	else if(!m_columnsVisible[i] && l->isColumnVisible(i + offset))
676 by Scott Wheeler
Don't refresh the search so often (i.e. every time that a column is shown
221
	    l->hideColumn(i + offset, false);
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
222
    }
284 by Scott Wheeler
Porting this bugfix to HEAD.
223
224
    l->updateLeftColumn();
673 by Scott Wheeler
Save / restore the "completion mode" for the inline tag editor in JuK's
225
    l->renameLineEdit()->setCompletionMode(m_inlineCompletion);
1242 by Scott Wheeler
Make sure that the column resize settings are shared across playlists and
226
    l->slotColumnResizeModeChanged();
277 by Scott Wheeler
Save and restore column order.
227
}
228
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
229
////////////////////////////////////////////////////////////////////////////////
230
// Playlist::ShareSettings protected members
231
////////////////////////////////////////////////////////////////////////////////
232
277 by Scott Wheeler
Save and restore column order.
233
Playlist::SharedSettings::SharedSettings()
234
{
1040 by Scott Wheeler
Switch from KConfigGroupSaver to KConfigGroup
235
    KConfigGroup config(KGlobal::config(), "PlaylistShared");
236
1215 by Michael Pyne
Implement bug 73435 (Add option for manual column widths). Due to a limitation in QListViews, hiding columns doesn't work too well in this mode, which you'll probably encounter while resizing columns next to hidden columns.
237
    bool resizeColumnsManually = config.readBoolEntry("ResizeColumnsManually", false);
238
    action<KToggleAction>("resizeColumnsManually")->setChecked(resizeColumnsManually);
239
1040 by Scott Wheeler
Switch from KConfigGroupSaver to KConfigGroup
240
    // save column order
241
    m_columnOrder = config.readIntListEntry("ColumnOrder");
242
243
    QValueList<int> l = config.readIntListEntry("VisibleColumns");
244
245
    if(l.isEmpty()) {
246
247
	// Provide some default values for column visibility if none were
248
	// read from the configuration file.
249
250
	for(int i = 0; i <= PlaylistItem::lastColumn(); i++) {
251
	    switch(i) {
252
	    case PlaylistItem::BitrateColumn:
253
	    case PlaylistItem::CommentColumn:
254
	    case PlaylistItem::FileNameColumn:
1157 by Scott Wheeler
Don't show the full path column by default.
255
	    case PlaylistItem::FullPathColumn:
1040 by Scott Wheeler
Switch from KConfigGroupSaver to KConfigGroup
256
		m_columnsVisible.append(false);
257
		break;
258
	    default:
259
		m_columnsVisible.append(true);
260
	    }
261
	}
262
    }
263
    else {
264
	// Convert the int list into a bool list.
1050 by Laurent Montel
Don't call rename dialogbox when there is not item selected
265
1040 by Scott Wheeler
Switch from KConfigGroupSaver to KConfigGroup
266
	m_columnsVisible.resize(l.size(), true);
267
	uint i = 0;
268
	for(QValueList<int>::Iterator it = l.begin(); it != l.end(); ++it) {
269
	    if(! bool(*it))
270
		m_columnsVisible[i] = bool(*it);
271
	    i++;
272
	}
273
    }
274
275
    m_inlineCompletion = KGlobalSettings::Completion(
276
	config.readNumEntry("InlineCompletionMode", KGlobalSettings::CompletionAuto));
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
277
}
278
279
////////////////////////////////////////////////////////////////////////////////
280
// Playlist::SharedSettings private members
281
////////////////////////////////////////////////////////////////////////////////
282
283
void Playlist::SharedSettings::writeConfig()
284
{
1040 by Scott Wheeler
Switch from KConfigGroupSaver to KConfigGroup
285
    KConfigGroup config(KGlobal::config(), "PlaylistShared");
286
    config.writeEntry("ColumnOrder", m_columnOrder);
287
288
    QValueList<int> l;
289
    for(uint i = 0; i < m_columnsVisible.size(); i++)
290
	l.append(int(m_columnsVisible[i]));
291
292
    config.writeEntry("VisibleColumns", l);
293
    config.writeEntry("InlineCompletionMode", m_inlineCompletion);
294
1244 by Scott Wheeler
Make sure that we don't resize the columns on events that would normally trigger
295
    config.writeEntry("ResizeColumnsManually", manualResize());
1215 by Michael Pyne
Implement bug 73435 (Add option for manual column widths). Due to a limitation in QListViews, hiding columns doesn't work too well in this mode, which you'll probably encounter while resizing columns next to hidden columns.
296
1040 by Scott Wheeler
Switch from KConfigGroupSaver to KConfigGroup
297
    KGlobal::config()->sync();
277 by Scott Wheeler
Save and restore column order.
298
}
276 by Scott Wheeler
Just added this functionality to kdelibs, so check to see if we're
299
56 by Scott Wheeler
More of the architecture cleanups -- added files.
300
////////////////////////////////////////////////////////////////////////////////
209 by Scott Wheeler
Cleaned up the behavior of "Play Next" by making it get reset on back,
301
// public members
56 by Scott Wheeler
More of the architecture cleanups -- added files.
302
////////////////////////////////////////////////////////////////////////////////
303
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
304
PlaylistItemList Playlist::m_history;
305
UpcomingPlaylist *Playlist::m_upcomingPlaylist = 0;
1067 by Scott Wheeler
Forgot to commit this earlier...make the back popup menu work again.
306
QMap<int, PlaylistItem *> Playlist::m_backMenuItems;
443 by Scott Wheeler
Added a method to determine the currently playing playlist and made some
307
int Playlist::m_leftColumn = 0;
308
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
309
Playlist::Playlist(PlaylistCollection *collection, const QString &name,
310
		   const QString &iconName) :
311
    KListView(collection->playlistStack(), name.latin1()),
312
    m_collection(collection),
313
    m_selectedCount(0),
314
    m_allowDuplicates(false),
315
    m_polished(false),
316
    m_applySharedSettings(true),
1241 by Scott Wheeler
Automatically switch on manual column width mode if the user tries to resize
317
    m_mousePressed(false),
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
318
    m_disableColumnWidthUpdates(true),
319
    m_widthsDirty(true),
320
    m_searchEnabled(true),
321
    m_lastSelected(0),
322
    m_playlistName(name),
1013 by Scott Wheeler
Valgrind pointed out that QToolTips are not QObjects and aren't deleted when
323
    m_rmbMenu(0),
324
    m_toolTip(0)
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
325
{
326
    setup();
327
    collection->setupPlaylist(this, iconName);
328
}
329
330
Playlist::Playlist(PlaylistCollection *collection, const PlaylistItemList &items,
331
		   const QString &name, const QString &iconName) :
332
    KListView(collection->playlistStack(), name.latin1()),
333
    m_collection(collection),
334
    m_selectedCount(0),
335
    m_allowDuplicates(false),
336
    m_polished(false),
337
    m_applySharedSettings(true),
1241 by Scott Wheeler
Automatically switch on manual column width mode if the user tries to resize
338
    m_mousePressed(false),
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
339
    m_disableColumnWidthUpdates(true),
340
    m_widthsDirty(true),
341
    m_searchEnabled(true),
342
    m_lastSelected(0),
343
    m_playlistName(name),
1013 by Scott Wheeler
Valgrind pointed out that QToolTips are not QObjects and aren't deleted when
344
    m_rmbMenu(0),
345
    m_toolTip(0)
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
346
{
347
    setup();
348
    collection->setupPlaylist(this, iconName);
349
    createItems(items);
350
}
351
352
Playlist::Playlist(PlaylistCollection *collection, const QFileInfo &playlistFile,
353
		   const QString &iconName) :
354
    KListView(collection->playlistStack()),
355
    m_collection(collection),
356
    m_selectedCount(0),
357
    m_allowDuplicates(false),
358
    m_polished(false),
359
    m_applySharedSettings(true),
1241 by Scott Wheeler
Automatically switch on manual column width mode if the user tries to resize
360
    m_mousePressed(false),
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
361
    m_disableColumnWidthUpdates(true),
362
    m_widthsDirty(true),
363
    m_searchEnabled(true),
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
364
    m_lastSelected(0),
544 by Scott Wheeler
*) Create playlist RMB menus on demand.
365
    m_fileName(playlistFile.absFilePath()),
1013 by Scott Wheeler
Valgrind pointed out that QToolTips are not QObjects and aren't deleted when
366
    m_rmbMenu(0),
367
    m_toolTip(0)
63 by Scott Wheeler
Uhh. Fixed stuff. Added features.
368
{
69 by Scott Wheeler
Ok, again, a few days without a suitable internet connection so, a list of
369
    setup();
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
370
    loadFile(m_fileName, playlistFile);
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
371
    collection->setupPlaylist(this, iconName);
372
}
373
374
Playlist::Playlist(PlaylistCollection *collection, bool delaySetup) :
375
    KListView(collection->playlistStack()),
376
    m_collection(collection),
377
    m_selectedCount(0),
378
    m_allowDuplicates(false),
379
    m_polished(false),
380
    m_applySharedSettings(true),
1241 by Scott Wheeler
Automatically switch on manual column width mode if the user tries to resize
381
    m_mousePressed(false),
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
382
    m_disableColumnWidthUpdates(true),
383
    m_widthsDirty(true),
983 by Scott Wheeler
Yay for valigrind. This was uninitialized and caused the search to not
384
    m_searchEnabled(true),
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
385
    m_lastSelected(0),
1013 by Scott Wheeler
Valgrind pointed out that QToolTips are not QObjects and aren't deleted when
386
    m_rmbMenu(0),
387
    m_toolTip(0)
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
388
{
389
    setup();
390
391
    if(!delaySetup)
392
	collection->setupPlaylist(this, "midi");
56 by Scott Wheeler
More of the architecture cleanups -- added files.
393
}
394
395
Playlist::~Playlist()
396
{
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
397
    // clearItem() will take care of removing the items from the history,
398
    // so call clearItems() to make sure it happens.
399
400
    clearItems(items());
1013 by Scott Wheeler
Valgrind pointed out that QToolTips are not QObjects and aren't deleted when
401
402
    delete m_toolTip;
1246 by Michael Pyne
Fix bug 90662 (Crash after editing tags of many songs) based on patch supplied by the bug reporter.
403
404
    // Select a different playlist if we're the selected one
405
406
    if(isVisible() && this != CollectionList::instance())
407
	m_collection->raise(CollectionList::instance());
56 by Scott Wheeler
More of the architecture cleanups -- added files.
408
}
409
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
410
QString Playlist::name() const
411
{
412
    if(m_playlistName.isNull())
413
	return m_fileName.section(QDir::separator(), -1).section('.', 0, -2);
414
    else
415
	return m_playlistName;
416
}
417
418
FileHandle Playlist::currentFile() const
419
{
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
420
    return playingItem() ? playingItem()->file() : FileHandle::null();
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
421
}
422
423
int Playlist::time() const
424
{
425
    int time = 0;
426
    QListViewItemIterator it(const_cast<Playlist *>(this));
427
    while (it.current()) {
428
	PlaylistItem *item = static_cast<PlaylistItem *>(it.current());
1059 by Scott Wheeler
Make startup time fast again -- make sure that we don't stat things before
429
	time += item->file().tag()->seconds();
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
430
	it++;
431
    }
432
    return time;
433
}
434
992 by Michael Pyne
Made it possible to quickly play the found song from the search bar by
435
void Playlist::playFirst()
436
{
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
437
    TrackSequenceManager::instance()->setNextItem(static_cast<PlaylistItem *>(
438
	QListViewItemIterator(const_cast<Playlist *>(this), QListViewItemIterator::Visible).current()));
1067 by Scott Wheeler
Forgot to commit this earlier...make the back popup menu work again.
439
    action("forward")->activate();
992 by Michael Pyne
Made it possible to quickly play the found song from the search bar by
440
}
441
1393 by Michael Pyne
Fix bug 89113 (Add functionality to switch to next/prev album in album random play), except for the previous album part.
442
void Playlist::playNextAlbum()
443
{
444
    PlaylistItem *current = TrackSequenceManager::instance()->currentItem();
445
    if(!current)
446
	return; // No next album if we're not already playing.
447
448
    QString currentAlbum = current->file().tag()->album();
449
    current = TrackSequenceManager::instance()->nextItem();
450
451
    while(current && current->file().tag()->album() == currentAlbum)
452
	current = TrackSequenceManager::instance()->nextItem();
453
454
    TrackSequenceManager::instance()->setNextItem(current);
455
    action("forward")->activate();
456
}
457
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
458
void Playlist::playNext()
459
{
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
460
    TrackSequenceManager::instance()->setCurrentPlaylist(this);
1310 by Michael Pyne
Remove the unnecessary dependency of filehandle.h on coveritem.h, and correct the files that broke because of this.
461
    setPlaying(TrackSequenceManager::instance()->nextItem());
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
462
}
463
464
void Playlist::stop()
465
{
1067 by Scott Wheeler
Forgot to commit this earlier...make the back popup menu work again.
466
    m_history.clear();
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
467
    setPlaying(0);
468
}
469
470
void Playlist::playPrevious()
471
{
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
472
    if(!playingItem())
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
473
	return;
474
475
    bool random = action("randomPlay") && action<KToggleAction>("randomPlay")->isChecked();
476
477
    PlaylistItem *previous = 0;
478
479
    if(random && !m_history.isEmpty()) {
480
        PlaylistItemList::Iterator last = m_history.fromLast();
481
        previous = *last;
482
        m_history.remove(last);
483
    }
484
    else {
485
	m_history.clear();
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
486
	previous = TrackSequenceManager::instance()->previousItem();
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
487
    }
488
489
    if(!previous)
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
490
	previous = static_cast<PlaylistItem *>(playingItem()->itemAbove());
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
491
1065 by Scott Wheeler
Make back work in random play mode again.
492
    setPlaying(previous, false);
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
493
}
494
495
void Playlist::setName(const QString &n)
496
{
1000 by Scott Wheeler
*) Clean up the PlaylistBox API removing signals, slots and methods that aren't
497
    m_collection->addName(n);
498
    m_collection->removeName(m_playlistName);
499
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
500
    m_playlistName = n;
501
    emit signalNameChanged(m_playlistName);
502
}
503
146 by Scott Wheeler
Reworked the playlist restoring and saving code to use a binary cache
504
void Playlist::save()
62 by Scott Wheeler
Yep. More general updates. The context menus on the CollectionListBox
505
{
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
506
    if(m_fileName.isEmpty())
65 by Scott Wheeler
Several days of changes -- again.
507
	return saveAs();
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
508
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
509
    QFile file(m_fileName);
65 by Scott Wheeler
Several days of changes -- again.
510
511
    if(!file.open(IO_WriteOnly))
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
512
	return KMessageBox::error(this, i18n("Could not save to file %1.").arg(m_fileName));
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
513
65 by Scott Wheeler
Several days of changes -- again.
514
    QTextStream stream(&file);
515
516
    QStringList fileList = files();
517
518
    for(QStringList::Iterator it = fileList.begin(); it != fileList.end(); ++it)
519
	stream << *it << endl;
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
520
65 by Scott Wheeler
Several days of changes -- again.
521
    file.close();
62 by Scott Wheeler
Yep. More general updates. The context menus on the CollectionListBox
522
}
523
524
void Playlist::saveAs()
525
{
410 by Scott Wheeler
Added a new namespace to encapsulate all of the operations that know about
526
    m_fileName = MediaFiles::savePlaylistDialog(name(), this);
527
528
    if(!m_fileName.isEmpty()) {
529
	// If there's no playlist name set, use the file name.
178 by Scott Wheeler
Wrote a lovely little script to prefix all member variables with m_
530
	if(m_playlistName.isEmpty())
180 by Scott Wheeler
More cleanups -- this time: finished TagEditor, CollectionList,
531
	    emit signalNameChanged(name());
414 by Zack Rusin
MusicBrainz support. The initial version (just detecting file tags is supported,
532
65 by Scott Wheeler
Several days of changes -- again.
533
	save();
534
    }
62 by Scott Wheeler
Yep. More general updates. The context menus on the CollectionListBox
535
}
536
186 by Scott Wheeler
Delay cache integrity checking beyond start up time by moving it to the
537
void Playlist::clearItem(PlaylistItem *item, bool emitChanged)
538
{
539
    emit signalAboutToRemove(item);
853 by Scott Wheeler
Start porting things over to the new fandangled FileHandle class. There's
540
    m_members.remove(item->file().absFilePath());
1086 by Scott Wheeler
Remove items from the PlaylistSearch's lists when they're cleared from the
541
    m_search.clearItem(item);
542
768 by Scott Wheeler
Finally was able to reproduce this one. Add lots of paranoia to check for
543
    if(!m_randomList.isEmpty() && !m_visibleChanged)
389 by Zack Rusin
Implementing the random play as in other modern players - meaning that although
544
        m_randomList.remove(item);
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
545
    m_history.remove(item);
546
887 by Scott Wheeler
PlaylistItem and CollectionListItem are no longer QObject. This meant moving
547
    delete item;
998 by Scott Wheeler
check to see if we should signal a change
548
    if(emitChanged)
1062 by Scott Wheeler
Separate update() into dataChaged() and currentChanged() to avoid reshowing
549
	dataChanged();
186 by Scott Wheeler
Delay cache integrity checking beyond start up time by moving it to the
550
}
551
62 by Scott Wheeler
Yep. More general updates. The context menus on the CollectionListBox
552
void Playlist::clearItems(const PlaylistItemList &items)
56 by Scott Wheeler
More of the architecture cleanups -- added files.
553
{
349 by Scott Wheeler
Switched PlaylistItemList from QPtrList<PlaylistItem> to
554
    for(PlaylistItemList::ConstIterator it = items.begin(); it != items.end(); ++it)
555
	clearItem(*it, false);
556
1062 by Scott Wheeler
Separate update() into dataChaged() and currentChanged() to avoid reshowing
557
    dataChanged();
56 by Scott Wheeler
More of the architecture cleanups -- added files.
558
}
559
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
560
PlaylistItem *Playlist::playingItem() // static
561
{
1344 by Scott Wheeler
Keep showing the playing item when a dynamic list is created and restore it
562
    return PlaylistItem::playingItems().isEmpty() ? 0 : PlaylistItem::playingItems().front();
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
563
}
564
1203 by Scott Wheeler
Make Folder Playlists a real type that's restored as such. Now they automatically
565
QStringList Playlist::files() const
62 by Scott Wheeler
Yep. More general updates. The context menus on the CollectionListBox
566
{
567
    QStringList list;
677 by Scott Wheeler
Save and restore all items in the playlists -- not just the ones that match
568
1203 by Scott Wheeler
Make Folder Playlists a real type that's restored as such. Now they automatically
569
    for(QListViewItemIterator it(const_cast<Playlist *>(this)); it.current(); ++it)
853 by Scott Wheeler
Start porting things over to the new fandangled FileHandle class. There's
570
	list.append(static_cast<PlaylistItem *>(*it)->file().absFilePath());
62 by Scott Wheeler
Yep. More general updates. The context menus on the CollectionListBox
571
142 by Scott Wheeler
Ok, you're welcome everyone. Moving away from my long standard style
572
    return list;
62 by Scott Wheeler
Yep. More general updates. The context menus on the CollectionListBox
573
}
574
352 by Scott Wheeler
Added the frontend to the search class that I committed earlier. Wow, that
575
PlaylistItemList Playlist::items()
576
{
678 by Scott Wheeler
Use the newly discovered QListViewItemIterator::IteratorFlag to drive the
577
    return items(QListViewItemIterator::IteratorFlag(0));
352 by Scott Wheeler
Added the frontend to the search class that I committed earlier. Wow, that
578
}
579
678 by Scott Wheeler
Use the newly discovered QListViewItemIterator::IteratorFlag to drive the
580
PlaylistItemList Playlist::visibleItems()
62 by Scott Wheeler
Yep. More general updates. The context menus on the CollectionListBox
581
{
678 by Scott Wheeler
Use the newly discovered QListViewItemIterator::IteratorFlag to drive the
582
    return items(QListViewItemIterator::Visible);
62 by Scott Wheeler
Yep. More general updates. The context menus on the CollectionListBox
583
}
584
678 by Scott Wheeler
Use the newly discovered QListViewItemIterator::IteratorFlag to drive the
585
PlaylistItemList Playlist::selectedItems()
62 by Scott Wheeler
Yep. More general updates. The context menus on the CollectionListBox
586
{
587
    PlaylistItemList list;
575 by Scott Wheeler
An optimization for a couple of important cases in determining the set of
588
589
    switch(m_selectedCount) {
590
    case 0:
591
	break;
768 by Scott Wheeler
Finally was able to reproduce this one. Add lots of paranoia to check for
592
	// case 1:
593
	// list.append(m_lastSelected);
594
	// break;
575 by Scott Wheeler
An optimization for a couple of important cases in determining the set of
595
    default:
681 by Scott Wheeler
Don't macth selected items that aren't visible.
596
	list = items(QListViewItemIterator::IteratorFlag(QListViewItemIterator::Selected |
597
							 QListViewItemIterator::Visible));
575 by Scott Wheeler
An optimization for a couple of important cases in determining the set of
598
	break;
599
    }
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
600
142 by Scott Wheeler
Ok, you're welcome everyone. Moving away from my long standard style
601
    return list;
56 by Scott Wheeler
More of the architecture cleanups -- added files.
602
}
603
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
604
PlaylistItem *Playlist::firstChild() const
605
{
606
    return static_cast<PlaylistItem *>(KListView::firstChild());
607
}
608
284 by Scott Wheeler
Porting this bugfix to HEAD.
609
void Playlist::updateLeftColumn()
610
{
611
    int newLeftColumn = leftMostVisibleColumn();
612
613
    if(m_leftColumn != newLeftColumn) {
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
614
	updatePlaying();
284 by Scott Wheeler
Porting this bugfix to HEAD.
615
	m_leftColumn = newLeftColumn;
616
    }
617
}
618
443 by Scott Wheeler
Added a method to determine the currently playing playlist and made some
619
void Playlist::setItemsVisible(const PlaylistItemList &items, bool visible) // static
352 by Scott Wheeler
Added the frontend to the search class that I committed earlier. Wow, that
620
{
438 by Scott Wheeler
* Made the static variable a class level variable and added a comment.
621
    m_visibleChanged = true;
352 by Scott Wheeler
Added the frontend to the search class that I committed earlier. Wow, that
622
    for(PlaylistItemList::ConstIterator it = items.begin(); it != items.end(); ++it)
623
	(*it)->setVisible(visible);
624
}
625
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
626
void Playlist::setSearch(const PlaylistSearch &s)
627
{
628
    m_search = s;
629
630
    if(!m_searchEnabled)
631
	return;
632
1026 by Scott Wheeler
Only play visible items in random play mode.
633
    // Make sure that we only play visible items.
634
635
    m_randomList.clear();
636
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
637
    setItemsVisible(s.matchedItems(), true);
638
    setItemsVisible(s.unmatchedItems(), false);
639
}
640
641
void Playlist::setSearchEnabled(bool enabled)
642
{
643
    if(m_searchEnabled == enabled)
644
	return;
645
646
    m_searchEnabled = enabled;
647
648
    if(enabled) {
649
	setItemsVisible(m_search.matchedItems(), true);
650
	setItemsVisible(m_search.unmatchedItems(), false);
651
    }
652
    else
653
	setItemsVisible(items(), true);
654
}
655
575 by Scott Wheeler
An optimization for a couple of important cases in determining the set of
656
void Playlist::markItemSelected(PlaylistItem *item, bool selected)
657
{
658
    if(selected && !item->isSelected()) {
659
	m_selectedCount++;
660
	m_lastSelected = item;
661
    }
662
    else if(!selected && item->isSelected())
663
	m_selectedCount--;
664
}
665
1344 by Scott Wheeler
Keep showing the playing item when a dynamic list is created and restore it
666
void Playlist::synchronizePlayingItems(const PlaylistList &sources, bool setMaster)
667
{
668
    for(PlaylistList::ConstIterator it = sources.begin(); it != sources.end(); ++it) {
669
        if((*it)->playing()) {
670
            CollectionListItem *base = playingItem()->collectionItem();
671
            for(QListViewItemIterator itemIt(this); itemIt.current(); ++itemIt) {
672
                PlaylistItem *item = static_cast<PlaylistItem *>(itemIt.current());
673
                if(base == item->collectionItem()) {
674
                    item->setPlaying(true, setMaster);
1367 by Scott Wheeler
Ok, so this is sort of working. Adding some stuff so that clicking on the
675
		    PlaylistItemList playing = PlaylistItem::playingItems();
676
		    TrackSequenceManager::instance()->setCurrent(item);
1344 by Scott Wheeler
Keep showing the playing item when a dynamic list is created and restore it
677
                    return;
678
                }
679
            }
680
            return;
681
        }
682
    }
683
}
684
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
685
////////////////////////////////////////////////////////////////////////////////
686
// public slots
687
////////////////////////////////////////////////////////////////////////////////
688
148 by Scott Wheeler
Edit actions should now work everywhere. The next step is cleaning up the
689
void Playlist::copy()
690
{
691
    kapp->clipboard()->setData(dragObject(0), QClipboard::Clipboard);
692
}
693
694
void Playlist::paste()
695
{
533 by Scott Wheeler
Oops. I misses a few switches from QListViewItem to PlaylistItem in the
696
    decode(kapp->clipboard()->data(), static_cast<PlaylistItem *>(currentItem()));
148 by Scott Wheeler
Edit actions should now work everywhere. The next step is cleaning up the
697
}
698
699
void Playlist::clear()
700
{
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
701
    PlaylistItemList l = selectedItems();
702
    if(l.isEmpty())
703
	l = items();
704
705
    clearItems(l);
148 by Scott Wheeler
Edit actions should now work everywhere. The next step is cleaning up the
706
}
707
499 by Scott Wheeler
Add "Refresh Items" to the RMB menu on a playlist.
708
void Playlist::slotRefresh()
709
{
710
    PlaylistItemList l = selectedItems();
711
    if(l.isEmpty())
712
	l = visibleItems();
713
714
    KApplication::setOverrideCursor(Qt::waitCursor);
715
    for(PlaylistItemList::Iterator it = l.begin(); it != l.end(); ++it) {
887 by Scott Wheeler
PlaylistItem and CollectionListItem are no longer QObject. This meant moving
716
	(*it)->refreshFromDisk();
749 by Scott Wheeler
Don't crash trying to "refresh" tags for files that no longer exist.
717
1388 by Michael Pyne
Fix bug 95446 (Refreshing removed songs leaves blank entries) in HEAD.
718
	if(!(*it)->file().tag() || !(*it)->file().fileInfo().exists()) {
749 by Scott Wheeler
Don't crash trying to "refresh" tags for files that no longer exist.
719
	    kdDebug(65432) << "Error while trying to refresh the tag.  "
720
			   << "This file has probably been removed."
721
			   << endl;
722
	    delete (*it)->collectionItem();
723
	}
724
1036 by Scott Wheeler
Get rid of a few of the processEvent() hacks and replace them with one that's
725
	processEvents();
499 by Scott Wheeler
Add "Refresh Items" to the RMB menu on a playlist.
726
    }
727
    KApplication::restoreOverrideCursor();
728
}
729
360 by Frerich Raabe
- 80% of the "Rename & Move files based on tag information" thing. Lacks
730
void Playlist::slotRenameFile()
731
{
654 by Frerich Raabe
- Don't show a busy mouse cursor when only a single item gets renamed
732
    FileRenamer renamer;
360 by Frerich Raabe
- 80% of the "Rename & Move files based on tag information" thing. Lacks
733
    PlaylistItemList items = selectedItems();
1051 by Scott Wheeler
CVS_SILENT follow the style of the rest of JuK's code
734
735
    if(items.isEmpty())
1050 by Laurent Montel
Don't call rename dialogbox when there is not item selected
736
        return;
737
1123 by Michael Pyne
Fix a bug with renaming files that is exposed by the History list. When
738
    emit signalEnableDirWatch(false);
739
1264 by Michael Pyne
GUI: Overhaul the file renamer configuration dialog based on a design of Scott's. This involved a lot more code than I thought at first, but it should be pretty neat.
740
    renamer.rename(items);
1071 by Michael Pyne
* Implement drag-and-drop retagging of songs while using the tree view playlist mode, fixing bug 62307.
741
    dataChanged();
742
1123 by Michael Pyne
Fix a bug with renaming files that is exposed by the History list. When
743
    emit signalEnableDirWatch(true);
360 by Frerich Raabe
- 80% of the "Rename & Move files based on tag information" thing. Lacks
744
}
745
1299 by Scott Wheeler
Ok, huge patch from Nathan Toone to add a cover manager and such. There
746
void Playlist::slotViewCover()
747
{
748
    PlaylistItemList items = selectedItems();
749
    if (items.isEmpty())
750
        return;
751
    for(PlaylistItemList::Iterator it = items.begin(); it != items.end(); ++it)
1359 by Scott Wheeler
Remove the now uneeded CoverPopup class and simplify things a bit. This
752
        (*it)->file().coverInfo()->popup();
1299 by Scott Wheeler
Ok, huge patch from Nathan Toone to add a cover manager and such. There
753
}
754
755
void Playlist::slotRemoveCover()
756
{
757
    PlaylistItemList items = selectedItems();
1327 by Scott Wheeler
Put the CoverInfo API on a diet; there's no need duplicating this stuff over
758
    if(items.isEmpty())
1299 by Scott Wheeler
Ok, huge patch from Nathan Toone to add a cover manager and such. There
759
        return;
1327 by Scott Wheeler
Put the CoverInfo API on a diet; there's no need duplicating this stuff over
760
    int button = KMessageBox::warningContinueCancel(this,
761
						    i18n("Are you sure you want to delete these covers?"),
762
						    QString::null,
763
						    i18n("&Delete Covers"));
1333 by Scott Wheeler
Hmm, it's better if I also check in the parts that were emitting this unused
764
    if(button == KMessageBox::Continue)
1329 by Scott Wheeler
Clean up from my last commit and also in general -- this make sure that
765
	refreshAlbums(items);
1299 by Scott Wheeler
Ok, huge patch from Nathan Toone to add a cover manager and such. There
766
}
767
768
void Playlist::slotAddCover(bool retrieveLocal)
769
{
770
    PlaylistItemList items = selectedItems();
771
772
    if(items.isEmpty())
773
        return;
774
775
    QImage image;
776
777
    if(retrieveLocal) {
778
        KURL file = KFileDialog::getImageOpenURL(
779
	    ":homedir", this, i18n("Select cover image file - JuK"));
780
        image = QImage(file.directory() + "/" + file.fileName());
781
    }
782
    else {
783
        PlaylistItemList::Iterator it=items.begin();
1305 by Scott Wheeler
Switch to using FileHandle rather than passing around tag pointers, since
784
        image = GoogleFetcher((*it)->file()).pixmap().convertToImage();;
1299 by Scott Wheeler
Ok, huge patch from Nathan Toone to add a cover manager and such. There
785
    }
786
787
    if(image.isNull())
788
        return;
789
1329 by Scott Wheeler
Clean up from my last commit and also in general -- this make sure that
790
    refreshAlbums(items, image);
1299 by Scott Wheeler
Ok, huge patch from Nathan Toone to add a cover manager and such. There
791
}
792
526 by Scott Wheeler
Went through documenting the Playlist API a bit more and doing some cleanups
793
void Playlist::slotGuessTagInfo(TagGuesser::Type type)
794
{
795
    KApplication::setOverrideCursor(Qt::waitCursor);
796
    PlaylistItemList items = selectedItems();
1210 by Michael Pyne
Fix bug 89324 (Juk crashes guessing tags in a tree view folder with only one item).
797
    setCanDeletePlaylist(false);
874 by Frerich Raabe
- Don't be so rough on the GUI while guessing tags for many files (and/or over
798
    for(PlaylistItemList::Iterator it = items.begin(); it != items.end(); ++it) {
526 by Scott Wheeler
Went through documenting the Playlist API a bit more and doing some cleanups
799
        (*it)->guessTagInfo(type);
874 by Frerich Raabe
- Don't be so rough on the GUI while guessing tags for many files (and/or over
800
1036 by Scott Wheeler
Get rid of a few of the processEvent() hacks and replace them with one that's
801
	processEvents();
874 by Frerich Raabe
- Don't be so rough on the GUI while guessing tags for many files (and/or over
802
    }
1222 by Michael Pyne
Implement bug 61340 (Add undo support for multi-tagging).
803
804
    // MusicBrainz queries automatically commit at this point.  What would
805
    // be nice is having a signal emitted when the last query is completed.
806
807
    if(type == TagGuesser::FileName)
808
	TagTransactionManager::instance()->commit();
809
1071 by Michael Pyne
* Implement drag-and-drop retagging of songs while using the tree view playlist mode, fixing bug 62307.
810
    dataChanged();
1210 by Michael Pyne
Fix bug 89324 (Juk crashes guessing tags in a tree view folder with only one item).
811
    setCanDeletePlaylist(true);
327 by Frerich Raabe
- Show a busy cursor when guessing tag information, Tag::save() is so slow :-(
812
    KApplication::restoreOverrideCursor();
326 by Frerich Raabe
- I like a few milliseconds better than a few seconds for updating an MP3 tag
813
}
814
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
815
void Playlist::slotReload()
816
{
817
    QFileInfo fileInfo(m_fileName);
818
    if(!fileInfo.exists() || !fileInfo.isFile() || !fileInfo.isReadable())
819
	return;
389 by Zack Rusin
Implementing the random play as in other modern players - meaning that although
820
491 by Scott Wheeler
Make it possible to reload multiple playlists at once.
821
    clearItems(items());
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
822
    loadFile(m_fileName, fileInfo);
823
}
824
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
825
void Playlist::slotWeightDirty(int column)
620 by Scott Wheeler
More changes related to the width. Don't barf if there are no items in the
826
{
827
    if(column < 0) {
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
828
	m_weightDirty.clear();
620 by Scott Wheeler
More changes related to the width. Don't barf if there are no items in the
829
	for(int i = 0; i < columns(); i++) {
830
	    if(isColumnVisible(i))
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
831
		m_weightDirty.append(i);
620 by Scott Wheeler
More changes related to the width. Don't barf if there are no items in the
832
	}
833
	return;
834
    }
835
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
836
    if(m_weightDirty.find(column) == m_weightDirty.end())
837
	m_weightDirty.append(column);
620 by Scott Wheeler
More changes related to the width. Don't barf if there are no items in the
838
}
839
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
840
void Playlist::slotShowPlaying()
841
{
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
842
    if(!playingItem())
991 by Scott Wheeler
Don't crash if the user clicks on the jump button when there isn't a file
843
	return;
844
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
845
    Playlist *l = playingItem()->playlist();
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
846
847
    l->clearSelection();
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
848
    l->setSelected(playingItem(), true);
849
    l->ensureItemVisible(playingItem());
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
850
    m_collection->raise(l);
851
}
852
1242 by Scott Wheeler
Make sure that the column resize settings are shared across playlists and
853
void Playlist::slotColumnResizeModeChanged()
854
{
1244 by Scott Wheeler
Make sure that we don't resize the columns on events that would normally trigger
855
    if(manualResize())
1242 by Scott Wheeler
Make sure that the column resize settings are shared across playlists and
856
	setHScrollBarMode(Auto);
857
    else
858
	setHScrollBarMode(AlwaysOff);
859
1244 by Scott Wheeler
Make sure that we don't resize the columns on events that would normally trigger
860
    if(!manualResize())
1242 by Scott Wheeler
Make sure that the column resize settings are shared across playlists and
861
	slotUpdateColumnWidths();
862
863
    SharedSettings::instance()->sync();
864
}
865
56 by Scott Wheeler
More of the architecture cleanups -- added files.
866
////////////////////////////////////////////////////////////////////////////////
180 by Scott Wheeler
More cleanups -- this time: finished TagEditor, CollectionList,
867
// protected members
59 by Scott Wheeler
Updates from the weekend. Lots of cleanups. Now also, all items in the
868
////////////////////////////////////////////////////////////////////////////////
869
526 by Scott Wheeler
Went through documenting the Playlist API a bit more and doing some cleanups
870
void Playlist::removeFromDisk(const PlaylistItemList &items)
180 by Scott Wheeler
More cleanups -- this time: finished TagEditor, CollectionList,
871
{
872
    if(isVisible() && !items.isEmpty()) {
873
1189 by Michael Pyne
Fix bug 83495 by making JuK move deleted music to the Trash instead of removing them immediately. This also caught a poor KDE developer whom I'll leave nameless, so I figured it was time to hurry up and fix this. =D
874
	QStringList files;
349 by Scott Wheeler
Switched PlaylistItemList from QPtrList<PlaylistItem> to
875
	for(PlaylistItemList::ConstIterator it = items.begin(); it != items.end(); ++it)
853 by Scott Wheeler
Start porting things over to the new fandangled FileHandle class. There's
876
            files.append((*it)->file().absFilePath());
180 by Scott Wheeler
More cleanups -- this time: finished TagEditor, CollectionList,
877
1198 by Michael Pyne
The "Delete" action can again delete files. I've changed the Remove Files dialog box to include a checkbox which allows you to delete files instead of moving them to the Trash, and the setting is saved. The default setting is to move to the Trash Bin instead of deleting.
878
	DeleteDialog dialog(this);
879
	if(dialog.confirmDeleteList(files)) {
880
	    bool shouldDelete = dialog.shouldDelete();
1288 by Michael Pyne
I think this should just about wrap up the errorList() conversions.
881
	    QStringList errorFiles;
1198 by Michael Pyne
The "Delete" action can again delete files. I've changed the Remove Files dialog box to include a checkbox which allows you to delete files instead of moving them to the Trash, and the setting is saved. The default setting is to move to the Trash Bin instead of deleting.
882
349 by Scott Wheeler
Switched PlaylistItemList from QPtrList<PlaylistItem> to
883
	    for(PlaylistItemList::ConstIterator it = items.begin(); it != items.end(); ++it) {
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
884
		if(playingItem() == *it)
1189 by Michael Pyne
Fix bug 83495 by making JuK move deleted music to the Trash instead of removing them immediately. This also caught a poor KDE developer whom I'll leave nameless, so I figured it was time to hurry up and fix this. =D
885
		    action("forward")->activate();
1097 by Michael Pyne
Fix crashtacular bug 84396, and also take the opportunity to fix a similar but as-yet-undiscovered crash bug with the back popup menu.
886
1198 by Michael Pyne
The "Delete" action can again delete files. I've changed the Remove Files dialog box to include a checkbox which allows you to delete files instead of moving them to the Trash, and the setting is saved. The default setting is to move to the Trash Bin instead of deleting.
887
		QString removePath = (*it)->file().absFilePath();
1229 by Michael Pyne
Fix bug 90606 (Trashing files no longer works). I had been planning to use trash:/ anyways, but forgot to change it.
888
		if((!shouldDelete && KIO::NetAccess::synchronousRun(KIO::trash(removePath), this)) ||
1198 by Michael Pyne
The "Delete" action can again delete files. I've changed the Remove Files dialog box to include a checkbox which allows you to delete files instead of moving them to the Trash, and the setting is saved. The default setting is to move to the Trash Bin instead of deleting.
889
		   (shouldDelete && QFile::remove(removePath))) {
438 by Scott Wheeler
* Made the static variable a class level variable and added a comment.
890
                    if(!m_randomList.isEmpty() && !m_visibleChanged)
389 by Zack Rusin
Implementing the random play as in other modern players - meaning that although
891
                        m_randomList.remove(*it);
687 by Scott Wheeler
Remove the collection item instead of removing the individual item.
892
		    CollectionList::instance()->clearItem((*it)->collectionItem());
1097 by Michael Pyne
Fix crashtacular bug 84396, and also take the opportunity to fix a similar but as-yet-undiscovered crash bug with the back popup menu.
893
894
		    // Get Orwellian and erase the song from history. :-)
895
896
		    m_history.remove(*it);
180 by Scott Wheeler
More cleanups -- this time: finished TagEditor, CollectionList,
897
		}
898
		else
1288 by Michael Pyne
I think this should just about wrap up the errorList() conversions.
899
		    errorFiles.append((*it)->file().absFilePath());
180 by Scott Wheeler
More cleanups -- this time: finished TagEditor, CollectionList,
900
	    }
901
1288 by Michael Pyne
I think this should just about wrap up the errorList() conversions.
902
	    if(!errorFiles.isEmpty()) {
903
		QString errorMsg = shouldDelete ? 
904
			i18n("Could not delete these files") :
905
			i18n("Could not move these files to the Trash");
906
		KMessageBox::errorList(this, errorMsg, errorFiles);
907
	    }
180 by Scott Wheeler
More cleanups -- this time: finished TagEditor, CollectionList,
908
	}
1062 by Scott Wheeler
Separate update() into dataChaged() and currentChanged() to avoid reshowing
909
	dataChanged();
180 by Scott Wheeler
More cleanups -- this time: finished TagEditor, CollectionList,
910
    }
911
}
912
148 by Scott Wheeler
Edit actions should now work everywhere. The next step is cleaning up the
913
QDragObject *Playlist::dragObject(QWidget *parent)
61 by Scott Wheeler
More updates including drag and drop support between playlists, from one
914
{
62 by Scott Wheeler
Yep. More general updates. The context menus on the CollectionListBox
915
    PlaylistItemList items = selectedItems();
61 by Scott Wheeler
More updates including drag and drop support between playlists, from one
916
    KURL::List urls;
349 by Scott Wheeler
Switched PlaylistItemList from QPtrList<PlaylistItem> to
917
    for(PlaylistItemList::Iterator it = items.begin(); it != items.end(); ++it) {
61 by Scott Wheeler
More updates including drag and drop support between playlists, from one
918
	KURL url;
853 by Scott Wheeler
Start porting things over to the new fandangled FileHandle class. There's
919
	url.setPath((*it)->file().absFilePath());
61 by Scott Wheeler
More updates including drag and drop support between playlists, from one
920
	urls.append(url);
921
    }
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
922
148 by Scott Wheeler
Edit actions should now work everywhere. The next step is cleaning up the
923
    KURLDrag *drag = new KURLDrag(urls, parent, "Playlist Items");
518 by Nadeem Hasan
* Use IconSets in playlist context menu.
924
    drag->setPixmap(BarIcon("sound"));
61 by Scott Wheeler
More updates including drag and drop support between playlists, from one
925
142 by Scott Wheeler
Ok, you're welcome everyone. Moving away from my long standard style
926
    return drag;
61 by Scott Wheeler
More updates including drag and drop support between playlists, from one
927
}
928
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
929
bool Playlist::canDecode(QMimeSource *s)
930
{
931
    KURL::List urls;
932
    return KURLDrag::decode(s, urls) && !urls.isEmpty();
933
}
934
1322 by Scott Wheeler
Handle image drops in the decode function rather than a separate one. Also
935
void Playlist::decode(QMimeSource *s, PlaylistItem *item)
148 by Scott Wheeler
Edit actions should now work everywhere. The next step is cleaning up the
936
{
937
    KURL::List urls;
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
938
148 by Scott Wheeler
Edit actions should now work everywhere. The next step is cleaning up the
939
    if(!KURLDrag::decode(s, urls) || urls.isEmpty())
940
	return;
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
941
1322 by Scott Wheeler
Handle image drops in the decode function rather than a separate one. Also
942
    // handle dropped images
943
944
    if(!MediaFiles::isMediaFile(urls.front().path())) {
945
946
	QString file;
947
948
	if(urls.front().isLocalFile())
949
	    file = urls.front().path();
950
	else
951
	    KIO::NetAccess::download(urls.front(), file, 0);
952
953
	KMimeType::Ptr mimeType = KMimeType::findByPath(file);
954
955
	if(item && mimeType->name().startsWith("image/")) {
1327 by Scott Wheeler
Put the CoverInfo API on a diet; there's no need duplicating this stuff over
956
	    item->file().coverInfo()->setCover(QImage(file));
1322 by Scott Wheeler
Handle image drops in the decode function rather than a separate one. Also
957
	    refreshAlbum(item->file().tag()->artist(),
958
			 item->file().tag()->album());
959
	}
1341 by Scott Wheeler
Remove temp files when we're done with them.
960
961
        KIO::NetAccess::removeTempFile(file);
1322 by Scott Wheeler
Handle image drops in the decode function rather than a separate one. Also
962
    }
963
148 by Scott Wheeler
Edit actions should now work everywhere. The next step is cleaning up the
964
    QStringList fileList;
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
965
1251 by Laurent Montel
it++ -> ++it
966
    for(KURL::List::Iterator it = urls.begin(); it != urls.end(); ++it)
148 by Scott Wheeler
Edit actions should now work everywhere. The next step is cleaning up the
967
	fileList.append((*it).path());
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
968
1322 by Scott Wheeler
Handle image drops in the decode function rather than a separate one. Also
969
    addFiles(fileList, m_collection->importPlaylists(), item);
148 by Scott Wheeler
Edit actions should now work everywhere. The next step is cleaning up the
970
}
971
547 by Scott Wheeler
Ignore clicks on the listview header when above the padding column at the
972
bool Playlist::eventFilter(QObject *watched, QEvent *e)
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
973
{
547 by Scott Wheeler
Ignore clicks on the listview header when above the padding column at the
974
    if(watched == header()) {
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
975
	switch(e->type()) {
976
	case QEvent::MouseButtonPress:
977
	{
1241 by Scott Wheeler
Automatically switch on manual column width mode if the user tries to resize
978
	    switch(static_cast<QMouseEvent *>(e)->button()) {
979
	    case RightButton:
178 by Scott Wheeler
Wrote a lovely little script to prefix all member variables with m_
980
		m_headerMenu->popup(QCursor::pos());
1241 by Scott Wheeler
Automatically switch on manual column width mode if the user tries to resize
981
		break;
982
	    case LeftButton:
983
		m_mousePressed = true;
984
		break;
985
	    default:
986
		break;
987
	    }
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
988
	    break;
989
	}
990
	case QEvent::MouseButtonRelease:
991
	{
1241 by Scott Wheeler
Automatically switch on manual column width mode if the user tries to resize
992
	    if(static_cast<QMouseEvent *>(e)->button() == LeftButton)
993
		m_mousePressed = false;
994
1244 by Scott Wheeler
Make sure that we don't resize the columns on events that would normally trigger
995
	    if(!manualResize() && m_widthsDirty)
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
996
		QTimer::singleShot(0, this, SLOT(slotUpdateColumnWidths()));
997
	    break;
998
	}
999
1000
	default:
1001
	    break;
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1002
	}
1003
    }
1004
1005
    return KListView::eventFilter(watched, e);
1006
}
1007
61 by Scott Wheeler
More updates including drag and drop support between playlists, from one
1008
void Playlist::contentsDropEvent(QDropEvent *e)
1009
{
532 by Scott Wheeler
More changes from Lars. I did a number of cosmetic changes; Lars, can
1010
    QPoint vp = contentsToViewport(e->pos());
1322 by Scott Wheeler
Handle image drops in the decode function rather than a separate one. Also
1011
    PlaylistItem *item = static_cast<PlaylistItem *>(itemAt(vp));
532 by Scott Wheeler
More changes from Lars. I did a number of cosmetic changes; Lars, can
1012
1013
    // When dropping on the upper half of an item, insert before this item.
1014
    // This is what the user expects, and also allows the insertion at
1015
    // top of the list
1016
1322 by Scott Wheeler
Handle image drops in the decode function rather than a separate one. Also
1017
    if(!item)
1018
	item = static_cast<PlaylistItem *>(lastItem());
1019
    else if(vp.y() < item->itemPos() + item->height() / 2)
1020
	item = static_cast<PlaylistItem *>(item->itemAbove());
532 by Scott Wheeler
More changes from Lars. I did a number of cosmetic changes; Lars, can
1021
61 by Scott Wheeler
More updates including drag and drop support between playlists, from one
1022
    if(e->source() == this) {
500 by Scott Wheeler
Make it so that dragging something around automatically turns off sorting.
1023
1024
	// Since we're trying to arrange things manually, turn off sorting.
1025
1026
	setSorting(columns() + 1);
1027
61 by Scott Wheeler
More updates including drag and drop support between playlists, from one
1028
	QPtrList<QListViewItem> items = KListView::selectedItems();
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
1029
62 by Scott Wheeler
Yep. More general updates. The context menus on the CollectionListBox
1030
	for(QPtrListIterator<QListViewItem> it(items); it.current(); ++it) {
1322 by Scott Wheeler
Handle image drops in the decode function rather than a separate one. Also
1031
	    if(!item) {
532 by Scott Wheeler
More changes from Lars. I did a number of cosmetic changes; Lars, can
1032
1033
		// Insert the item at the top of the list.  This is a bit ugly,
1034
		// but I don't see another way.
1035
1036
		takeItem(it.current());
1037
		insertItem(it.current());
1038
	    }
1039
	    else
1322 by Scott Wheeler
Handle image drops in the decode function rather than a separate one. Also
1040
		it.current()->moveItem(item);
532 by Scott Wheeler
More changes from Lars. I did a number of cosmetic changes; Lars, can
1041
1322 by Scott Wheeler
Handle image drops in the decode function rather than a separate one. Also
1042
	    item = static_cast<PlaylistItem *>(it.current());
61 by Scott Wheeler
More updates including drag and drop support between playlists, from one
1043
	}
1044
    }
148 by Scott Wheeler
Edit actions should now work everywhere. The next step is cleaning up the
1045
    else
1322 by Scott Wheeler
Handle image drops in the decode function rather than a separate one. Also
1046
	decode(e, item);
601 by Scott Wheeler
Call the implementation in the base class so that the drag indicator is
1047
1071 by Michael Pyne
* Implement drag-and-drop retagging of songs while using the tree view playlist mode, fixing bug 62307.
1048
    dataChanged();
1209 by Michael Pyne
Automatically switch to the destination playlist if you hover over the playlist icon for a moment during a drag-and-drop operation.
1049
    emit signalPlaylistItemsDropped(this);
601 by Scott Wheeler
Call the implementation in the base class so that the drag indicator is
1050
    KListView::contentsDropEvent(e);
61 by Scott Wheeler
More updates including drag and drop support between playlists, from one
1051
}
1052
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
1053
void Playlist::contentsMouseDoubleClickEvent(QMouseEvent *e)
1054
{
1352 by Michael Pyne
You should be able to programmatically disable the Upcoming Playlist once it's enabled without having to manually uncheck the KAction.
1055
    // Filter out non left button double clicks, that way users don't have the
1056
    // weird experience of switching songs from a double right-click.
1057
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
1058
    if(e->button() == LeftButton)
1059
	KListView::contentsMouseDoubleClickEvent(e);
1060
}
1061
277 by Scott Wheeler
Save and restore column order.
1062
void Playlist::showEvent(QShowEvent *e)
1063
{
679 by Scott Wheeler
Try even harder to not call redisplaySearch() again with the goal of making
1064
    if(m_applySharedSettings) {
1065
	SharedSettings::instance()->apply(this);
1066
	m_applySharedSettings = false;
1067
    }
277 by Scott Wheeler
Save and restore column order.
1068
    KListView::showEvent(e);
1069
}
1070
679 by Scott Wheeler
Try even harder to not call redisplaySearch() again with the goal of making
1071
void Playlist::applySharedSettings()
1072
{
1073
    m_applySharedSettings = true;
1074
}
1075
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1076
void Playlist::read(QDataStream &s)
1077
{
1078
    QString buffer;
1079
1080
    s >> m_playlistName
1081
      >> m_fileName;
1082
1083
    QStringList files;
1084
    s >> files;
1059 by Scott Wheeler
Make startup time fast again -- make sure that we don't stat things before
1085
1086
    QListViewItem *after = 0;
1087
    for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it)
1088
        after = createItem(FileHandle(*it), after, false);
1089
1062 by Scott Wheeler
Separate update() into dataChaged() and currentChanged() to avoid reshowing
1090
    dataChanged();
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1091
    m_collection->setupPlaylist(this, "midi");
1092
}
1093
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1094
void Playlist::viewportPaintEvent(QPaintEvent *pe)
1095
{
1096
    // If there are columns that need to be updated, well, update them.
1097
1244 by Scott Wheeler
Make sure that we don't resize the columns on events that would normally trigger
1098
    if(!m_weightDirty.isEmpty() && !manualResize())
1099
    {
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1100
	calculateColumnWeights();
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
1101
	slotUpdateColumnWidths();
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1102
    }
1103
1104
    KListView::viewportPaintEvent(pe);
1105
}
1106
1107
void Playlist::viewportResizeEvent(QResizeEvent *re)
1108
{
1109
    // If the width of the view has changed, manually update the column
1110
    // widths.
1111
1244 by Scott Wheeler
Make sure that we don't resize the columns on events that would normally trigger
1112
    if(re->size().width() != re->oldSize().width() && !manualResize())
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
1113
	slotUpdateColumnWidths();
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1114
1115
    KListView::viewportResizeEvent(re);
1116
}
1117
1118
void Playlist::addColumn(const QString &label)
1119
{
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
1120
    slotWeightDirty(columns());
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1121
    KListView::addColumn(label, 30);
1122
}
1123
894 by Scott Wheeler
*) Ported Playlist::createItem() over to using FileHandle.
1124
PlaylistItem *Playlist::createItem(const FileHandle &file,
523 by Scott Wheeler
Another patch based on Lars's work. Translate the coordinates properly and
1125
				   QListViewItem *after, bool emitChanged)
59 by Scott Wheeler
Updates from the weekend. Lots of cleanups. Now also, all items in the
1126
{
894 by Scott Wheeler
*) Ported Playlist::createItem() over to using FileHandle.
1127
    return createItem<PlaylistItem, CollectionListItem, CollectionList>(file, after, emitChanged);
59 by Scott Wheeler
Updates from the weekend. Lots of cleanups. Now also, all items in the
1128
}
1129
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
1130
void Playlist::createItems(const PlaylistItemList &siblings, PlaylistItem *after)
365 by Scott Wheeler
Added a new method for creating new PlaylistItems that are copies of other
1131
{
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
1132
    createItems<CollectionListItem, PlaylistItem, PlaylistItem>(siblings, after);
365 by Scott Wheeler
Added a new method for creating new PlaylistItems that are copies of other
1133
}
1134
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1135
void Playlist::addFiles(const QStringList &files, bool importPlaylists,
1136
			PlaylistItem *after)
1137
{
1138
    if(!after)
1139
	after = static_cast<PlaylistItem *>(lastItem());
1140
1141
    KApplication::setOverrideCursor(Qt::waitCursor);
1142
1143
    PaintEater pe(this);
1144
1145
    for(QStringList::ConstIterator it = files.begin(); it != files.end(); ++it)
1146
        after = addFile(*it, importPlaylists, after);
1147
1148
    slotWeightDirty();
1062 by Scott Wheeler
Separate update() into dataChaged() and currentChanged() to avoid reshowing
1149
    dataChanged();
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1150
1151
    KApplication::restoreOverrideCursor();
1152
}
1153
1329 by Scott Wheeler
Clean up from my last commit and also in general -- this make sure that
1154
void Playlist::refreshAlbums(const PlaylistItemList &items, const QImage &image)
1155
{
1156
    QValueList< QPair<QString, QString> > albums;
1157
1158
    for(PlaylistItemList::ConstIterator it = items.begin(); it != items.end(); ++it) {
1159
	if(albums.find(qMakePair((*it)->file().tag()->artist(),
1160
				 (*it)->file().tag()->album())) == albums.end())
1161
	{
1162
	    albums.append(qMakePair((*it)->file().tag()->artist(),
1163
				    (*it)->file().tag()->album()));				    
1164
	    if(image.isNull())
1165
		(*it)->file().coverInfo()->clearCover();
1166
	    else
1167
		(*it)->file().coverInfo()->setCover(image);
1168
	}
1169
	else
1170
	    (*it)->file().coverInfo()->setCover();
1171
    }
1172
1173
    for(QValueList< QPair<QString, QString> >::ConstIterator it = albums.begin();
1174
	it != albums.end(); ++it)
1175
    {
1176
	refreshAlbum((*it).first, (*it).second);
1177
    }
1178
}
1179
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
1180
void Playlist::updatePlaying() const
1181
{
1344 by Scott Wheeler
Keep showing the playing item when a dynamic list is created and restore it
1182
    for(PlaylistItemList::ConstIterator it = PlaylistItem::playingItems().begin();
1183
	it != PlaylistItem::playingItems().end(); ++it)
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
1184
    {
1185
	(*it)->listView()->triggerUpdate();
1186
    }
1187
}
1188
1322 by Scott Wheeler
Handle image drops in the decode function rather than a separate one. Also
1189
void Playlist::refreshAlbum(const QString &artist, const QString &album)
1190
{
1191
    ColumnList columns;
1192
    columns.append(PlaylistItem::ArtistColumn);
1193
    PlaylistSearch::Component artistComponent(artist, false, columns,
1194
					      PlaylistSearch::Component::Exact);
1195
1196
    columns.clear();
1197
    columns.append(PlaylistItem::AlbumColumn);
1198
    PlaylistSearch::Component albumComponent(album, false, columns,
1199
					     PlaylistSearch::Component::Exact);
1200
1201
    PlaylistSearch::ComponentList components;
1202
    components.append(artist);
1203
    components.append(album);
1204
1205
    PlaylistList playlists;
1206
    playlists.append(CollectionList::instance());
1207
1208
    PlaylistSearch search(playlists, components);
1209
    PlaylistItemList matches = search.matchedItems();
1210
1211
    for(PlaylistItemList::Iterator it = matches.begin(); it != matches.end(); ++it)
1212
	(*it)->refresh();
1213
}
1214
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1215
void Playlist::hideColumn(int c, bool updateSearch)
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1216
{
178 by Scott Wheeler
Wrote a lovely little script to prefix all member variables with m_
1217
    m_headerMenu->setItemChecked(c, false);
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1218
667 by Scott Wheeler
Make it so that the visible column list is updated correctly when it's
1219
    if(!isColumnVisible(c))
1220
	return;
1221
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1222
    setColumnWidthMode(c, Manual);
1223
    setColumnWidth(c, 0);
222 by Scott Wheeler
Ok, added some fixes to make the "left most column" => "left most *visible*
1224
1231 by Michael Pyne
I do believe that this is the best we're going to be able to do with manual column resizing combined with the possibility of showing and hiding columns.
1225
    // Moving the column to the end seems to prevent it from randomly
1226
    // popping up.
1227
1228
    header()->moveSection(c, header()->count());
1229
    header()->setResizeEnabled(false, c);
1230
222 by Scott Wheeler
Ok, added some fixes to make the "left most column" => "left most *visible*
1231
    if(c == m_leftColumn) {
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
1232
	updatePlaying();
222 by Scott Wheeler
Ok, added some fixes to make the "left most column" => "left most *visible*
1233
	m_leftColumn = leftMostVisibleColumn();
1234
    }
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1235
1244 by Scott Wheeler
Make sure that we don't resize the columns on events that would normally trigger
1236
    if(!manualResize()) {
1237
	slotUpdateColumnWidths();
1238
	triggerUpdate();
1239
    }
667 by Scott Wheeler
Make it so that the visible column list is updated correctly when it's
1240
1241
    if(this != CollectionList::instance())
676 by Scott Wheeler
Don't refresh the search so often (i.e. every time that a column is shown
1242
	CollectionList::instance()->hideColumn(c, false);
667 by Scott Wheeler
Make it so that the visible column list is updated correctly when it's
1243
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1244
    if(updateSearch)
1245
	redisplaySearch();
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1246
}
1247
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1248
void Playlist::showColumn(int c, bool updateSearch)
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1249
{
178 by Scott Wheeler
Wrote a lovely little script to prefix all member variables with m_
1250
    m_headerMenu->setItemChecked(c, true);
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1251
667 by Scott Wheeler
Make it so that the visible column list is updated correctly when it's
1252
    if(isColumnVisible(c))
1253
	return;
1254
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1255
    // Just set the width to one to mark the column as visible -- we'll update
1256
    // the real size in the next call.
1257
1258
    setColumnWidth(c, 1);
1231 by Michael Pyne
I do believe that this is the best we're going to be able to do with manual column resizing combined with the possibility of showing and hiding columns.
1259
    header()->setResizeEnabled(true, c);
1260
    header()->moveSection(c, c); // Approximate old position
222 by Scott Wheeler
Ok, added some fixes to make the "left most column" => "left most *visible*
1261
1262
    if(c == leftMostVisibleColumn()) {
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
1263
	updatePlaying();
222 by Scott Wheeler
Ok, added some fixes to make the "left most column" => "left most *visible*
1264
	m_leftColumn = leftMostVisibleColumn();
1265
    }
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1266
1244 by Scott Wheeler
Make sure that we don't resize the columns on events that would normally trigger
1267
    if(!manualResize()) {
1268
	slotUpdateColumnWidths();
1269
	triggerUpdate();
1270
    }
667 by Scott Wheeler
Make it so that the visible column list is updated correctly when it's
1271
1272
    if(this != CollectionList::instance())
676 by Scott Wheeler
Don't refresh the search so often (i.e. every time that a column is shown
1273
	CollectionList::instance()->showColumn(c, false);
667 by Scott Wheeler
Make it so that the visible column list is updated correctly when it's
1274
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1275
    if(updateSearch)
1276
	redisplaySearch();
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1277
}
1278
1279
bool Playlist::isColumnVisible(int c) const
1280
{
222 by Scott Wheeler
Ok, added some fixes to make the "left most column" => "left most *visible*
1281
    return columnWidth(c) != 0;
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1282
}
1283
466 by Scott Wheeler
Create playlists (and as such load) faster by delaying much of the
1284
void Playlist::polish()
56 by Scott Wheeler
More of the architecture cleanups -- added files.
1285
{
468 by Scott Wheeler
A couple of small clean ups and added some processEvents hackery...
1286
    KListView::polish();
1287
466 by Scott Wheeler
Create playlists (and as such load) faster by delaying much of the
1288
    if(m_polished)
1289
	return;
1290
1291
    m_polished = true;
1292
56 by Scott Wheeler
More of the architecture cleanups -- added files.
1293
    addColumn(i18n("Track Name"));
1294
    addColumn(i18n("Artist"));
1295
    addColumn(i18n("Album"));
1299 by Scott Wheeler
Ok, huge patch from Nathan Toone to add a cover manager and such. There
1296
    addColumn(i18n("Cover"));
56 by Scott Wheeler
More of the architecture cleanups -- added files.
1297
    addColumn(i18n("Track"));
1298
    addColumn(i18n("Genre"));
1299
    addColumn(i18n("Year"));
1300
    addColumn(i18n("Length"));
902 by Scott Wheeler
Add a bitrate column (hidden by default).
1301
    addColumn(i18n("Bitrate"));
332 by Scott Wheeler
Added a comment column (that's hidden by default) and also made the file
1302
    addColumn(i18n("Comment"));
56 by Scott Wheeler
More of the architecture cleanups -- added files.
1303
    addColumn(i18n("File Name"));
1150 by Scott Wheeler
Ok, here's an altogether more sane approach to this -- just split this up
1304
    addColumn(i18n("File Name (full path)"));
56 by Scott Wheeler
More of the architecture cleanups -- added files.
1305
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1306
    setRenameable(PlaylistItem::TrackColumn, true);
1307
    setRenameable(PlaylistItem::ArtistColumn, true);
1308
    setRenameable(PlaylistItem::AlbumColumn, true);
112 by Scott Wheeler
Got inline editing mostly done.
1309
    setRenameable(PlaylistItem::TrackNumberColumn, true);
108 by Scott Wheeler
Added genre support to inline editing. Also added "Remove files" to the
1310
    setRenameable(PlaylistItem::GenreColumn, true);
112 by Scott Wheeler
Got inline editing mostly done.
1311
    setRenameable(PlaylistItem::YearColumn, true);
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1312
56 by Scott Wheeler
More of the architecture cleanups -- added files.
1313
    setAllColumnsShowFocus(true);
1314
    setSelectionMode(QListView::Extended);
1315
    setShowSortIndicator(true);
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1316
    setDropVisualizer(true);
56 by Scott Wheeler
More of the architecture cleanups -- added files.
1317
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
1318
    m_columnFixedWidths.resize(columns(), 0);
1319
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1320
    //////////////////////////////////////////////////
1321
    // setup header RMB menu
1322
    //////////////////////////////////////////////////
1323
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
1324
    m_columnVisibleAction = new KActionMenu(i18n("&Show Columns"), this, "showColumns");
466 by Scott Wheeler
Create playlists (and as such load) faster by delaying much of the
1325
178 by Scott Wheeler
Wrote a lovely little script to prefix all member variables with m_
1326
    m_headerMenu = m_columnVisibleAction->popupMenu();
1327
    m_headerMenu->insertTitle(i18n("Show"));
1328
    m_headerMenu->setCheckable(true);
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1329
468 by Scott Wheeler
A couple of small clean ups and added some processEvents hackery...
1330
    for(int i = 0; i < header()->count(); ++i) {
1150 by Scott Wheeler
Ok, here's an altogether more sane approach to this -- just split this up
1331
	if(i == PlaylistItem::FileNameColumn)
1332
	    m_headerMenu->insertSeparator();
178 by Scott Wheeler
Wrote a lovely little script to prefix all member variables with m_
1333
	m_headerMenu->insertItem(header()->label(i), i);
1334
	m_headerMenu->setItemChecked(i, true);
474 by Daniel Molkentin
The "proper workaround" ;)
1335
	adjustColumn(i);
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1336
    }
1337
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
1338
    connect(m_headerMenu, SIGNAL(activated(int)), this, SLOT(slotToggleColumnVisible(int)));
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1339
526 by Scott Wheeler
Went through documenting the Playlist API a bit more and doing some cleanups
1340
    connect(this, SIGNAL(contextMenuRequested(QListViewItem *, const QPoint &, int)),
180 by Scott Wheeler
More cleanups -- this time: finished TagEditor, CollectionList,
1341
	    this, SLOT(slotShowRMBMenu(QListViewItem *, const QPoint &, int)));
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1342
    connect(this, SIGNAL(itemRenamed(QListViewItem *, const QString &, int)),
764 by Scott Wheeler
CVS_SILENT API nitpicks
1343
	    this, SLOT(slotInlineEditDone(QListViewItem *, const QString &, int)));
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1344
    connect(this, SIGNAL(doubleClicked(QListViewItem *)),
1345
	    this, SLOT(slotPlayCurrent()));
1050 by Laurent Montel
Don't call rename dialogbox when there is not item selected
1346
    connect(this, SIGNAL(returnPressed(QListViewItem *)),
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1347
	    this, SLOT(slotPlayCurrent()));
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1348
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
1349
    connect(header(), SIGNAL(sizeChange(int, int, int)),
1350
	    this, SLOT(slotColumnSizeChanged(int, int, int)));
1351
673 by Scott Wheeler
Save / restore the "completion mode" for the inline tag editor in JuK's
1352
    connect(renameLineEdit(), SIGNAL(completionModeChanged(KGlobalSettings::Completion)),
1353
	    this, SLOT(slotInlineCompletionModeChanged(KGlobalSettings::Completion)));
1354
1241 by Scott Wheeler
Automatically switch on manual column width mode if the user tries to resize
1355
    connect(action("resizeColumnsManually"), SIGNAL(activated()),
1356
	    this, SLOT(slotColumnResizeModeChanged()));
1357
1358
    if(action<KToggleAction>("resizeColumnsManually")->isChecked())
1359
	setHScrollBarMode(Auto);
1360
    else
1361
	setHScrollBarMode(AlwaysOff);
56 by Scott Wheeler
More of the architecture cleanups -- added files.
1362
63 by Scott Wheeler
Uhh. Fixed stuff. Added features.
1363
    setAcceptDrops(true);
507 by Scott Wheeler
Moved some things around to make the drop indicator work properly.
1364
    setDropVisualizer(true);
620 by Scott Wheeler
More changes related to the width. Don't barf if there are no items in the
1365
1366
    m_disableColumnWidthUpdates = false;
903 by Scott Wheeler
Only show the "short" file name (i.e. not the path) in the column by default
1367
1368
    setShowToolTips(false);
1013 by Scott Wheeler
Valgrind pointed out that QToolTips are not QObjects and aren't deleted when
1369
    m_toolTip = new PlaylistToolTip(viewport(), this);
466 by Scott Wheeler
Create playlists (and as such load) faster by delaying much of the
1370
}
1371
755 by Scott Wheeler
Make it so that items that are added are checked against the current search
1372
void Playlist::setupItem(PlaylistItem *item)
1373
{
1374
    if(!m_search.isEmpty())
1375
	item->setVisible(m_search.checkItem(item));
1038 by Scott Wheeler
A small hack to update the playlist column widths when the second item is
1376
1244 by Scott Wheeler
Make sure that we don't resize the columns on events that would normally trigger
1377
    if(childCount() <= 2 && !manualResize()) {
1038 by Scott Wheeler
A small hack to update the playlist column widths when the second item is
1378
	slotWeightDirty();
1379
	slotUpdateColumnWidths();
1380
	triggerUpdate();
1381
    }
755 by Scott Wheeler
Make it so that items that are added are checked against the current search
1382
}
1383
1210 by Michael Pyne
Fix bug 89324 (Juk crashes guessing tags in a tree view folder with only one item).
1384
void Playlist::setCanDeletePlaylist(bool canDelete)
1385
{
1386
    m_collection->setCanDeletePlaylist(canDelete);
1387
}
1388
466 by Scott Wheeler
Create playlists (and as such load) faster by delaying much of the
1389
////////////////////////////////////////////////////////////////////////////////
1067 by Scott Wheeler
Forgot to commit this earlier...make the back popup menu work again.
1390
// protected slots
1391
////////////////////////////////////////////////////////////////////////////////
1392
1393
void Playlist::slotPopulateBackMenu() const
1394
{
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
1395
    if(!playingItem())
1067 by Scott Wheeler
Forgot to commit this earlier...make the back popup menu work again.
1396
	return;
1397
1398
    KPopupMenu *menu = action<KToolBarPopupAction>("back")->popupMenu();
1399
    menu->clear();
1400
    m_backMenuItems.clear();
1401
1402
    int count = 0;
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
1403
    PlaylistItemList::ConstIterator it = m_history.end();
1067 by Scott Wheeler
Forgot to commit this earlier...make the back popup menu work again.
1404
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
1405
    while(it != m_history.begin() && count < 10) {
1067 by Scott Wheeler
Forgot to commit this earlier...make the back popup menu work again.
1406
	++count;
1407
	--it;
1408
	int index = menu->insertItem((*it)->file().tag()->title());
1409
	m_backMenuItems[index] = *it;
1410
    }
1411
}
1412
1413
void Playlist::slotPlayFromBackMenu(int number) const
1414
{
1415
    if(!m_backMenuItems.contains(number))
1416
	return;
1417
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
1418
    TrackSequenceManager::instance()->setNextItem(m_backMenuItems[number]);
1067 by Scott Wheeler
Forgot to commit this earlier...make the back popup menu work again.
1419
    action("forward")->activate();
1420
}
1421
1422
////////////////////////////////////////////////////////////////////////////////
466 by Scott Wheeler
Create playlists (and as such load) faster by delaying much of the
1423
// private members
1424
////////////////////////////////////////////////////////////////////////////////
1425
1426
void Playlist::setup()
1427
{
471 by Scott Wheeler
QListView doesn't seem to update the items if you set the margin after
1428
    setItemMargin(3);
1429
221 by Scott Wheeler
Make it so that the left most column always displays the playing indicator.
1430
    connect(header(), SIGNAL(indexChange(int, int, int)), this, SLOT(slotColumnOrderChanged(int, int, int)));
756 by Scott Wheeler
Save and restore the sort column for playlists.
1431
    setSorting(1);
221 by Scott Wheeler
Make it so that the left most column always displays the playing indicator.
1432
}
1433
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
1434
void Playlist::loadFile(const QString &fileName, const QFileInfo &fileInfo)
1435
{
1436
    QFile file(fileName);
1437
    if(!file.open(IO_ReadOnly))
1438
	return;
1439
1440
    QTextStream stream(&file);
1441
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1442
    // Turn off non-explicit sorting.
1443
926 by Scott Wheeler
Use the static column width from PlaylistItem rather than fetching the current
1444
    setSorting(PlaylistItem::lastColumn() + columnOffset() + 1);
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
1445
1446
    PlaylistItem *after = 0;
1447
620 by Scott Wheeler
More changes related to the width. Don't barf if there are no items in the
1448
    m_disableColumnWidthUpdates = true;
1449
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
1450
    while(!stream.atEnd()) {
410 by Scott Wheeler
Added a new namespace to encapsulate all of the operations that know about
1451
	QString itemName = stream.readLine().stripWhiteSpace();
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
1452
1453
	QFileInfo item(itemName);
1454
1455
	if(item.isRelative())
1456
	    item.setFile(QDir::cleanDirPath(fileInfo.dirPath(true) + "/" + itemName));
1457
870 by Waldo Bastian
Keep files and directories separate (BR70371)
1458
	if(item.exists() && item.isFile() && item.isReadable() &&
1459
	   MediaFiles::isMediaFile(item.fileName()))
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1460
	{
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
1461
	    if(after)
894 by Scott Wheeler
*) Ported Playlist::createItem() over to using FileHandle.
1462
		after = createItem(FileHandle(item, item.absFilePath()), after, false);
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
1463
	    else
894 by Scott Wheeler
*) Ported Playlist::createItem() over to using FileHandle.
1464
		after = createItem(FileHandle(item, item.absFilePath()), 0, false);
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
1465
	}
1466
    }
1467
1468
    file.close();
451 by Scott Wheeler
More work on the SearchPlaylist class to get it ready for usage with
1469
1062 by Scott Wheeler
Separate update() into dataChaged() and currentChanged() to avoid reshowing
1470
    dataChanged();
775 by Lukáš Tinkl
have to change this text, it creates awful nonsenses
1471
620 by Scott Wheeler
More changes related to the width. Don't barf if there are no items in the
1472
    m_disableColumnWidthUpdates = false;
343 by Scott Wheeler
Added "reload from disk" in the RMB menu for the PlaylistBox.
1473
}
1474
1065 by Scott Wheeler
Make back work in random play mode again.
1475
void Playlist::setPlaying(PlaylistItem *item, bool addToHistory)
221 by Scott Wheeler
Make it so that the left most column always displays the playing indicator.
1476
{
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
1477
    if(playingItem() == item)
1065 by Scott Wheeler
Make back work in random play mode again.
1478
	return;
1479
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
1480
    if(playingItem()) {
1199 by Michael Pyne
Fix bug 88847 (Previous track doesn't work anymore in Play Queue mode). This was actually by design, as items in the upcoming playlist are so ephemeral that keeping track of them would later crash JuK. However, instead the associate collection list item is stored instead, which I feel is a better alternative.
1481
	if(addToHistory) {
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
1482
	    if(playingItem()->playlist() == m_upcomingPlaylist)
1483
		m_history.append(playingItem()->collectionItem());
1199 by Michael Pyne
Fix bug 88847 (Previous track doesn't work anymore in Play Queue mode). This was actually by design, as items in the upcoming playlist are so ephemeral that keeping track of them would later crash JuK. However, instead the associate collection list item is stored instead, which I feel is a better alternative.
1484
	    else
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
1485
		m_history.append(playingItem());
1199 by Michael Pyne
Fix bug 88847 (Previous track doesn't work anymore in Play Queue mode). This was actually by design, as items in the upcoming playlist are so ephemeral that keeping track of them would later crash JuK. However, instead the associate collection list item is stored instead, which I feel is a better alternative.
1486
	}
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
1487
	playingItem()->setPlaying(false);
221 by Scott Wheeler
Make it so that the left most column always displays the playing indicator.
1488
    }
294 by Scott Wheeler
Change the column color of the playing row.
1489
1182 by Michael Pyne
Fix bug 87659 (Dynamic playlists not responding correctly).
1490
    TrackSequenceManager::instance()->setCurrent(item);
1491
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1492
    if(!item)
1493
	return;
1494
1495
    item->setPlaying(true);
1067 by Scott Wheeler
Forgot to commit this earlier...make the back popup menu work again.
1496
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
1497
    bool enableBack = !m_history.isEmpty();
1067 by Scott Wheeler
Forgot to commit this earlier...make the back popup menu work again.
1498
    action<KToolBarPopupAction>("back")->popupMenu()->setEnabled(enableBack);
56 by Scott Wheeler
More of the architecture cleanups -- added files.
1499
}
1500
446 by Scott Wheeler
* Cleaned up some includes
1501
bool Playlist::playing() const
1502
{
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
1503
    return playingItem() && this == playingItem()->playlist();
446 by Scott Wheeler
* Cleaned up some includes
1504
}
1505
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1506
int Playlist::leftMostVisibleColumn() const
1507
{
1508
    int i = 0;
1509
    while(!isColumnVisible(header()->mapToSection(i)) && i < PlaylistItem::lastColumn())
1510
	i++;
1511
1512
    return header()->mapToSection(i);
1513
}
1514
678 by Scott Wheeler
Use the newly discovered QListViewItemIterator::IteratorFlag to drive the
1515
PlaylistItemList Playlist::items(QListViewItemIterator::IteratorFlag flags)
1516
{
1517
    PlaylistItemList list;
1518
1519
    for(QListViewItemIterator it(this, flags); it.current(); ++it)
1520
	list.append(static_cast<PlaylistItem *>(it.current()));
1521
1522
    return list;
1523
}
1524
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
1525
void Playlist::calculateColumnWeights()
1526
{
1527
    if(m_disableColumnWidthUpdates)
1528
	return;
1529
1530
    PlaylistItemList l = items();
1531
    QValueListConstIterator<int> columnIt;
1532
1533
    QValueVector<double> averageWidth(columns(), 0);
1534
    double itemCount = l.size();
1535
1536
    QValueVector<int> cachedWidth;
1537
1538
    // Here we're not using a real average, but averaging the squares of the
1539
    // column widths and then using the square root of that value.  This gives
1540
    // a nice weighting to the longer columns without doing something arbitrary
1541
    // like adding a fixed amount of padding.
1542
1543
    for(PlaylistItemList::ConstIterator it = l.begin(); it != l.end(); ++it) {
1544
	cachedWidth = (*it)->cachedWidths();
1545
	for(columnIt = m_weightDirty.begin(); columnIt != m_weightDirty.end(); ++columnIt)
903 by Scott Wheeler
Only show the "short" file name (i.e. not the path) in the column by default
1546
	    averageWidth[*columnIt] += pow(double(cachedWidth[*columnIt]), 2.0) / itemCount;
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
1547
    }
1548
1549
    m_columnWeights.resize(columns(), -1);
1550
1551
    for(columnIt = m_weightDirty.begin(); columnIt != m_weightDirty.end(); ++columnIt) {
1552
	m_columnWeights[*columnIt] = int(sqrt(averageWidth[*columnIt]) + 0.5);
1553
1554
	//  kdDebug(65432) << k_funcinfo << "m_columnWeights[" << *columnIt << "] == "
1555
	//                 << m_columnWeights[*columnIt] << endl;
1556
    }
1557
1558
    m_weightDirty.clear();
1559
}
1560
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1561
PlaylistItem *Playlist::addFile(const QString &file, bool importPlaylists,
1562
				PlaylistItem *after)
1563
{
1158 by Scott Wheeler
Update the status bar while loading.
1564
    if(processEvents())
1565
	m_collection->dataChanged();
1036 by Scott Wheeler
Get rid of a few of the processEvent() hacks and replace them with one that's
1566
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1567
    const QFileInfo fileInfo = QDir::cleanDirPath(file);
1568
1569
    if(!fileInfo.exists())
1570
	return after;
1571
1572
    if(fileInfo.isFile() && fileInfo.isReadable()) {
1573
	if(MediaFiles::isMediaFile(file))
1574
	    return createItem(FileHandle(fileInfo, fileInfo.absFilePath()), after, false);
1575
1029 by Scott Wheeler
The deleteLater() thing for duplicate playlist file was a bad, bad idea.
1576
	if(importPlaylists && MediaFiles::isPlaylistFile(file) &&
1577
	   !m_collection->containsPlaylistFile(fileInfo.absFilePath()))
1578
	{
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1579
	    new Playlist(m_collection, fileInfo);
1580
	    return after;
1581
	}
1582
    }
1583
1584
    if(fileInfo.isDir()) {
1585
1083 by Scott Wheeler
Move away from QDir::listEntries() to using ::readdir() since at some point
1586
	// Resorting to the POSIX API because QDir::listEntries() stats every
1587
	// file and blocks while it's doing so.
1588
1589
	DIR *dir = ::opendir(QFile::encodeName(fileInfo.filePath()));
1177 by Michael Pyne
Forward porting bugfix for crash bug #87491.
1590
1591
	if(dir) {
1592
	    struct dirent *dirEntry;
1593
1594
	    for(dirEntry = ::readdir(dir); dirEntry; dirEntry = ::readdir(dir)) {
1595
		if(strcmp(dirEntry->d_name, ".") != 0 && strcmp(dirEntry->d_name, "..") != 0)
1596
		    after = addFile(fileInfo.filePath() + QDir::separator() +
1597
				    QFile::decodeName(dirEntry->d_name), importPlaylists, after);
1598
	    }
1599
	    ::closedir(dir);
1600
	}
1601
	else
1602
	{
1603
	    kdWarning(65432) << "Unable to open directory "
1604
	                     << fileInfo.filePath()
1605
			     << ", make sure it is readable.\n";
1606
	}
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
1607
    }
1608
1609
    return after;
1610
}
1611
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
1612
////////////////////////////////////////////////////////////////////////////////
1613
// private slots
1614
////////////////////////////////////////////////////////////////////////////////
1615
1616
void Playlist::slotUpdateColumnWidths()
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1617
{
1244 by Scott Wheeler
Make sure that we don't resize the columns on events that would normally trigger
1618
    if(m_disableColumnWidthUpdates || manualResize())
620 by Scott Wheeler
More changes related to the width. Don't barf if there are no items in the
1619
	return;
1620
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1621
    // Make sure that the column weights have been initialized before trying to
1622
    // update the columns.
775 by Lukáš Tinkl
have to change this text, it creates awful nonsenses
1623
618 by Scott Wheeler
A smarter algorithm for mapping column weights to column widths. Still
1624
    QValueList<int> visibleColumns;
1625
    for(int i = 0; i < columns(); i++) {
1626
	if(isColumnVisible(i))
1627
	    visibleColumns.append(i);
1628
    }
1629
620 by Scott Wheeler
More changes related to the width. Don't barf if there are no items in the
1630
    QValueListConstIterator<int> it;
1631
1632
    if(count() == 0) {
1633
	for(it = visibleColumns.begin(); it != visibleColumns.end(); ++it)
670 by Scott Wheeler
oops, parens in the wrong place
1634
	    setColumnWidth(*it, header()->fontMetrics().width(header()->label(*it)) + 10);
620 by Scott Wheeler
More changes related to the width. Don't barf if there are no items in the
1635
1636
	return;
1637
    }
1638
1639
    if(m_columnWeights.isEmpty())
1640
	return;
1641
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1642
    // First build a list of minimum widths based on the strings in the listview
1643
    // header.  We won't let the width of the column go below this width.
1644
618 by Scott Wheeler
A smarter algorithm for mapping column weights to column widths. Still
1645
    QValueVector<int> minimumWidth(columns(), 0);
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1646
    int minimumWidthTotal = 0;
1647
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
1648
    // Also build a list of either the minimum *or* the fixed width -- whichever is
1649
    // greater.
1650
1651
    QValueVector<int> minimumFixedWidth(columns(), 0);
1652
    int minimumFixedWidthTotal = 0;
1653
618 by Scott Wheeler
A smarter algorithm for mapping column weights to column widths. Still
1654
    for(it = visibleColumns.begin(); it != visibleColumns.end(); ++it) {
705 by Enrico Ros
CVS_SILENT
1655
	int column = *it;
1656
	minimumWidth[column] = header()->fontMetrics().width(header()->label(column)) + 10;
1657
	minimumWidthTotal += minimumWidth[column];
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
1658
705 by Enrico Ros
CVS_SILENT
1659
	minimumFixedWidth[column] = QMAX(minimumWidth[column], m_columnFixedWidths[column]);
1660
	minimumFixedWidthTotal += minimumFixedWidth[column];
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1661
    }
1662
1663
    // Make sure that the width won't get any smaller than this.  We have to
1664
    // account for the scrollbar as well.  Since this method is called from the
1665
    // resize event this will set a pretty hard lower bound on the size.
1666
1667
    setMinimumWidth(minimumWidthTotal + verticalScrollBar()->width());
1668
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
1669
    // If we've got enough room for the fixed widths (larger than the minimum
1670
    // widths) then instead use those for our "minimum widths".
1671
1672
    if(minimumFixedWidthTotal < visibleWidth()) {
1673
	minimumWidth = minimumFixedWidth;
1674
	minimumWidthTotal = minimumFixedWidthTotal;
1675
    }
1676
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1677
    // We've got a list of columns "weights" based on some statistics gathered
1678
    // about the widths of the items in that column.  We need to find the total
618 by Scott Wheeler
A smarter algorithm for mapping column weights to column widths. Still
1679
    // useful weight to use as a divisor for each column's weight.
1680
1681
    double totalWeight = 0;
1682
    for(it = visibleColumns.begin(); it != visibleColumns.end(); ++it)
1683
	totalWeight += m_columnWeights[*it];
1684
1685
    // Computed a "weighted width" for each visible column.  This would be the
1686
    // width if we didn't have to handle the cases of minimum and maximum widths.
1687
1688
    QValueVector<int> weightedWidth(columns(), 0);
1689
    for(it = visibleColumns.begin(); it != visibleColumns.end(); ++it)
1690
	weightedWidth[*it] = int(double(m_columnWeights[*it]) / totalWeight * visibleWidth() + 0.5);
1691
1692
    // The "extra" width for each column.  This is the weighted width less the
1693
    // minimum width or zero if the minimum width is greater than the weighted
1694
    // width.
1695
1696
    QValueVector<int> extraWidth(columns(), 0);
1697
1698
    // This is used as an indicator if we have any columns where the weighted
1699
    // width is less than the minimum width.  If this is false then we can
1700
    // just use the weighted width with no problems, otherwise we have to
1701
    // "readjust" the widths.
1702
1703
    bool readjust = false;
1704
1705
    // If we have columns where the weighted width is less than the minimum width
1706
    // we need to steal that space from somewhere.  The amount that we need to
1707
    // steal is the "neededWidth".
1708
1709
    int neededWidth = 0;
1710
1711
    // While we're on the topic of stealing -- we have to have somewhere to steal
1712
    // from.  availableWidth is the sum of the amount of space beyond the minimum
1713
    // width that each column has been allocated -- the sum of the values of
1714
    // extraWidth[].
1715
1716
    int availableWidth = 0;
1717
1718
    // Fill in the values discussed above.
1719
1720
    for(it = visibleColumns.begin(); it != visibleColumns.end(); ++it) {
1721
	if(weightedWidth[*it] < minimumWidth[*it]) {
1722
	    readjust = true;
1723
	    extraWidth[*it] = 0;
1724
	    neededWidth += minimumWidth[*it] - weightedWidth[*it];
1725
	}
1726
	else {
1727
	    extraWidth[*it] = weightedWidth[*it] - minimumWidth[*it];
1728
	    availableWidth += extraWidth[*it];
1729
	}
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1730
    }
1731
618 by Scott Wheeler
A smarter algorithm for mapping column weights to column widths. Still
1732
    // The adjustmentRatio is the amount of the "extraWidth[]" that columns will
1733
    // actually be given.
1734
1735
    double adjustmentRatio = (double(availableWidth) - double(neededWidth)) / double(availableWidth);
1736
1737
    // This will be the sum of the total space that we actually use.  Because of
1738
    // rounding error this won't be the exact available width.
1739
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1740
    int usedWidth = 0;
618 by Scott Wheeler
A smarter algorithm for mapping column weights to column widths. Still
1741
1742
    // Now set the actual column widths.  If the weighted widths are all greater
1743
    // than the minimum widths, just use those, otherwise use the "reajusted
1744
    // weighted width".
1745
1746
    for(it = visibleColumns.begin(); it != visibleColumns.end(); ++it) {
1747
	int width;
1748
	if(readjust) {
1749
	    int adjustedExtraWidth = int(double(extraWidth[*it]) * adjustmentRatio + 0.5);
1750
	    width = minimumWidth[*it] + adjustedExtraWidth;
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1751
	}
618 by Scott Wheeler
A smarter algorithm for mapping column weights to column widths. Still
1752
	else
1753
	    width = weightedWidth[*it];
775 by Lukáš Tinkl
have to change this text, it creates awful nonsenses
1754
618 by Scott Wheeler
A smarter algorithm for mapping column weights to column widths. Still
1755
	setColumnWidth(*it, width);
1756
	usedWidth += width;
616 by Scott Wheeler
First try at a "weighted" view for the column widths in JuK. There are
1757
    }
1758
1759
    // Fill the remaining gap for a clean fit into the available space.
1760
1761
    int remainingWidth = visibleWidth() - usedWidth;
618 by Scott Wheeler
A smarter algorithm for mapping column weights to column widths. Still
1762
    setColumnWidth(visibleColumns.back(), columnWidth(visibleColumns.back()) + remainingWidth);
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
1763
1764
    m_widthsDirty = false;
1765
}
56 by Scott Wheeler
More of the architecture cleanups -- added files.
1766
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
1767
void Playlist::slotAddToUpcoming()
1768
{
1174 by Scott Wheeler
A number of modifications to the new "upcoming playlist" stuff.
1769
    m_collection->setUpcomingPlaylistEnabled(true);
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
1770
    m_upcomingPlaylist->appendItems(selectedItems());
1771
}
1772
180 by Scott Wheeler
More cleanups -- this time: finished TagEditor, CollectionList,
1773
void Playlist::slotShowRMBMenu(QListViewItem *item, const QPoint &point, int column)
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1774
{
108 by Scott Wheeler
Added genre support to inline editing. Also added "Remove files" to the
1775
    if(!item)
1776
	return;
1777
544 by Scott Wheeler
*) Create playlist RMB menus on demand.
1778
    // Create the RMB menu on demand.
1779
1780
    if(!m_rmbMenu) {
1781
1782
	// A bit of a hack to get a pointer to the action collection.
1783
	// Probably more of these actions should be ported over to using KActions.
1784
1785
	m_rmbMenu = new KPopupMenu(this);
1786
1174 by Scott Wheeler
A number of modifications to the new "upcoming playlist" stuff.
1787
	m_rmbUpcomingID = m_rmbMenu->insertItem(SmallIcon("today"),
1788
	    i18n("Add to Play Queue"), this, SLOT(slotAddToUpcoming()));
923 by Scott Wheeler
Use the global KActions here rather than new items.
1789
	m_rmbMenu->insertSeparator();
1790
1791
	if(!readOnly()) {
1792
	    action("edit_cut")->plug(m_rmbMenu);
1793
	    action("edit_copy")->plug(m_rmbMenu);
1794
	    action("edit_paste")->plug(m_rmbMenu);
1795
	    action("edit_clear")->plug(m_rmbMenu);
1796
	}
1797
	else
1798
	    action("edit_copy")->plug(m_rmbMenu);
1799
1800
	m_rmbEditID = m_rmbMenu->insertItem(
1091 by Stephan Binner
The warningContinueCancel and icon lover was here.
1801
	    i18n("Edit"), this, SLOT(slotRenameTag()));
1014 by Scott Wheeler
A little more valgrinding -- we now don't add this action to the menu if
1802
1803
	action("refresh")->plug(m_rmbMenu);
1804
	action("removeItem")->plug(m_rmbMenu);
923 by Scott Wheeler
Use the global KActions here rather than new items.
1805
1806
	m_rmbMenu->insertSeparator();
1807
1808
	action("guessTag")->plug(m_rmbMenu);
1809
	action("renameFile")->plug(m_rmbMenu);
1810
1299 by Scott Wheeler
Ok, huge patch from Nathan Toone to add a cover manager and such. There
1811
	action("coverManager")->plug(m_rmbMenu);
1812
923 by Scott Wheeler
Use the global KActions here rather than new items.
1813
	m_rmbMenu->insertSeparator();
1814
1815
	m_rmbMenu->insertItem(
925 by Scott Wheeler
These action icons seem to not exist anymore -- found new appropriate ones.
1816
	    SmallIcon("folder_new"), i18n("Create Playlist From Selected Items"), this, SLOT(slotCreateGroup()));
984 by Michael Pyne
Add "export to K3b" support to JuK.
1817
1818
	K3bExporter *exporter = new K3bExporter(this);
1819
	KAction *k3bAction = exporter->action();
1820
	if(k3bAction)
1821
	    k3bAction->plug(m_rmbMenu);
544 by Scott Wheeler
*) Create playlist RMB menus on demand.
1822
    }
1823
554 by Scott Wheeler
Updates to the (still only sort of working) history playlist.
1824
    // Ignore any columns added by subclasses.
1825
1826
    column -= columnOffset();
155 by Scott Wheeler
*) Applied Daniel's patch for hiding and showing columns
1827
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
1828
    bool showEdit =
1829
	(column == PlaylistItem::TrackColumn) ||
1830
	(column == PlaylistItem::ArtistColumn) ||
108 by Scott Wheeler
Added genre support to inline editing. Also added "Remove files" to the
1831
	(column == PlaylistItem::AlbumColumn) ||
112 by Scott Wheeler
Got inline editing mostly done.
1832
	(column == PlaylistItem::TrackNumberColumn) ||
1833
	(column == PlaylistItem::GenreColumn) ||
1834
	(column == PlaylistItem::YearColumn);
108 by Scott Wheeler
Added genre support to inline editing. Also added "Remove files" to the
1835
519 by Nadeem Hasan
Fix spacing for wheels :)
1836
    if(showEdit)
518 by Nadeem Hasan
* Use IconSets in playlist context menu.
1837
	m_rmbMenu->changeItem(m_rmbEditID,
775 by Lukáš Tinkl
have to change this text, it creates awful nonsenses
1838
		i18n("Edit '%1'").arg(columnText(column)));
518 by Nadeem Hasan
* Use IconSets in playlist context menu.
1839
1840
    m_rmbMenu->setItemVisible(m_rmbEditID, showEdit);
108 by Scott Wheeler
Added genre support to inline editing. Also added "Remove files" to the
1841
1106 by Michael Pyne
Fix bug 84616 by disabling the tag editor pane and the Edit... context-menu option when only one file is selected, and it's read-only.
1842
    // Disable edit menu if only one file is selected, and it's read-only
1843
1844
    QFileInfo fi(static_cast<PlaylistItem*>(item)->file().absFilePath());
1845
    bool enableEdit = true;
1846
1847
    if(!fi.isWritable() && selectedItems().count() == 1)
1848
	enableEdit = false;
1849
1850
    m_rmbMenu->setItemEnabled(m_rmbEditID, enableEdit);
1851
178 by Scott Wheeler
Wrote a lovely little script to prefix all member variables with m_
1852
    m_rmbMenu->popup(point);
1853
    m_currentColumn = column;
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1854
}
1855
180 by Scott Wheeler
More cleanups -- this time: finished TagEditor, CollectionList,
1856
void Playlist::slotRenameTag()
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1857
{
394 by Scott Wheeler
fix inline tag editing -- there previously was a test for a condition that
1858
    // kdDebug(65432) << "Playlist::slotRenameTag()" << endl;
1859
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1860
    // setup completions and validators
198 by Daniel Molkentin
Patch based on the work of Matt Proud to allow inline renaming of multiple files.
1861
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1862
    CollectionList *list = CollectionList::instance();
1863
1864
    KLineEdit *edit = renameLineEdit();
1865
554 by Scott Wheeler
Updates to the (still only sort of working) history playlist.
1866
    switch(m_currentColumn - columnOffset())
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1867
    {
674 by Scott Wheeler
*) It's preferable to do completion when the artist column is selected. ;-)
1868
    case PlaylistItem::ArtistColumn:
508 by Scott Wheeler
Clean up the API for "unique sets" generated by the collection list. This
1869
	edit->completionObject()->setItems(list->uniqueSet(CollectionList::Artists));
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1870
	break;
1871
    case PlaylistItem::AlbumColumn:
508 by Scott Wheeler
Clean up the API for "unique sets" generated by the collection list. This
1872
	edit->completionObject()->setItems(list->uniqueSet(CollectionList::Albums));
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1873
	break;
108 by Scott Wheeler
Added genre support to inline editing. Also added "Remove files" to the
1874
    case PlaylistItem::GenreColumn:
674 by Scott Wheeler
*) It's preferable to do completion when the artist column is selected. ;-)
1875
    {
724 by Scott Wheeler
Another 10 files sacrificed to TagLib. Yay for removing code! :-) (TagLib
1876
	QStringList genreList;
1877
	TagLib::StringList genres = TagLib::ID3v1::genreList();
1878
	for(TagLib::StringList::ConstIterator it = genres.begin(); it != genres.end(); ++it)
1879
	    genreList.append(TStringToQString((*it)));
1880
	edit->completionObject()->setItems(genreList);
108 by Scott Wheeler
Added genre support to inline editing. Also added "Remove files" to the
1881
	break;
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1882
    }
674 by Scott Wheeler
*) It's preferable to do completion when the artist column is selected. ;-)
1883
    default:
1884
	edit->completionObject()->clear();
1885
	break;
1886
    }
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
1887
394 by Scott Wheeler
fix inline tag editing -- there previously was a test for a condition that
1888
    m_editText = currentItem()->text(m_currentColumn);
1889
178 by Scott Wheeler
Wrote a lovely little script to prefix all member variables with m_
1890
    rename(currentItem(), m_currentColumn);
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1891
}
1892
1104 by Michael Pyne
Fix bug 83882 by taking advantage of Scott's updates to taglib. I could only
1893
bool Playlist::editTag(PlaylistItem *item, const QString &text, int column)
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1894
{
1222 by Michael Pyne
Implement bug 61340 (Add undo support for multi-tagging).
1895
    Tag *newTag = TagTransactionManager::duplicateTag(item->file().tag());
1896
554 by Scott Wheeler
Updates to the (still only sort of working) history playlist.
1897
    switch(column - columnOffset())
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1898
    {
1899
    case PlaylistItem::TrackColumn:
1222 by Michael Pyne
Implement bug 61340 (Add undo support for multi-tagging).
1900
	newTag->setTitle(text);
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1901
	break;
1902
    case PlaylistItem::ArtistColumn:
1222 by Michael Pyne
Implement bug 61340 (Add undo support for multi-tagging).
1903
	newTag->setArtist(text);
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1904
	break;
1905
    case PlaylistItem::AlbumColumn:
1222 by Michael Pyne
Implement bug 61340 (Add undo support for multi-tagging).
1906
	newTag->setAlbum(text);
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1907
	break;
112 by Scott Wheeler
Got inline editing mostly done.
1908
    case PlaylistItem::TrackNumberColumn:
1909
    {
1910
	bool ok;
1911
	int value = text.toInt(&ok);
1912
	if(ok)
1222 by Michael Pyne
Implement bug 61340 (Add undo support for multi-tagging).
1913
	    newTag->setTrack(value);
112 by Scott Wheeler
Got inline editing mostly done.
1914
	break;
1915
    }
108 by Scott Wheeler
Added genre support to inline editing. Also added "Remove files" to the
1916
    case PlaylistItem::GenreColumn:
1222 by Michael Pyne
Implement bug 61340 (Add undo support for multi-tagging).
1917
	newTag->setGenre(text);
108 by Scott Wheeler
Added genre support to inline editing. Also added "Remove files" to the
1918
	break;
112 by Scott Wheeler
Got inline editing mostly done.
1919
    case PlaylistItem::YearColumn:
1920
    {
1921
	bool ok;
1922
	int value = text.toInt(&ok);
1923
	if(ok)
1222 by Michael Pyne
Implement bug 61340 (Add undo support for multi-tagging).
1924
	    newTag->setYear(value);
112 by Scott Wheeler
Got inline editing mostly done.
1925
	break;
1926
    }
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1927
    }
1928
1222 by Michael Pyne
Implement bug 61340 (Add undo support for multi-tagging).
1929
    TagTransactionManager::instance()->changeTagOnItem(item, newTag);
1930
    return true;
101 by Scott Wheeler
The first parts of inline tag editing, mostly by danimo.
1931
}
1932
764 by Scott Wheeler
CVS_SILENT API nitpicks
1933
void Playlist::slotInlineEditDone(QListViewItem *, const QString &, int column)
198 by Daniel Molkentin
Patch based on the work of Matt Proud to allow inline renaming of multiple files.
1934
{
763 by Scott Wheeler
Make inline editing work again.
1935
    QString text = renameLineEdit()->text();
1134 by Michael Pyne
Fix bug 83945 by only skipping the tag editing operation from the inline editor if every tag is identical to the edit text, instead of just checking the one track that was edited.
1936
    bool changed = false;
763 by Scott Wheeler
Make inline editing work again.
1937
672 by Scott Wheeler
Make it so that editing the genre with the inline tag editor works.
1938
    PlaylistItemList l = selectedItems();
1134 by Michael Pyne
Fix bug 83945 by only skipping the tag editing operation from the inline editor if every tag is identical to the edit text, instead of just checking the one track that was edited.
1939
1940
    // See if any of the files have a tag different from the input.
1941
1942
    for(PlaylistItemList::ConstIterator it = l.begin(); it != l.end() && !changed; ++it)
1943
	if((*it)->text(column - columnOffset()) != text)
1944
	    changed = true;
1945
1946
    if(!changed ||
672 by Scott Wheeler
Make it so that editing the genre with the inline tag editor works.
1947
       (l.count() > 1 && KMessageBox::warningYesNo(
1948
	   0,
795 by Jonathan Riddell
KDE proofreads typos
1949
	   i18n("This will edit multiple files. Are you sure?"),
672 by Scott Wheeler
Make it so that editing the genre with the inline tag editor works.
1950
	   QString::null,
1951
	   KStdGuiItem::yes(),
1952
	   KStdGuiItem::no(),
1953
	   "DontWarnMultipleTags") == KMessageBox::No))
494 by Scott Wheeler
Some interactivity hacks for staying responsive while tagging a list of
1954
    {
1955
	return;
1956
    }
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
1957
1222 by Michael Pyne
Implement bug 61340 (Add undo support for multi-tagging).
1958
    for(PlaylistItemList::ConstIterator it = l.begin(); it != l.end(); ++it)
1959
	editTag(*it, text, column);
1960
1961
    TagTransactionManager::instance()->commit();
1104 by Michael Pyne
Fix bug 83882 by taking advantage of Scott's updates to taglib. I could only
1962
1071 by Michael Pyne
* Implement drag-and-drop retagging of songs while using the tree view playlist mode, fixing bug 62307.
1963
    CollectionList::instance()->dataChanged();
1964
    dataChanged();
1965
    update();
198 by Daniel Molkentin
Patch based on the work of Matt Proud to allow inline renaming of multiple files.
1966
}
1967
221 by Scott Wheeler
Make it so that the left most column always displays the playing indicator.
1968
void Playlist::slotColumnOrderChanged(int, int from, int to)
1969
{
1970
    if(from == 0 || to == 0) {
1342 by Scott Wheeler
Switch Playlist::m_playingItem to PlaylistItem::m_playingItems and introduce
1971
	updatePlaying();
221 by Scott Wheeler
Make it so that the left most column always displays the playing indicator.
1972
	m_leftColumn = header()->mapToSection(0);
1973
    }
277 by Scott Wheeler
Save and restore column order.
1974
1975
    SharedSettings::instance()->setColumnOrder(this);
221 by Scott Wheeler
Make it so that the left most column always displays the playing indicator.
1976
}
1977
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
1978
void Playlist::slotToggleColumnVisible(int column)
1979
{
1150 by Scott Wheeler
Ok, here's an altogether more sane approach to this -- just split this up
1980
    if(!isColumnVisible(column)) {
1981
	int fileNameColumn = PlaylistItem::FileNameColumn + columnOffset();
1982
	int fullPathColumn = PlaylistItem::FullPathColumn + columnOffset();
1983
1984
	if(column == fileNameColumn && isColumnVisible(fullPathColumn)) {
1985
	    hideColumn(fullPathColumn, false);
1986
	    SharedSettings::instance()->toggleColumnVisible(fullPathColumn);
1987
	}
1988
	if(column == fullPathColumn && isColumnVisible(fileNameColumn)) {
1989
	    hideColumn(fileNameColumn, false);
1990
	    SharedSettings::instance()->toggleColumnVisible(fileNameColumn);
1991
	}
1992
    }
1993
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
1994
    if(isColumnVisible(column))
1995
	hideColumn(column);
1996
    else
1997
	showColumn(column);
1998
559 by Scott Wheeler
More adjustments to make use of "columnOffset()". Now hiding columns in
1999
    SharedSettings::instance()->toggleColumnVisible(column - columnOffset());
279 by Scott Wheeler
Ported the saving of visible columns to the new Playlist::SharedSettings
2000
}
2001
1144 by Michael Pyne
Fix Create Playlist from Selected Items to actually ask the user for the
2002
void Playlist::slotCreateGroup()
2003
{
2004
    QString name = m_collection->playlistNameDialog(i18n("Create New Playlist"));
2005
2006
    if(!name.isEmpty())
2007
	new Playlist(m_collection, selectedItems(), name);
2008
}
2009
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
2010
void Playlist::slotColumnSizeChanged(int column, int, int newSize)
2011
{
2012
    m_widthsDirty = true;
2013
    m_columnFixedWidths[column] = newSize;
1241 by Scott Wheeler
Automatically switch on manual column width mode if the user tries to resize
2014
2015
    if(m_mousePressed && !action<KToggleAction>("resizeColumnsManually")->isChecked()) {
2016
	KMessageBox::information(this,
2017
				 i18n("Manual column widths have been enabled.  You can "
2018
				      "switch back to automatic column sizes in the view "
2019
				      "menu."),
2020
				 i18n("Manual Column Widths Enabled"),
2021
				 "ShowManualColumnWidthInformation");
2022
	
2023
	action<KToggleAction>("resizeColumnsManually")->setChecked(true);
2024
	slotColumnResizeModeChanged();
2025
    }
622 by Scott Wheeler
Allow the user to resize the columns. This still feels a little awkward
2026
}
2027
673 by Scott Wheeler
Save / restore the "completion mode" for the inline tag editor in JuK's
2028
void Playlist::slotInlineCompletionModeChanged(KGlobalSettings::Completion mode)
2029
{
2030
    SharedSettings::instance()->setInlineCompletionMode(mode);
2031
}
2032
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
2033
void Playlist::slotPlayCurrent()
2034
{
1170 by Michael Pyne
OK, here it is. This commit introduces a new feature to JuK, the upcoming
2035
    QListViewItemIterator it(this, QListViewItemIterator::Selected);
2036
    PlaylistItem *next = static_cast<PlaylistItem *>(it.current());
2037
    TrackSequenceManager::instance()->setNextItem(next);
1067 by Scott Wheeler
Forgot to commit this earlier...make the back popup menu work again.
2038
    action("forward")->activate();
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
2039
}
2040
180 by Scott Wheeler
More cleanups -- this time: finished TagEditor, CollectionList,
2041
////////////////////////////////////////////////////////////////////////////////
2042
// helper functions
2043
////////////////////////////////////////////////////////////////////////////////
2044
1203 by Scott Wheeler
Make Folder Playlists a real type that's restored as such. Now they automatically
2045
QDataStream &operator<<(QDataStream &s, const Playlist &p)
146 by Scott Wheeler
Reworked the playlist restoring and saving code to use a binary cache
2046
{
2047
    s << p.name();
2048
    s << p.fileName();
2049
    s << p.files();
289 by Zack Rusin
Schecking ... :) Styleguide fixes + accelerator fixes.
2050
146 by Scott Wheeler
Reworked the playlist restoring and saving code to use a binary cache
2051
    return s;
2052
}
2053
2054
QDataStream &operator>>(QDataStream &s, Playlist &p)
2055
{
978 by Scott Wheeler
Ok, big cleanups essentially implimenting the stuff that has been in the
2056
    p.read(s);
146 by Scott Wheeler
Reworked the playlist restoring and saving code to use a binary cache
2057
    return s;
2058
}
2059
1158 by Scott Wheeler
Update the status bar while loading.
2060
bool processEvents()
1036 by Scott Wheeler
Get rid of a few of the processEvent() hacks and replace them with one that's
2061
{
2062
    static QTime time = QTime::currentTime();
2063
1084 by Scott Wheeler
Process events every 0.2 seconds rather than every 0.5 seconds while scanning
2064
    if(time.elapsed() > 200) {
1036 by Scott Wheeler
Get rid of a few of the processEvent() hacks and replace them with one that's
2065
	time.restart();
2066
	kapp->processEvents();
1158 by Scott Wheeler
Update the status bar while loading.
2067
	return true;
1036 by Scott Wheeler
Get rid of a few of the processEvent() hacks and replace them with one that's
2068
    }
1158 by Scott Wheeler
Update the status bar while loading.
2069
    return false;
1036 by Scott Wheeler
Get rid of a few of the processEvent() hacks and replace them with one that's
2070
}
2071
56 by Scott Wheeler
More of the architecture cleanups -- added files.
2072
#include "playlist.moc"