Undo and redo actions for the playlist. Note that undoing a sort or a shuffle doesn't work yet. Fixes issue #152

This commit is contained in:
David Sansome 2010-04-19 18:44:35 +00:00
parent 9d0541a53b
commit b2236bfd1e
24 changed files with 549 additions and 69 deletions

View File

@ -81,5 +81,7 @@
<file>schema-7.sql</file>
<file>tiny-pause.png</file>
<file>tiny-start.png</file>
<file>edit-redo.png</file>
<file>edit-undo.png</file>
</qresource>
</RCC>

BIN
data/edit-redo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
data/edit-undo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -75,6 +75,7 @@ set(CLEMENTINE-SOURCES
settingsprovider.cpp
libraryplaylistitem.cpp
scopedtransaction.cpp
playlistundocommands.cpp
)
# Header files that have Q_OBJECT in

View File

@ -310,11 +310,22 @@ MainWindow::MainWindow(QNetworkAccessManager* network, Engine::Type engine, QWid
connect(library_config_dialog_.get(), SIGNAL(accepted()), ui_.library_view, SLOT(ReloadSettings()));
// Playlist menu
QAction* playlist_undo = playlist_->undo_stack()->createUndoAction(this);
QAction* playlist_redo = playlist_->undo_stack()->createRedoAction(this);
playlist_undo->setIcon(QIcon(":edit-undo.png"));
playlist_undo->setShortcut(QKeySequence::Undo);
playlist_redo->setIcon(QIcon(":edit-redo.png"));
playlist_redo->setShortcut(QKeySequence::Redo);
addAction(playlist_undo); // These seem to be required to get the keyboard
addAction(playlist_redo); // shortcuts to work
playlist_play_pause_ = playlist_menu_->addAction(tr("Play"), this, SLOT(PlaylistPlay()));
playlist_menu_->addAction(ui_.action_stop);
playlist_stop_after_ = playlist_menu_->addAction(QIcon(":media-playback-stop.png"), tr("Stop after this track"), this, SLOT(PlaylistStopAfter()));
playlist_menu_->addSeparator();
playlist_menu_->addAction(ui_.action_remove_from_playlist);
playlist_menu_->addAction(playlist_undo);
playlist_menu_->addAction(playlist_redo);
playlist_menu_->addSeparator();
playlist_menu_->addAction(ui_.action_edit_track);
playlist_menu_->addAction(ui_.action_edit_value);

View File

@ -23,6 +23,7 @@
#include "savedradio.h"
#include "librarybackend.h"
#include "libraryplaylistitem.h"
#include "playlistundocommands.h"
#include <QtDebug>
#include <QMimeData>
@ -30,6 +31,7 @@
#include <QSettings>
#include <QFileInfo>
#include <QDirIterator>
#include <QUndoStack>
#include <boost/bind.hpp>
#include <algorithm>
@ -50,7 +52,8 @@ Playlist::Playlist(QObject *parent, SettingsProvider* settings)
scrobble_point_(-1),
has_scrobbled_(false),
playlist_sequence_(NULL),
ignore_sorting_(false)
ignore_sorting_(false),
undo_stack_(new QUndoStack(this))
{
settings_->set_group(kSettingsGroup);
@ -352,48 +355,7 @@ bool Playlist::dropMimeData(const QMimeData* data, Qt::DropAction action, int ro
stream >> source_rows;
qStableSort(source_rows); // Make sure we take them in order
layoutAboutToBeChanged();
PlaylistItemList moved_items;
// Take the items out of the list first, keeping track of whether the
// insertion point changes
int offset = 0;
foreach (int source_row, source_rows) {
moved_items << items_.takeAt(source_row-offset);
if (row != -1 && row >= source_row)
row --;
offset++;
}
// Put the items back in
const int start = row == -1 ? items_.count() : row;
for (int i=start ; i<start+moved_items.count() ; ++i) {
items_.insert(i, moved_items[i - start]);
}
// Update persistent indexes
foreach (const QModelIndex& pidx, persistentIndexList()) {
const int dest_offset = source_rows.indexOf(pidx.row());
if (dest_offset != -1) {
// This index was moved
changePersistentIndex(pidx, index(start + dest_offset, pidx.column(), QModelIndex()));
} else {
int d = 0;
foreach (int source_row, source_rows) {
if (pidx.row() > source_row)
d --;
}
if (pidx.row() + d >= start)
d += source_rows.count();
changePersistentIndex(pidx, index(pidx.row() + d, pidx.column(), QModelIndex()));
}
}
current_virtual_index_ = virtual_items_.indexOf(current_index());
layoutChanged();
Save();
undo_stack_->push(new PlaylistUndoCommands::MoveItems(this, source_rows, row));
} else if (data->hasUrls()) {
// URL list dragged from the file list or some other app
InsertPaths(data->urls(), row);
@ -402,7 +364,95 @@ bool Playlist::dropMimeData(const QMimeData* data, Qt::DropAction action, int ro
return true;
}
QModelIndex Playlist::InsertPaths(QList<QUrl> urls, int after) {
void Playlist::MoveItemsWithoutUndo(const QList<int> &source_rows, int pos) {
layoutAboutToBeChanged();
PlaylistItemList moved_items;
// Take the items out of the list first, keeping track of whether the
// insertion point changes
int offset = 0;
foreach (int source_row, source_rows) {
moved_items << items_.takeAt(source_row-offset);
if (pos != -1 && pos >= source_row)
pos --;
offset++;
}
// Put the items back in
const int start = pos == -1 ? items_.count() : pos;
for (int i=start ; i<start+moved_items.count() ; ++i) {
items_.insert(i, moved_items[i - start]);
}
// Update persistent indexes
foreach (const QModelIndex& pidx, persistentIndexList()) {
const int dest_offset = source_rows.indexOf(pidx.row());
if (dest_offset != -1) {
// This index was moved
changePersistentIndex(pidx, index(start + dest_offset, pidx.column(), QModelIndex()));
} else {
int d = 0;
foreach (int source_row, source_rows) {
if (pidx.row() > source_row)
d --;
}
if (pidx.row() + d >= start)
d += source_rows.count();
changePersistentIndex(pidx, index(pidx.row() + d, pidx.column(), QModelIndex()));
}
}
current_virtual_index_ = virtual_items_.indexOf(current_index());
layoutChanged();
Save();
}
void Playlist::MoveItemsWithoutUndo(int start, const QList<int>& dest_rows) {
layoutAboutToBeChanged();
PlaylistItemList moved_items;
if (start == -1)
start = items_.count() - dest_rows.count();
// Take the items out of the list first, keeping track of whether the
// insertion point changes
for (int i=start ; i<start + dest_rows.count() ; ++i)
moved_items << items_.takeAt(start);
// Put the items back in
int offset = 0;
foreach (int dest_row, dest_rows) {
items_.insert(dest_row, moved_items[offset]);
offset ++;
}
// Update persistent indexes
foreach (const QModelIndex& pidx, persistentIndexList()) {
if (pidx.row() >= start && pidx.row() < start + dest_rows.count()) {
// This index was moved
const int i = pidx.row() - start;
changePersistentIndex(pidx, index(dest_rows[i], pidx.column(), QModelIndex()));
} else {
int d = 0;
if (pidx.row() >= start + dest_rows.count())
d -= dest_rows.count();
foreach (int dest_row, dest_rows) {
if (pidx.row() + d > dest_row)
d ++;
}
changePersistentIndex(pidx, index(pidx.row() + d, pidx.column(), QModelIndex()));
}
}
current_virtual_index_ = virtual_items_.indexOf(current_index());
layoutChanged();
Save();
}
QModelIndex Playlist::InsertPaths(QList<QUrl> urls, int pos) {
SongList songs;
for (int i=0 ; i<urls.count() ; ++i) {
QUrl url(urls[i]);
@ -438,14 +488,25 @@ QModelIndex Playlist::InsertPaths(QList<QUrl> urls, int after) {
}
}
return InsertSongs(songs, after);
return InsertSongs(songs, pos);
}
QModelIndex Playlist::InsertItems(const PlaylistItemList& items, int after) {
QModelIndex Playlist::InsertItems(const PlaylistItemList& items, int pos) {
if (items.isEmpty())
return QModelIndex();
const int start = after == -1 ? items_.count() : after;
const int start = pos == -1 ? items_.count() : pos;
undo_stack_->push(new PlaylistUndoCommands::InsertItems(this, items, pos));
return index(start, 0);
}
QModelIndex Playlist::InsertItemsWithoutUndo(const PlaylistItemList& items,
int pos) {
if (items.isEmpty())
return QModelIndex();
const int start = pos == -1 ? items_.count() : pos;
const int end = start + items.count() - 1;
beginInsertRows(QModelIndex(), start, end);
@ -461,23 +522,23 @@ QModelIndex Playlist::InsertItems(const PlaylistItemList& items, int after) {
return index(start, 0);
}
QModelIndex Playlist::InsertLibraryItems(const SongList& songs, int after) {
QModelIndex Playlist::InsertLibraryItems(const SongList& songs, int pos) {
PlaylistItemList items;
foreach (const Song& song, songs) {
items << shared_ptr<PlaylistItem>(new LibraryPlaylistItem(song));
}
return InsertItems(items, after);
return InsertItems(items, pos);
}
QModelIndex Playlist::InsertSongs(const SongList& songs, int after) {
QModelIndex Playlist::InsertSongs(const SongList& songs, int pos) {
PlaylistItemList items;
foreach (const Song& song, songs) {
items << shared_ptr<PlaylistItem>(new SongPlaylistItem(song));
}
return InsertItems(items, after);
return InsertItems(items, pos);
}
QModelIndex Playlist::InsertRadioStations(const QList<RadioItem*>& items, int after) {
QModelIndex Playlist::InsertRadioStations(const QList<RadioItem*>& items, int pos) {
PlaylistItemList playlist_items;
foreach (RadioItem* item, items) {
if (!item->playable)
@ -486,16 +547,16 @@ QModelIndex Playlist::InsertRadioStations(const QList<RadioItem*>& items, int af
playlist_items << shared_ptr<PlaylistItem>(
new RadioPlaylistItem(item->service, item->Url(), item->Title(), item->Artist()));
}
return InsertItems(playlist_items, after);
return InsertItems(playlist_items, pos);
}
QModelIndex Playlist::InsertStreamUrls(const QList<QUrl>& urls, int after) {
QModelIndex Playlist::InsertStreamUrls(const QList<QUrl>& urls, int pos) {
PlaylistItemList playlist_items;
foreach (const QUrl& url, urls) {
playlist_items << shared_ptr<PlaylistItem>(new RadioPlaylistItem(
RadioModel::ServiceByName(SavedRadio::kServiceName), url.toString(), url.toString(), QString()));
}
return InsertItems(playlist_items, after);
return InsertItems(playlist_items, pos);
}
QMimeData* Playlist::mimeData(const QModelIndexList& indexes) const {
@ -613,6 +674,9 @@ void Playlist::sort(int column, Qt::SortOrder order) {
layoutChanged();
// TODO
undo_stack_->clear();
Save();
}
@ -676,11 +740,21 @@ bool Playlist::removeRows(int row, int count, const QModelIndex& parent) {
if (row < 0 || row >= items_.size() || row + count > items_.size()) {
return false;
}
beginRemoveRows(parent, row, row+count-1);
undo_stack_->push(new PlaylistUndoCommands::RemoveItems(this, row, count));
return true;
}
PlaylistItemList Playlist::RemoveItemsWithoutUndo(int row, int count) {
if (row < 0 || row >= items_.size() || row + count > items_.size()) {
return PlaylistItemList();
}
beginRemoveRows(QModelIndex(), row, row+count-1);
// Remove items
PlaylistItemList ret;
for (int i=0 ; i<count ; ++i)
items_.removeAt(row);
ret << items_.takeAt(row);
endRemoveRows();
@ -701,7 +775,7 @@ bool Playlist::removeRows(int row, int count, const QModelIndex& parent) {
current_virtual_index_ = virtual_items_.indexOf(current_index());
Save();
return true;
return ret;
}
void Playlist::StopAfter(int row) {
@ -787,11 +861,7 @@ void Playlist::UpdateScrobblePoint() {
}
void Playlist::Clear() {
items_.clear();
virtual_items_.clear();
reset();
current_virtual_index_ = -1;
undo_stack_->push(new PlaylistUndoCommands::RemoveItems(this, 0, items_.count()));
Save();
}
@ -822,6 +892,9 @@ void Playlist::Shuffle() {
layoutChanged();
// TODO
undo_stack_->clear();
Save();
}

View File

@ -31,9 +31,21 @@
class RadioService;
class LibraryBackendInterface;
class QUndoStack;
namespace PlaylistUndoCommands {
class InsertItems;
class RemoveItems;
class MoveItems;
}
class Playlist : public QAbstractListModel {
Q_OBJECT
friend class PlaylistUndoCommands::InsertItems;
friend class PlaylistUndoCommands::RemoveItems;
friend class PlaylistUndoCommands::MoveItems;
public:
Playlist(QObject* parent = 0, SettingsProvider* settings = NULL);
~Playlist();
@ -100,18 +112,20 @@ class Playlist : public QAbstractListModel {
void set_sequence(PlaylistSequence* v);
PlaylistSequence* sequence() const { return playlist_sequence_; }
QUndoStack* undo_stack() const { return undo_stack_; }
// Scrobbling
int scrobble_point() const { return scrobble_point_; }
bool has_scrobbled() const { return has_scrobbled_; }
void set_scrobbled(bool v) { has_scrobbled_ = v; }
// Changing the playlist
QModelIndex InsertItems(const PlaylistItemList& items, int after = -1);
QModelIndex InsertLibraryItems(const SongList& items, int after = -1);
QModelIndex InsertSongs(const SongList& items, int after = -1);
QModelIndex InsertRadioStations(const QList<RadioItem*>& items, int after = -1);
QModelIndex InsertStreamUrls(const QList<QUrl>& urls, int after = -1);
QModelIndex InsertPaths(QList<QUrl> urls, int after = -1);
QModelIndex InsertItems(const PlaylistItemList& items, int pos = -1);
QModelIndex InsertLibraryItems(const SongList& items, int pos = -1);
QModelIndex InsertSongs(const SongList& items, int pos = -1);
QModelIndex InsertRadioStations(const QList<RadioItem*>& items, int pos = -1);
QModelIndex InsertStreamUrls(const QList<QUrl>& urls, int pos = -1);
QModelIndex InsertPaths(QList<QUrl> urls, int pos = -1);
void StopAfter(int row);
void ReloadItems(const QList<int>& rows);
@ -159,6 +173,13 @@ class Playlist : public QAbstractListModel {
void ReshuffleIndices();
int NextVirtualIndex(int i) const;
// Modify the playlist without changing the undo stack. These are used by
// our friends in PlaylistUndoCommands
QModelIndex InsertItemsWithoutUndo(const PlaylistItemList& items, int pos);
PlaylistItemList RemoveItemsWithoutUndo(int pos, int count);
void MoveItemsWithoutUndo(const QList<int>& source_rows, int pos);
void MoveItemsWithoutUndo(int start, const QList<int>& dest_rows);
private:
boost::scoped_ptr<SettingsProvider> settings_;
@ -183,6 +204,8 @@ class Playlist : public QAbstractListModel {
// Hack to stop QTreeView::setModel sorting the playlist
bool ignore_sorting_;
QUndoStack* undo_stack_;
};
#endif // PLAYLIST_H

View File

@ -0,0 +1,81 @@
/* This file is part of Clementine.
Clementine 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 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "playlistundocommands.h"
#include "playlist.h"
namespace PlaylistUndoCommands {
Base::Base(Playlist *playlist)
: QUndoCommand(0),
playlist_(playlist)
{
}
InsertItems::InsertItems(Playlist *playlist, const PlaylistItemList &items, int pos)
: Base(playlist),
items_(items),
pos_(pos)
{
setText(tr("add %n songs", "", items_.count()));
}
void InsertItems::redo() {
playlist_->InsertItemsWithoutUndo(items_, pos_);
}
void InsertItems::undo() {
const int start = pos_ == -1 ?
playlist_->rowCount() - items_.count() : pos_;
playlist_->RemoveItemsWithoutUndo(start, items_.count());
}
RemoveItems::RemoveItems(Playlist *playlist, int pos, int count)
: Base(playlist),
pos_(pos),
count_(count)
{
setText(tr("remove %n songs", "", count_));
}
void RemoveItems::redo() {
items_ = playlist_->RemoveItemsWithoutUndo(pos_, count_);
}
void RemoveItems::undo() {
playlist_->InsertItemsWithoutUndo(items_, pos_);
}
MoveItems::MoveItems(Playlist *playlist, const QList<int> &source_rows, int pos)
: Base(playlist),
source_rows_(source_rows),
pos_(pos)
{
setText(tr("move songs", "", source_rows.count()));
}
void MoveItems::redo() {
playlist_->MoveItemsWithoutUndo(source_rows_, pos_);
}
void MoveItems::undo() {
playlist_->MoveItemsWithoutUndo(pos_, source_rows_);
}
} // namespace

View File

@ -0,0 +1,76 @@
/* This file is part of Clementine.
Clementine 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 3 of the License, or
(at your option) any later version.
Clementine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Clementine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef PLAYLISTUNDOCOMMANDS_H
#define PLAYLISTUNDOCOMMANDS_H
#include <QUndoCommand>
#include <QCoreApplication>
#include "playlistitem.h"
class Playlist;
namespace PlaylistUndoCommands {
class Base : public QUndoCommand {
Q_DECLARE_TR_FUNCTIONS(PlaylistUndoCommands);
public:
Base(Playlist* playlist);
protected:
Playlist* playlist_;
};
class InsertItems : public Base {
public:
InsertItems(Playlist* playlist, const PlaylistItemList& items, int pos);
void undo();
void redo();
private:
PlaylistItemList items_;
int pos_;
};
class RemoveItems : public Base {
public:
RemoveItems(Playlist* playlist, int pos, int count);
void undo();
void redo();
private:
int pos_;
int count_;
PlaylistItemList items_;
};
class MoveItems : public Base {
public:
MoveItems(Playlist* playlist, const QList<int>& source_rows, int pos);
void undo();
void redo();
private:
QList<int> source_rows_;
int pos_;
};
} //namespace
#endif // PLAYLISTUNDOCOMMANDS_H

View File

@ -564,6 +564,17 @@ msgstr "Clementine"
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, fuzzy, c-format
msgid "remove %n songs"
msgstr "Další skladba"
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr "Clementine"
@ -985,6 +996,10 @@ msgstr ""
msgid "Enable equalizer"
msgstr ""
#, fuzzy
#~ msgid "insert %n tracks"
#~ msgstr "Další skladba"
#~ msgid "%1's Neighborhood"
#~ msgstr "Sousedství uživatele %1"

View File

@ -568,6 +568,17 @@ msgstr "Clementine"
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, fuzzy, c-format
msgid "remove %n songs"
msgstr "%n Stücke bearbeiten"
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr "Clementine"
@ -992,5 +1003,9 @@ msgstr ""
msgid "Enable equalizer"
msgstr ""
#, fuzzy
#~ msgid "insert %n tracks"
#~ msgstr "%n Stücke bearbeiten"
#~ msgid "%1's Library"
#~ msgstr "%1s Musiksammlung"

View File

@ -566,6 +566,17 @@ msgstr "Clementine"
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, fuzzy, c-format
msgid "remove %n songs"
msgstr "Τροποποίηση %n κομματιών"
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr "Clementine"
@ -989,6 +1000,10 @@ msgstr "Προκαθορισμένα:"
msgid "Enable equalizer"
msgstr "Ενεργοποίηση του ισοσταθμιστή"
#, fuzzy
#~ msgid "insert %n tracks"
#~ msgstr "Τροποποίηση %n κομματιών"
#~ msgid "%1's Neighborhood"
#~ msgstr "%1's Συνοικιακά"

View File

@ -550,6 +550,17 @@ msgstr "Select engine"
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr "Unknown audio engine \"%1\". Choices are:"
#, c-format
msgid "add %n songs"
msgstr ""
#, fuzzy, c-format
msgid "remove %n songs"
msgstr "Editing %n tracks"
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr "Clementine"
@ -969,3 +980,7 @@ msgstr "Preset:"
msgid "Enable equalizer"
msgstr "Enable equalizer"
#, fuzzy
#~ msgid "insert %n tracks"
#~ msgstr "Editing %n tracks"

View File

@ -566,6 +566,17 @@ msgstr "Clementine"
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, fuzzy, c-format
msgid "remove %n songs"
msgstr "Editando %n pistas"
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr "Clementine"
@ -993,6 +1004,10 @@ msgstr "Preconfiguración:"
msgid "Enable equalizer"
msgstr "Habilitar el ecualizador"
#, fuzzy
#~ msgid "insert %n tracks"
#~ msgstr "Editando %n pistas"
#~ msgid "%1's Neighborhood"
#~ msgstr "Vecinos de %1"

View File

@ -567,6 +567,17 @@ msgstr "Clementine"
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, fuzzy, c-format
msgid "remove %n songs"
msgstr "Editer %n pistes"
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr "Clementine"
@ -993,6 +1004,10 @@ msgstr ""
msgid "Enable equalizer"
msgstr "Activer l'égaliseur"
#, fuzzy
#~ msgid "insert %n tracks"
#~ msgstr "Editer %n pistes"
#~ msgid "%1's Neighborhood"
#~ msgstr "Voisinnage de %1"

View File

@ -571,6 +571,17 @@ msgstr "Clementine"
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, fuzzy, c-format
msgid "remove %n songs"
msgstr "Endrer %n spor"
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr "Clementine"
@ -993,6 +1004,10 @@ msgstr "Forhåndsinnstillinger:"
msgid "Enable equalizer"
msgstr "Slå på equalizer"
#, fuzzy
#~ msgid "insert %n tracks"
#~ msgstr "Endrer %n spor"
#~ msgid "%1's Neighborhood"
#~ msgstr "%1s nabolag"

View File

@ -563,6 +563,17 @@ msgstr ""
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, fuzzy, c-format
msgid "remove %n songs"
msgstr "Następny utwór"
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr ""
@ -982,6 +993,10 @@ msgstr ""
msgid "Enable equalizer"
msgstr ""
#, fuzzy
#~ msgid "insert %n tracks"
#~ msgstr "Następny utwór"
#~ msgid "%1's Neighborhood"
#~ msgstr "%1 sąsiada"

View File

@ -566,6 +566,17 @@ msgstr "Clementine"
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, fuzzy, c-format
msgid "remove %n songs"
msgstr "Editando %n faixas"
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr "Clementine"
@ -988,6 +999,10 @@ msgstr "Predefinição:"
msgid "Enable equalizer"
msgstr "Activar o equalizador"
#, fuzzy
#~ msgid "insert %n tracks"
#~ msgstr "Editando %n faixas"
#~ msgid "%1's Neighborhood"
#~ msgstr "Vizinhos da %1's"

View File

@ -558,6 +558,17 @@ msgstr ""
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, c-format
msgid "remove %n songs"
msgstr ""
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr ""

View File

@ -564,6 +564,17 @@ msgstr "Clementine"
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, fuzzy, c-format
msgid "remove %n songs"
msgstr "Редактирую %n треков"
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr "Clementine"
@ -986,6 +997,10 @@ msgstr "Настройка:"
msgid "Enable equalizer"
msgstr "Включить эквалайзер"
#, fuzzy
#~ msgid "insert %n tracks"
#~ msgstr "Редактирую %n треков"
#~ msgid "%1's Neighborhood"
#~ msgstr "Соседи %1"

View File

@ -564,6 +564,17 @@ msgstr ""
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, fuzzy, c-format
msgid "remove %n songs"
msgstr "Nesledujca skladba"
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr ""
@ -985,6 +996,10 @@ msgstr ""
msgid "Enable equalizer"
msgstr ""
#, fuzzy
#~ msgid "insert %n tracks"
#~ msgstr "Nesledujca skladba"
#~ msgid "%1's Neighborhood"
#~ msgstr "%1 susedia"

View File

@ -562,6 +562,17 @@ msgstr "Clementine"
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, fuzzy, c-format
msgid "remove %n songs"
msgstr "Redigerar %n spår"
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr "Clementine"
@ -985,3 +996,7 @@ msgstr "Förval:"
msgid "Enable equalizer"
msgstr "Aktivera equalizer"
#, fuzzy
#~ msgid "insert %n tracks"
#~ msgstr "Redigerar %n spår"

View File

@ -558,6 +558,17 @@ msgstr ""
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, c-format
msgid "remove %n songs"
msgstr ""
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr ""

View File

@ -549,6 +549,17 @@ msgstr ""
msgid "Unknown audio engine \"%1\". Choices are:"
msgstr ""
#, c-format
msgid "add %n songs"
msgstr ""
#, c-format
msgid "remove %n songs"
msgstr ""
msgid "move songs"
msgstr ""
msgid "Clementine"
msgstr ""