playlistsplitter.cpp 9.75 KB
Newer Older
1 2
/***************************************************************************
    begin                : Fri Sep 13 2002
3
    copyright            : (C) 2002 - 2004 by Scott Wheeler
4
    email                : wheeler@kde.org
Michael Pyne's avatar
Michael Pyne committed
5 6 7

    copyright            : (C) 2009 by Michael Pyne
    email                : michael.pyne@kdemail.net
8 9 10 11 12 13 14 15 16 17 18
 ***************************************************************************/

/***************************************************************************
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 ***************************************************************************/

19 20
#include "playlistsplitter.h"

21
#include <kicon.h>
22
#include <kaction.h>
23
#include <kglobal.h>
24
#include <kactioncollection.h>
25
#include <kdebug.h>
Laurent Montel's avatar
Poirt  
Laurent Montel committed
26
#include <ktoggleaction.h>
27
#include <kconfiggroup.h>
28

29
#include <QEvent>
Laurent Montel's avatar
Laurent Montel committed
30
#include <QVBoxLayout>
31
#include <QLatin1String>
32
#include <QList>
33
#include <QStackedWidget>
34
#include <QSizePolicy>
35

36
#include "searchwidget.h"
37
#include "playlistsearch.h"
38
#include "actioncollection.h"
39 40
#include "tageditor.h"
#include "collectionlist.h"
41
#include "playermanager.h"
42
#include "nowplaying.h"
43
#include "playlistbox.h"
44

45
////////////////////////////////////////////////////////////////////////////////
46
// public methods
47 48
////////////////////////////////////////////////////////////////////////////////

49
PlaylistSplitter::PlaylistSplitter(PlayerManager *player, QWidget *parent) :
50
    QSplitter(Qt::Horizontal, parent),
51
    m_newVisible(0),
52 53 54
    m_playlistBox(0),
    m_searchWidget(0),
    m_playlistStack(0),
55
    m_editor(0),
56 57
    m_nowPlaying(0),
    m_player(player)
58
{
59
    setObjectName(QLatin1String("playlistSplitter"));
60

61
    setupActions();
62 63
    setupLayout();
    readConfig();
64 65

    m_editor->slotUpdateCollection();
66
    m_editor->setupObservers();
67
}
68

69
PlaylistSplitter::~PlaylistSplitter()
70
{
71
    saveConfig();
72

73 74 75 76 77 78
    // NowPlaying depends on the PlaylistCollection, so kill it now.
    delete m_nowPlaying;
    m_nowPlaying = 0;

    delete m_searchWidget; // Take no chances here either.

79 80 81 82
    // Since we want to ensure that the shutdown process for the PlaylistCollection
    // (a base class for PlaylistBox) has a chance to write the playlists to disk
    // before they are deleted we're explicitly deleting the PlaylistBox here.

83
    delete m_playlistBox;
84 85
}

86 87 88 89 90
PlaylistInterface *PlaylistSplitter::playlist() const
{
    return m_playlistBox;
}

91 92 93 94 95 96 97 98 99
bool PlaylistSplitter::eventFilter(QObject *, QEvent *event)
{
    if(event->type() == FocusUpEvent::id) {
        m_searchWidget->setFocus();
        return true;
    }
    return false;
}

100 101 102 103 104 105 106 107 108
////////////////////////////////////////////////////////////////////////////////
// public slots
////////////////////////////////////////////////////////////////////////////////

void PlaylistSplitter::setFocus()
{
    m_searchWidget->setFocus();
}

109 110 111 112 113
void PlaylistSplitter::slotFocusCurrentPlaylist()
{
    Playlist *playlist = m_playlistBox->visiblePlaylist();

    if(playlist) {
114
        playlist->setFocus();
Laurent Montel's avatar
Laurent Montel committed
115
        playlist->K3ListView::selectAll(false);
116

117
        // Select the top visible (and matching) item.
118

119
        PlaylistItem *item = static_cast<PlaylistItem *>(playlist->itemAt(QPoint(0, 0)));
120

121 122
        if(!item)
            return;
123

124 125
        // A little bit of a hack to make QListView repaint things properly.  Switch
        // to single selection mode, set the selection and then switch back.
126

Laurent Montel's avatar
Laurent Montel committed
127
        playlist->setSelectionMode(Q3ListView::Single);
128

129 130
        playlist->markItemSelected(item, true);
        playlist->setCurrentItem(item);
131

Laurent Montel's avatar
Laurent Montel committed
132
        playlist->setSelectionMode(Q3ListView::Extended);
133 134 135
    }
}

136
////////////////////////////////////////////////////////////////////////////////
137
// private members
138 139
////////////////////////////////////////////////////////////////////////////////

140 141 142 143 144
Playlist *PlaylistSplitter::visiblePlaylist() const
{
    return m_newVisible ? m_newVisible : m_playlistBox->visiblePlaylist();
}

145
void PlaylistSplitter::setupActions()
146
{
147
    KActionCollection* coll = ActionCollection::actions();
148
    KToggleAction *showSearch =
Pino Toscano's avatar
Pino Toscano committed
149
	 new KToggleAction(KIcon("edit-find"), i18n("Show &Search Bar"), this);
150 151
    coll->addAction("showSearch", showSearch);

Laurent Montel's avatar
Laurent Montel committed
152
    KAction *act = new KAction(KIcon("edit-clear"), i18n("Edit Track Search"), this);
153
    coll->addAction("editTrackSearch", act);
154 155
    act->setShortcut(Qt::Key_F6);
    connect(act, SIGNAL(triggered(bool)), SLOT(setFocus()));
156 157
}

158 159
void PlaylistSplitter::setupLayout()
{
160
    setOpaqueResize(false);
161

Michael Pyne's avatar
Michael Pyne committed
162 163 164 165
    // Disable the GUI until startup is complete (as indicated by PlaylistBox)

    setEnabled(false);

166 167
    // Create a splitter to go between the playlists and the editor.

168
    QSplitter *editorSplitter = new QSplitter(Qt::Vertical, this);
Laurent Montel's avatar
Laurent Montel committed
169
    editorSplitter->setObjectName( QLatin1String("editorSplitter" ));
170 171

    // Create the playlist and the editor.
172

173 174
    QWidget *top = new QWidget(editorSplitter);
    QVBoxLayout *topLayout = new QVBoxLayout(top);
Sebastian Sauer's avatar
Sebastian Sauer committed
175 176
    topLayout->setMargin(0);
    topLayout->setSpacing(0);
177

178
    m_playlistStack = new QStackedWidget(top);
Laurent Montel's avatar
Laurent Montel committed
179
    m_playlistStack->setObjectName( QLatin1String("playlistStack" ));
180
    m_playlistStack->installEventFilter(this);
181
    m_playlistStack->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
182
    m_playlistStack->hide(); // Will be shown after CollectionList filled.
183

Dirk Mueller's avatar
Dirk Mueller committed
184
    m_editor = new TagEditor(editorSplitter);
Laurent Montel's avatar
Laurent Montel committed
185
    m_editor->setObjectName( QLatin1String("TagEditor" ));
186 187 188

    // Make the editor as small as possible (or at least as small as recommended)

189 190
    editorSplitter->setStretchFactor(editorSplitter->indexOf(m_editor), 0);
    editorSplitter->setStretchFactor(editorSplitter->indexOf(top), 1);
191

192
    // Create the PlaylistBox
193

194
    m_playlistBox = new PlaylistBox(m_player, this, m_playlistStack);
Laurent Montel's avatar
Laurent Montel committed
195
    m_playlistBox->setObjectName( QLatin1String( "playlistBox" ) );
196

197 198
    connect(m_playlistBox->object(), SIGNAL(signalSelectedItemsChanged()),
            this, SLOT(slotPlaylistSelectionChanged()));
199 200
    connect(m_playlistBox, SIGNAL(signalPlaylistDestroyed(Playlist *)),
            m_editor, SLOT(slotPlaylistDestroyed(Playlist *)));
Michael Pyne's avatar
Michael Pyne committed
201
    connect(m_playlistBox, SIGNAL(startupComplete()), SLOT(slotEnable()));
202 203 204 205
    connect(m_playlistBox, SIGNAL(startFilePlayback(FileHandle)),
            m_player, SLOT(play(FileHandle)));

    m_player->setPlaylistInterface(m_playlistBox);
206

Michael Pyne's avatar
Michael Pyne committed
207 208 209
    // Let interested parties know we're ready
    connect(m_playlistBox, SIGNAL(startupComplete()), SIGNAL(guiReady()));

210
    insertWidget(0, m_playlistBox);
211

212
    m_nowPlaying = new NowPlaying(top, m_playlistBox);
213 214
    connect(m_player, SIGNAL(signalItemChanged(FileHandle)),
            m_nowPlaying, SLOT(slotUpdate(FileHandle)));
215

216
    // Create the search widget -- this must be done after the CollectionList is created.
217

218
    m_searchWidget = new SearchWidget(top);
219 220
    connect(m_searchWidget, SIGNAL(signalQueryChanged()),
            this, SLOT(slotShowSearchResults()));
221 222
    connect(m_searchWidget, SIGNAL(signalDownPressed()),
            this, SLOT(slotFocusCurrentPlaylist()));
223 224 225 226
    connect(m_searchWidget, SIGNAL(signalAdvancedSearchClicked()),
            m_playlistBox->object(), SLOT(slotCreateSearchPlaylist()));
    connect(m_searchWidget, SIGNAL(signalShown(bool)),
            m_playlistBox->object(), SLOT(slotSetSearchEnabled(bool)));
Michael Pyne's avatar
Michael Pyne committed
227 228
    connect(m_searchWidget, SIGNAL(returnPressed()),
            m_playlistBox->object(), SLOT(slotPlayFirst()));
229
    connect(ActionCollection::action<KToggleAction>("showSearch"), SIGNAL(toggled(bool)),
230
            m_searchWidget, SLOT(setEnabled(bool)));
231

232
    topLayout->addWidget(m_nowPlaying);
233
    topLayout->addWidget(m_searchWidget);
234
    topLayout->addWidget(m_playlistStack, 1);
235

236 237 238 239 240
    // Now that GUI setup is complete, add some auto-update signals.
    connect(CollectionList::instance(), SIGNAL(signalCollectionChanged()),
            m_editor, SLOT(slotUpdateCollection()));
    connect(m_playlistStack, SIGNAL(currentChanged(int)), this, SLOT(slotPlaylistChanged(int)));

241
    // Show the collection on startup.
242
    m_playlistBox->setSelected(0, true);
243 244 245 246
}

void PlaylistSplitter::readConfig()
{
247
    KConfigGroup config(KGlobal::config(), "Splitter");
248

249
    QList<int> splitterSizes = config.readEntry("PlaylistSplitterSizes",QList<int>());
250 251 252
    if(splitterSizes.isEmpty()) {
        splitterSizes.append(100);
        splitterSizes.append(640);
253
    }
254
    setSizes(splitterSizes);
255

256
    bool showSearch = config.readEntry("ShowSearch", true);
257
    ActionCollection::action<KToggleAction>("showSearch")->setChecked(showSearch);
258
    m_searchWidget->setHidden(!showSearch);
259 260
}

261
void PlaylistSplitter::saveConfig()
262
{
263 264
    KConfigGroup config(KGlobal::config(), "Splitter");
    config.writeEntry("PlaylistSplitterSizes", sizes());
265
    config.writeEntry("ShowSearch", ActionCollection::action<KToggleAction>("showSearch")->isChecked());
266 267
}

268
void PlaylistSplitter::slotShowSearchResults()
269 270 271
{
    PlaylistList playlists;
    playlists.append(visiblePlaylist());
272 273
    PlaylistSearch search = m_searchWidget->search(playlists);
    visiblePlaylist()->setSearch(search);
274 275
}

276
void PlaylistSplitter::slotPlaylistSelectionChanged()
277
{
278
    m_editor->slotSetItems(visiblePlaylist()->selectedItems());
279 280
}

281
void PlaylistSplitter::slotPlaylistChanged(int i)
282
{
283
    Playlist *p = qobject_cast<Playlist *>(m_playlistStack->widget(i));
284

285
    if(!p)
286
        return;
287 288 289 290

    m_newVisible = p;
    m_searchWidget->setSearch(p->search());
    m_newVisible = 0;
291 292
}

Michael Pyne's avatar
Michael Pyne committed
293 294 295
void PlaylistSplitter::slotEnable()
{
    setEnabled(true); // Ready to go.
296
    m_playlistStack->show();
Michael Pyne's avatar
Michael Pyne committed
297 298
}

299
#include "playlistsplitter.moc"
300 301

// vim: set et sw=4 tw=0 sta: