...
 
Commits (337)
include:
- https://invent.kde.org/sysadmin/ci-tooling/raw/master/invent/ci-before.yml
- https://invent.kde.org/sysadmin/ci-tooling/raw/master/invent/ci-applications-linux.yml
- https://invent.kde.org/sysadmin/ci-tooling/raw/master/invent/ci-applications-freebsd.yml
- https://invent.kde.org/sysadmin/ci-tooling/raw/master/invent/binary-flatpak.yml
variables:
BUNDLE: org.kde.juk.flatpak
flatpak:
extends: .flatpak
variables:
MANIFEST_URL: https://cgit.kde.org/flatpak-kde-applications.git/plain/org.kde.juk.json
MANIFEST_PATH: org.kde.juk.json
APP_ID: org.kde.juk
FLATPAK_MODULE: juk
CMAKE_ARGS: -DENABLE_TESTING=OFF
project(juk)
set( CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake )
find_package( KDE4 REQUIRED )
include( KDE4Defaults )
include( MacroLibrary )
include( CheckIncludeFileCXX )
cmake_minimum_required(VERSION 3.1 FATAL_ERROR)
# KDE Application Version, managed by KDE release team automatically
# https://community.kde.org/Guidelines_and_HOWTOs/Application_Versioning
set (KDE_APPLICATIONS_VERSION_MAJOR "20")
set (KDE_APPLICATIONS_VERSION_MINOR "03")
set (KDE_APPLICATIONS_VERSION_MICRO "70")
set (KDE_APPLICATIONS_VERSION "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATIONS_VERSION_MINOR}.${KDE_APPLICATIONS_VERSION_MICRO}")
project(juk VERSION ${KDE_APPLICATIONS_VERSION})
set(QT_MIN_VERSION "5.6.0")
set(KF5_MIN_VERSION "5.35.0")
find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
include(CMakePushCheckState)
include(CheckIncludeFileCXX)
include(KDEInstallDirs)
include(KDECompilerSettings NO_POLICY_SCOPE)
include(KDECMakeSettings NO_POLICY_SCOPE)
include(FeatureSummary)
include(ECMInstallIcons)
include(ECMAddAppIcon)
include(ECMQtDeclareLoggingCategory)
find_package(Qt5 ${QT_MIN_VERSION} REQUIRED COMPONENTS Concurrent Gui Svg Network Test Widgets)
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
CoreAddons
Completion
Config
Crash
GlobalAccel
I18n
IconThemes
DBusAddons
DocTools
KIO
JobWidgets
Notifications
TextWidgets
XmlGui
Wallet
WidgetsAddons
WindowSystem
)
find_package(Phonon4Qt5 4.6.60 REQUIRED NO_MODULE)
find_package( Taglib 1.6 )
find_package(Taglib 1.6 REQUIRED)
include_directories( ${KDE4_INCLUDES} ${QT_INCLUDES} )
include_directories(${CMAKE_BINARY_DIR} ${PHONON_INCLUDES})
add_subdirectory( doc )
add_subdirectory( tests )
add_subdirectory( pics )
macro_optional_find_package(TunePimp)
macro_log_feature(TUNEPIMP_FOUND "TunePimp" "A library for developing MusicBrainz enabled tagging applications" "http://www.musicbrainz.org/products/tunepimp" FALSE "" "Provides MusicBrainz tagging in Juk.")
if(TUNEPIMP_FOUND)
set(HAVE_TUNEPIMP 1)
if(TUNEPIMP_FOUND_VERSION_4)
set(HAVE_TUNEPIMP 4)
endif(TUNEPIMP_FOUND_VERSION_4)
if(TUNEPIMP_FOUND_VERSION_5)
set(HAVE_TUNEPIMP 5)
endif(TUNEPIMP_FOUND_VERSION_5)
else(TUNEPIMP_FOUND)
set(HAVE_TUNEPIMP 0)
endif(TUNEPIMP_FOUND)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${KDE4_ENABLE_EXCEPTIONS}")
#set_package_properties(FEATURE PROPERTIES DESCRIPTION "A library for developing MusicBrainz enabled tagging applications" URL "http://www.musicbrainz.org/products/tunepimp" TYPE OPTIONAL PURPOSE "Provides MusicBrainz tagging in Juk.")
# TODO: tunepimp is fully unsupported, replace this when tunepimp is replaced
# with whatever is actually current this decade.
set(HAVE_TUNEPIMP 0)
########### next target ###############
include_directories( ${TAGLIB_INCLUDES} )
add_definitions(-DQT3_SUPPORT -DQT3_SUPPORT_WARNINGS -DQT_STL)
include_directories( SYSTEM ${TAGLIB_INCLUDES} )
add_definitions(-DQT_STL -DQT_NO_URL_CAST_FROM_STRING)
# Look for Ogg Opus support in taglib (not released yet)
macro_push_required_vars()
cmake_push_check_state()
set(CMAKE_REQUIRED_INCLUDES ${CMAKE_REQUIRED_INCLUDES} ${TAGLIB_INCLUDES})
check_include_file_cxx(opusfile.h TAGLIB_HAS_OPUSFILE)
macro_pop_required_vars()
cmake_pop_check_state()
configure_file (config-juk.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-juk.h )
set(tunepimp_SRCS)
if(TUNEPIMP_FOUND)
set(tunepimp_SRCS trackpickerdialog.cpp)
include_directories( ${TUNEPIMP_INCLUDE_DIR} )
endif(TUNEPIMP_FOUND)
set(juk_SRCS ${tunepimp_SRCS}
set(juk_SRCS
advancedsearchdialog.cpp
slider.cpp
svghandler.cpp
......@@ -65,6 +91,7 @@ set(juk_SRCS ${tunepimp_SRCS}
dbuscollectionproxy.cpp
deletedialog.cpp
directorylist.cpp
directoryloader.cpp
dynamicplaylist.cpp
exampleoptions.cpp
folderplaylist.cpp
......@@ -75,7 +102,7 @@ set(juk_SRCS ${tunepimp_SRCS}
webimagefetcher.cpp
historyplaylist.cpp
juk.cpp
k3bexporter.cpp
juktag.cpp
keydialog.cpp
lyricswidget.cpp
main.cpp
......@@ -83,28 +110,24 @@ set(juk_SRCS ${tunepimp_SRCS}
mpris2/mediaplayer2.cpp
mpris2/mediaplayer2player.cpp
mpris2/mpris2.cpp
musicbrainzquery.cpp
nowplaying.cpp
playermanager.cpp
playlist.cpp
playlistbox.cpp
playlistcollection.cpp
playlistexporter.cpp
playlistinterface.cpp
playlistitem.cpp
playlistsearch.cpp
playlistsharedsettings.cpp
playlistsplitter.cpp
scrobbler.cpp
scrobbleconfigdlg.cpp
searchplaylist.cpp
searchwidget.cpp
slideraction.cpp
sortedstringlist.cpp
splashscreen.cpp
statuslabel.cpp
stringshare.cpp
systemtray.cpp
tag.cpp
tageditor.cpp
tagguesser.cpp
tagguesserconfigdlg.cpp
......@@ -114,39 +137,71 @@ set(juk_SRCS ${tunepimp_SRCS}
tracksequencemanager.cpp
treeviewitemplaylist.cpp
upcomingplaylist.cpp
ktrm.cpp
viewmode.cpp )
qt4_add_dbus_adaptor( juk_SRCS org.kde.juk.collection.xml
ecm_qt_declare_logging_category(juk_SRCS HEADER juk_debug.h
IDENTIFIER JUK_LOG CATEGORY_NAME org.kde.juk)
qt5_add_dbus_adaptor( juk_SRCS org.kde.juk.collection.xml
dbuscollectionproxy.h DBusCollectionProxy )
qt4_add_dbus_adaptor( juk_SRCS org.kde.juk.player.xml playermanager.h PlayerManager)
qt4_add_dbus_adaptor( juk_SRCS org.kde.juk.search.xml searchwidget.h SearchWidget)
kde4_add_ui_files(juk_SRCS
filerenamerbase.ui
filerenameroptionsbase.ui
directorylistbase.ui
trackpickerdialogbase.ui
tagguesserconfigdlgwidget.ui
exampleoptionsbase.ui
coverdialogbase.ui
deletedialogbase.ui
tageditor.ui
qt5_add_dbus_adaptor( juk_SRCS org.kde.juk.player.xml playermanager.h PlayerManager)
qt5_add_dbus_adaptor( juk_SRCS org.kde.juk.search.xml searchwidget.h SearchWidget)
ki18n_wrap_ui(juk_SRCS
filerenamerbase.ui
filerenameroptionsbase.ui
directorylistbase.ui
tagguesserconfigdlgwidget.ui
exampleoptionsbase.ui
coverdialogbase.ui
deletedialogbase.ui
tageditor.ui
)
kde4_add_app_icon(juk_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/hi*-app-juk.png")
kde4_add_executable(juk ${juk_SRCS})
file(GLOB ICONS_SRCS "${CMAKE_CURRENT_SOURCE_DIR}/*-apps-juk.png")
ecm_add_app_icon(juk_SRCS ICONS ${ICONS_SRCS})
add_executable(juk ${juk_SRCS})
kde_target_enable_exceptions(juk PRIVATE)
target_compile_definitions(juk PRIVATE QT_USE_QSTRINGBUILDER)
if(NOT MSVC AND NOT ( WIN32 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" ) )
set( LIBMATH m )
endif(NOT MSVC AND NOT ( WIN32 AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel" ) )
endif()
target_link_libraries(juk ${LIBMATH}
Qt5::Gui
Qt5::Svg
Qt5::Widgets
Qt5::Network
KF5::ConfigCore
KF5::CoreAddons
KF5::Completion
KF5::Crash
KF5::DBusAddons
KF5::GlobalAccel
KF5::KIOCore
KF5::KIOWidgets
KF5::KIOFileWidgets
KF5::JobWidgets
KF5::Notifications
KF5::I18n
KF5::IconThemes
KF5::TextWidgets
KF5::XmlGui
KF5::WindowSystem
KF5::WidgetsAddons
KF5::Wallet
Phonon::phonon4qt5
${TAGLIB_LIBRARIES}
)
target_link_libraries(juk ${LIBMATH} ${KDE4_KHTML_LIBS} ${TAGLIB_LIBRARIES} ${KDE4_KDE3SUPPORT_LIBS} ${KDE4_PHONON_LIBS})
if(TUNEPIMP_FOUND)
target_link_libraries(juk ${TUNEPIMP_LIBRARIES})
target_link_libraries(juk ${TUNEPIMP_LIBRARIES})
endif(TUNEPIMP_FOUND)
feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES)
install(TARGETS juk ${INSTALL_TARGETS_DEFAULT_ARGS} )
......@@ -154,10 +209,23 @@ install(TARGETS juk ${INSTALL_TARGETS_DEFAULT_ARGS} )
########### install files ###############
install( PROGRAMS org.kde.juk.desktop DESTINATION ${XDG_APPS_INSTALL_DIR} )
install( FILES juk.notifyrc jukui.rc jukui-rtl.rc DESTINATION ${DATA_INSTALL_DIR}/juk )
install( FILES org.kde.juk.appdata.xml DESTINATION ${SHARE_INSTALL_PREFIX}/metainfo )
install( FILES jukui.rc jukui-rtl.rc DESTINATION ${KXMLGUI_INSTALL_DIR}/juk )
install(
FILES juk.notifyrc
DESTINATION ${KNOTIFYRC_INSTALL_DIR}
)
install( FILES org.kde.juk.appdata.xml DESTINATION ${KDE_INSTALL_METAINFODIR} )
install( FILES jukservicemenu.desktop DESTINATION
${SERVICES_INSTALL_DIR}/ServiceMenus )
install( FILES org.kde.juk.collection.xml org.kde.juk.player.xml org.kde.juk.search.xml DESTINATION ${DBUS_INTERFACES_INSTALL_DIR} )
kde4_install_icons( ${ICON_INSTALL_DIR} )
ecm_install_icons(ICONS
128-apps-juk.png
16-apps-juk.png
32-apps-juk.png
48-apps-juk.png
64-apps-juk.png
DESTINATION ${ICON_INSTALL_DIR}
THEME hicolor
)
# A KDE Jukebox
<img src="https://invent.kde.org/kde/juk/raw/master/128-apps-juk.png" align="right"
title="Juk logo" width="96" height="96">
[JuK](https://juk.kde.org) is an audio jukebox application, supporting collections of MP3, Ogg Vorbis,
and FLAC audio files. It allows you to edit the tags of your audio files, and
manage your collection and playlists. Its main focus, in fact, is on music
management.
Learn more about [Juk at KDE.org](https://www.kde.org/applications/multimedia/juk/).
## Features
<img src="https://juk.kde.org/img/screenshots/juk-3.10.1-tag.png" align="center"
title="Screenshot of JuK" width="800">
- Collection list and multiple user defined playlists
- Ability to scan directories to automatically import playlists and music files
on start up
- Dynamic Search Playlists that are automatically updated as fields in the
collection change.
- A Tree View mode where playlists are automatically generated for sets of
albums, artists and genres.
- Playlist history to indicate which files have been played and when.
- Inline search for filtering the list of visible items.
- The ability to guess tag information from the file name
- Previous versions could also use MusicBrainz online lookup, but we need help to
get that working again.
- File renamer that can rename files based on the tag content.
- ID3v1, ID3v2 and Ogg Vorbis tag reading and editing support (via TagLib).
## Installation
The methods listed below for each major OS are based on executing the
installation commands on a terminal window. Alternatively, you can use
your OS' package management app.
Unless using `sudo` to escalate privileges, the installation commands are
expected to be executed as the `root` user.
### Ubuntu
```
sudo apt install juk
```
### Debian
```
apt install juk
```
### CentOS, Fedora, RHEL
```sh
dnf install juk # On CentOs, use 'yum' instead of 'dnf'
```
### OpenSUSE
```
zypper install juk
```
### ArchLinux
1. Enable the `extra` repository on `/etc/pacman.conf`:
```
[extra]
Include = /etc/pacman.d/mirrorlist
```
1. Install the `juk` xz package:
```
# pacman -Sy juk
```
### Other OSs
Find your OS and installation instructions on
[Packages Search](https://pkgs.org/download/juk).
......@@ -15,10 +15,11 @@
*/
#include "actioncollection.h"
#include "juk.h"
#include <kactioncollection.h>
#include <kdebug.h>
#include "juk.h"
#include "juk_debug.h"
namespace ActionCollection
{
......@@ -43,7 +44,7 @@ namespace ActionCollection
#ifndef NO_DEBUG
QAction *a = actions()->action(key);
if(!a)
kWarning() << "KAction \"" << key << "\" is not defined yet.";
qCWarning(JUK_LOG) << "QAction \"" << key << "\" is not defined yet.";
return a;
#else
return actions()->action(key);
......
/**
* Copyright (C) 2003-2004 Scott Wheeler <wheeler@kde.org>
* Copyright (C) 2017 Michael Pyne <mpyne@kde.org>
*
* 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
......@@ -17,16 +18,17 @@
#include "advancedsearchdialog.h"
#include <kcombobox.h>
#include <klineedit.h>
#include <kpushbutton.h>
#include <klocale.h>
#include <kvbox.h>
#include <KLocalizedString>
#include <KStandardGuiItem>
#include <QDialogButtonBox>
#include <QRadioButton>
#include <QLabel>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QGroupBox>
#include <QPushButton>
#include <QLineEdit>
#include "collectionlist.h"
#include "searchwidget.h"
......@@ -37,54 +39,75 @@
AdvancedSearchDialog::AdvancedSearchDialog(const QString &defaultName,
const PlaylistSearch &defaultSearch,
QWidget *parent,
const char *name) :
KDialog(parent)
QWidget *parent) :
QDialog(parent)
{
setCaption( i18n("Create Search Playlist") );
setButtons( Ok|Cancel );
setDefaultButton( Ok );
setObjectName( QLatin1String( name ) );
setModal(true);
setWindowTitle(i18n("Create Search Playlist"));
setObjectName(QStringLiteral("juk_advSrchDlg"));
KVBox *mw = new KVBox(this);
setMainWidget(mw);
auto mw = new QVBoxLayout(this);
setLayout(mw);
KHBox *box = new KHBox(mw);
box->setSpacing(5);
auto box = new QHBoxLayout;
mw->addLayout(box);
new QLabel(i18n("Playlist name:"), box);
m_playlistNameLineEdit = new KLineEdit(defaultName, box);
box->addWidget(new QLabel(i18n("Playlist name:")));
m_playlistNameLineEdit = new QLineEdit(defaultName);
box->addWidget(m_playlistNameLineEdit);
QGroupBox *criteriaGroupBox = new QGroupBox(i18n("Search Criteria"), mw);
mw->setStretchFactor(criteriaGroupBox, 1);
m_criteriaLayout = new QVBoxLayout;
QGroupBox *group = new QGroupBox();
auto criteriaGroupBox = new QGroupBox(i18n("Search Criteria"));
mw->addWidget(criteriaGroupBox, 1);
m_criteriaLayout = new QVBoxLayout(criteriaGroupBox);
auto group = new QGroupBox;
m_matchAnyButton = new QRadioButton(i18n("Match any of the following"));
m_matchAllButton = new QRadioButton(i18n("Match all of the following"));
QHBoxLayout *hgroupbox = new QHBoxLayout;
QHBoxLayout *hgroupbox = new QHBoxLayout(group);
hgroupbox->addWidget(m_matchAnyButton);
hgroupbox->addWidget(m_matchAllButton);
group->setLayout(hgroupbox);
m_criteriaLayout->addWidget(group);
m_criteriaLayout->addStretch(1); // more()/fewer() assume this is here
QWidget *buttons = new QWidget;
mw->addWidget(buttons);
QHBoxLayout *l = new QHBoxLayout(buttons);
l->setSpacing(5);
l->setContentsMargins(0, 0, 0, 0);
const auto &clearGuiItem = KStandardGuiItem::clear();
QPushButton *clearButton = new QPushButton(clearGuiItem.icon(), clearGuiItem.text());
connect(clearButton, &QPushButton::clicked,
this, &AdvancedSearchDialog::clearSearches);
l->addWidget(clearButton);
l->addStretch(1);
m_moreButton = new QPushButton(i18nc("additional search options", "More"));
connect(m_moreButton, &QPushButton::clicked,
this, &AdvancedSearchDialog::more);
l->addWidget(m_moreButton);
m_fewerButton = new QPushButton(i18n("Fewer"));
connect(m_fewerButton, &QPushButton::clicked,
this, &AdvancedSearchDialog::fewer);
l->addWidget(m_fewerButton);
auto buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
connect(buttonBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
connect(buttonBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
mw->addWidget(buttonBox);
if(defaultSearch.isNull()) {
SearchLine *newSearchLine = new SearchLine(this);
m_searchLines.append(newSearchLine);
m_criteriaLayout->addWidget(newSearchLine);
newSearchLine = new SearchLine(this);
m_searchLines.append(newSearchLine);
m_criteriaLayout->addWidget(newSearchLine);
this->more();
this->more(); // Create first 2 searches
m_matchAnyButton->setChecked(true);
}
else {
PlaylistSearch::ComponentList components = defaultSearch.components();
for(PlaylistSearch::ComponentList::ConstIterator it = components.constBegin();
it != components.constEnd();
++it)
......@@ -92,58 +115,18 @@ AdvancedSearchDialog::AdvancedSearchDialog(const QString &defaultName,
SearchLine *s = new SearchLine(this);
s->setSearchComponent(*it);
m_searchLines.append(s);
m_criteriaLayout->addWidget(s);
m_criteriaLayout->insertWidget(m_criteriaLayout->count() - 1, s);
}
if(defaultSearch.searchMode() == PlaylistSearch::MatchAny)
m_matchAnyButton->setChecked(true);
else
m_matchAllButton->setChecked(true);
}
QWidget *buttons = new QWidget(mw);
QHBoxLayout *l = new QHBoxLayout(buttons);
l->setSpacing(5);
l->setMargin(0);
KPushButton *clearButton = new KPushButton(KStandardGuiItem::clear(), buttons);
connect(clearButton, SIGNAL(clicked()), SLOT(clear()));
l->addWidget(clearButton);
l->addStretch(1);
m_moreButton = new KPushButton(i18nc("additional search options", "More"), buttons);
connect(m_moreButton, SIGNAL(clicked()), SLOT(more()));
l->addWidget(m_moreButton);
m_fewerButton = new KPushButton(i18n("Fewer"), buttons);
connect(m_fewerButton, SIGNAL(clicked()), SLOT(fewer()));
l->addWidget(m_fewerButton);
m_criteriaLayout->addStretch(1);
criteriaGroupBox->setLayout(m_criteriaLayout);
m_playlistNameLineEdit->setFocus();
}
AdvancedSearchDialog::~AdvancedSearchDialog()
{
}
////////////////////////////////////////////////////////////////////////////////
// public slots
////////////////////////////////////////////////////////////////////////////////
AdvancedSearchDialog::Result AdvancedSearchDialog::exec()
{
Result r;
r.result = DialogCode(KDialog::exec());
r.search = m_search;
r.playlistName = m_playlistName;
return r;
}
////////////////////////////////////////////////////////////////////////////////
// protected slots
////////////////////////////////////////////////////////////////////////////////
......@@ -155,29 +138,28 @@ void AdvancedSearchDialog::accept()
m_search.addPlaylist(CollectionList::instance());
QList<SearchLine *>::const_iterator it = m_searchLines.constBegin();
for(; it != m_searchLines.constEnd(); ++it)
m_search.addComponent((*it)->searchComponent());
for(const auto &searchLine : m_searchLines)
m_search.addComponent(searchLine->searchComponent());
PlaylistSearch::SearchMode m = PlaylistSearch::SearchMode(!m_matchAnyButton->isChecked());
m_search.setSearchMode(m);
m_playlistName = m_playlistNameLineEdit->text();
KDialog::accept();
QDialog::accept();
}
void AdvancedSearchDialog::clear()
void AdvancedSearchDialog::clearSearches()
{
QList<SearchLine *>::const_iterator it = m_searchLines.constBegin();
for(; it != m_searchLines.constEnd(); ++it)
(*it)->clear();
for(auto &searchLine : m_searchLines)
searchLine->clear();
}
void AdvancedSearchDialog::more()
{
SearchLine *searchLine = new SearchLine(this);
m_criteriaLayout->addWidget(searchLine);
// inserting it to keep the trailing stretch item at end
m_criteriaLayout->insertWidget(m_criteriaLayout->count() - 1, searchLine);
m_searchLines.append(searchLine);
searchLine->show();
updateButtons();
......@@ -201,6 +183,4 @@ void AdvancedSearchDialog::updateButtons()
m_fewerButton->setEnabled(m_searchLines.count() > 1);
}
#include "advancedsearchdialog.moc"
// vim: set et sw=4 tw=0 sta:
......@@ -17,44 +17,42 @@
#ifndef ADVANCEDSEARCHDIALOG_H
#define ADVANCEDSEARCHDIALOG_H
#include <kdialog.h>
#include <QDialog>
#include <QList>
#include "playlistsearch.h"
class KLineEdit;
class KPushButton;
class QLineEdit;
class QPushButton;
class QRadioButton;
class SearchLine;
class QBoxLayout;
class AdvancedSearchDialog : public KDialog
class AdvancedSearchDialog : public QDialog
{
Q_OBJECT
public:
struct Result
{
DialogCode result;
PlaylistSearch search;
QString playlistName;
};
explicit AdvancedSearchDialog(const QString &defaultName,
const PlaylistSearch &defaultSearch = PlaylistSearch(),
QWidget *parent = 0,
const char *name = 0);
explicit AdvancedSearchDialog(
const QString& defaultName,
const PlaylistSearch& defaultSearch = PlaylistSearch(),
QWidget* parent = nullptr);
virtual ~AdvancedSearchDialog();
PlaylistSearch resultSearch() const
{
return m_search;
}
public slots:
Result exec();
QString resultPlaylistName() const
{
return m_playlistName;
}
protected slots:
virtual void accept();
virtual void clear();
virtual void more();
virtual void fewer();
void accept() Q_DECL_OVERRIDE;
void clearSearches();
void more();
void fewer();
private:
void updateButtons();
......@@ -63,11 +61,11 @@ private:
PlaylistSearch m_search;
QString m_playlistName;
QList<SearchLine *> m_searchLines;
KLineEdit *m_playlistNameLineEdit;
QLineEdit *m_playlistNameLineEdit;
QRadioButton *m_matchAnyButton;
QRadioButton *m_matchAllButton;
KPushButton *m_moreButton;
KPushButton *m_fewerButton;
QPushButton *m_moreButton;
QPushButton *m_fewerButton;
};
#endif
......
This diff is collapsed.
......@@ -18,18 +18,18 @@
#ifndef JUK_CACHE_H
#define JUK_CACHE_H
#include <QtCore/QDataStream>
#include <QtCore/QFile>
#include <QtCore/QBuffer>
#include <QDataStream>
#include <QFile>
#include <QBuffer>
class Playlist;
class PlaylistCollection;
class FileHandle;
template<class T>
class QList;
class QVector;
typedef QList<Playlist *> PlaylistList;
typedef QVector<Playlist *> PlaylistList;
/**
* A simple QDataStream subclass that has an extra field to indicate the cache
......@@ -58,8 +58,12 @@ public:
static void loadPlaylists(PlaylistCollection *collection);
static void savePlaylists(const PlaylistList &playlists);
static void ensureAppDataStorageExists();
static bool cacheFileExists();
static QString fileHandleCacheFileName();
static QString playlistsCacheFileName();
bool prepareToLoadCachedItems();
FileHandle loadNextCachedItem();
......
#
# FIND_LIBRARY_WITH_DEBUG
# -> enhanced FIND_LIBRARY to allow the search for an
# optional debug library with a WIN32_DEBUG_POSTFIX similar
# to CMAKE_DEBUG_POSTFIX when creating a shared lib
# it has to be the second and third argument
# Copyright (c) 2007, Christian Ehrlicher, <ch.ehrlicher@gmx.de>
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions
# are met:
# 1. Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
# 2. Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the
# documentation and/or other materials provided with the distribution.
# 3. Neither the name of the University nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGE.
MACRO(FIND_LIBRARY_WITH_DEBUG var_name win32_dbg_postfix_name dgb_postfix libname)
IF(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX")
# no WIN32_DEBUG_POSTFIX -> simply pass all arguments to FIND_LIBRARY
FIND_LIBRARY(${var_name}
${win32_dbg_postfix_name}
${dgb_postfix}
${libname}
${ARGN}
)
ELSE(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX")
IF(NOT WIN32)
# on non-win32 we don't need to take care about WIN32_DEBUG_POSTFIX
FIND_LIBRARY(${var_name} ${libname} ${ARGN})
ELSE(NOT WIN32)
# 1. get all possible libnames
SET(args ${ARGN})
SET(newargs "")
SET(libnames_release "")
SET(libnames_debug "")
LIST(LENGTH args listCount)
IF("${libname}" STREQUAL "NAMES")
SET(append_rest 0)
LIST(APPEND args " ")
FOREACH(i RANGE ${listCount})
LIST(GET args ${i} val)
IF(append_rest)
LIST(APPEND newargs ${val})
ELSE(append_rest)
IF("${val}" STREQUAL "PATHS")
LIST(APPEND newargs ${val})
SET(append_rest 1)
ELSE("${val}" STREQUAL "PATHS")
LIST(APPEND libnames_release "${val}")
LIST(APPEND libnames_debug "${val}${dgb_postfix}")
ENDIF("${val}" STREQUAL "PATHS")
ENDIF(append_rest)
ENDFOREACH(i)
ELSE("${libname}" STREQUAL "NAMES")
# just one name
LIST(APPEND libnames_release "${libname}")
LIST(APPEND libnames_debug "${libname}${dgb_postfix}")
SET(newargs ${args})
ENDIF("${libname}" STREQUAL "NAMES")
# search the release lib
FIND_LIBRARY(${var_name}_RELEASE
NAMES ${libnames_release}
${newargs}
)
# search the debug lib
FIND_LIBRARY(${var_name}_DEBUG
NAMES ${libnames_debug}
${newargs}
)
IF(${var_name}_RELEASE AND ${var_name}_DEBUG)
# both libs found
SET(${var_name} optimized ${${var_name}_RELEASE}
debug ${${var_name}_DEBUG})
ELSE(${var_name}_RELEASE AND ${var_name}_DEBUG)
IF(${var_name}_RELEASE)
# only release found
SET(${var_name} ${${var_name}_RELEASE})
ELSE(${var_name}_RELEASE)
# only debug (or nothing) found
SET(${var_name} ${${var_name}_DEBUG})
ENDIF(${var_name}_RELEASE)
ENDIF(${var_name}_RELEASE AND ${var_name}_DEBUG)
MARK_AS_ADVANCED(${var_name}_RELEASE)
MARK_AS_ADVANCED(${var_name}_DEBUG)
ENDIF(NOT WIN32)
ENDIF(NOT "${win32_dbg_postfix_name}" STREQUAL "WIN32_DEBUG_POSTFIX")
ENDMACRO(FIND_LIBRARY_WITH_DEBUG)
# - Try to find the Taglib library
# Once done this will define
#
# TAGLIB_FOUND - system has the taglib library
# TAGLIB_CFLAGS - the taglib cflags
# TAGLIB_LIBRARIES - The libraries needed to use taglib
# Copyright (c) 2006, Laurent Montel, <montel@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
if(NOT TAGLIB_MIN_VERSION)
set(TAGLIB_MIN_VERSION "1.4")
endif(NOT TAGLIB_MIN_VERSION)
if(NOT WIN32)
find_program(TAGLIBCONFIG_EXECUTABLE NAMES taglib-config PATHS
${BIN_INSTALL_DIR}
)
endif(NOT WIN32)
#reset vars
set(TAGLIB_LIBRARIES)
set(TAGLIB_CFLAGS)
# if taglib-config has been found
if(TAGLIBCONFIG_EXECUTABLE)
exec_program(${TAGLIBCONFIG_EXECUTABLE} ARGS --version RETURN_VALUE _return_VALUE OUTPUT_VARIABLE TAGLIB_VERSION)
if(TAGLIB_VERSION VERSION_LESS "${TAGLIB_MIN_VERSION}")
message(STATUS "TagLib version not found: version searched :${TAGLIB_MIN_VERSION}, found ${TAGLIB_VERSION}")
set(TAGLIB_FOUND FALSE)
else(TAGLIB_VERSION VERSION_LESS "${TAGLIB_MIN_VERSION}")
exec_program(${TAGLIBCONFIG_EXECUTABLE} ARGS --libs RETURN_VALUE _return_VALUE OUTPUT_VARIABLE TAGLIB_LIBRARIES)
exec_program(${TAGLIBCONFIG_EXECUTABLE} ARGS --cflags RETURN_VALUE _return_VALUE OUTPUT_VARIABLE TAGLIB_CFLAGS)
if(TAGLIB_LIBRARIES AND TAGLIB_CFLAGS)
set(TAGLIB_FOUND TRUE)
message(STATUS "Found taglib: ${TAGLIB_LIBRARIES}")
endif(TAGLIB_LIBRARIES AND TAGLIB_CFLAGS)
string(REGEX REPLACE " *-I" ";" TAGLIB_INCLUDES "${TAGLIB_CFLAGS}")
endif(TAGLIB_VERSION VERSION_LESS "${TAGLIB_MIN_VERSION}")
mark_as_advanced(TAGLIB_CFLAGS TAGLIB_LIBRARIES TAGLIB_INCLUDES)
else(TAGLIBCONFIG_EXECUTABLE)
include(FindLibraryWithDebug)
include(FindPackageHandleStandardArgs)
find_path(TAGLIB_INCLUDES
NAMES
tag.h
PATH_SUFFIXES taglib
PATHS
${KDE4_INCLUDE_DIR}
${INCLUDE_INSTALL_DIR}
)
list(APPEND TAGLIB_INCLUDES "${TAGLIB_INCLUDES}/..")
find_library_with_debug(TAGLIB_LIBRARIES
WIN32_DEBUG_POSTFIX d
NAMES tag
PATHS
${KDE4_LIB_DIR}
${LIB_INSTALL_DIR}
)
find_package_handle_standard_args(Taglib DEFAULT_MSG
TAGLIB_INCLUDES TAGLIB_LIBRARIES)
endif(TAGLIBCONFIG_EXECUTABLE)
if(TAGLIB_FOUND)
if(NOT Taglib_FIND_QUIETLY AND TAGLIBCONFIG_EXECUTABLE)
message(STATUS "Taglib found: ${TAGLIB_LIBRARIES}")
endif(NOT Taglib_FIND_QUIETLY AND TAGLIBCONFIG_EXECUTABLE)
else(TAGLIB_FOUND)
if(Taglib_FIND_REQUIRED)
message(FATAL_ERROR "Could not find Taglib")
endif(Taglib_FIND_REQUIRED)
endif(TAGLIB_FOUND)
# Option for build or not TunePimp
# Copyright (c) 2006, Laurent Montel, <montel@kde.org>
#
# Redistribution and use is allowed according to the terms of the BSD license.
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
if(TUNEPIMP_INCLUDE_DIR AND TUNEPIMP_LIBRARIES)
# Already in cache, be silent
set(TunePimp_FIND_QUIETLY TRUE)
endif(TUNEPIMP_INCLUDE_DIR AND TUNEPIMP_LIBRARIES)
FIND_PATH(TUNEPIMP_INCLUDE_DIR tunepimp/tp_c.h)
# Search tunepimp-0.5
if(NOT TUNEPIMP_INCLUDE_DIR)
FIND_PATH(TUNEPIMP_INCLUDE_DIR tunepimp-0.5/tp_c.h)
endif(NOT TUNEPIMP_INCLUDE_DIR)
FIND_LIBRARY(TUNEPIMP_LIBRARIES NAMES tunepimp)
if(TUNEPIMP_INCLUDE_DIR AND TUNEPIMP_LIBRARIES)
MESSAGE( STATUS "tunepimp found: includes in ${TUNEPIMP_INCLUDE_DIR}, library in ${TUNEPIMP_LIBRARIES}")
set(TUNEPIMP_FOUND TRUE)
INCLUDE(CheckLibraryExists)
SET(old_flags ${CMAKE_REQUIRED_LIBRARIES})
SET(CMAKE_REQUIRED_LIBRARIES ${CMAKE_THREAD_LIBS_INIT})
CHECK_LIBRARY_EXISTS(${TUNEPIMP_LIBRARIES} tp_SetFileNameEncoding "" TUNEPIMP_FOUND_VERSION_4)
CHECK_LIBRARY_EXISTS(${TUNEPIMP_LIBRARIES} tr_GetPUID "" TUNEPIMP_FOUND_VERSION_5)
SET(CMAKE_REQUIRED_LIBRARIES ${old_flags})
MESSAGE(STATUS "TUNEPIMP_FOUND_VERSION_4 :<${TUNEPIMP_FOUND_VERSION_4}>")
MESSAGE(STATUS "TUNEPIMP_FOUND_VERSION_5 :<${TUNEPIMP_FOUND_VERSION_5}>")
else(TUNEPIMP_INCLUDE_DIR AND TUNEPIMP_LIBRARIES)
MESSAGE( STATUS "tunepimp not found")
endif(TUNEPIMP_INCLUDE_DIR AND TUNEPIMP_LIBRARIES)
MARK_AS_ADVANCED(TUNEPIMP_INCLUDE_DIR TUNEPIMP_LIBRARIES)
This diff is collapsed.
......@@ -14,8 +14,8 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef COLLECTIONLIST_H
#define COLLECTIONLIST_H
#ifndef JUK_COLLECTIONLIST_H
#define JUK_COLLECTIONLIST_H
#include <QHash>
#include <QVector>
......@@ -52,7 +52,7 @@ typedef QVector<TagCountDict *> TagCountDicts;
* It is being implemented as a "semi-singleton" because I need universal access
* to just one instance. However, because the collection needs initialization
* parameters (that will not always be available when an instance is needed).
* Hence there will be the familiar singleton "instance()" method allong with an
* Hence there will be the familiar singleton "instance()" method along with an
* "initialize()" method.
*/
......@@ -63,7 +63,7 @@ class CollectionListItem : public PlaylistItem
friend class PlaylistItem;
public:
virtual void refresh();
virtual void refresh() override;
PlaylistItem *itemForPlaylist(const Playlist *playlist);
void updateCollectionDict(const QString &oldPath, const QString &newPath);
void repaint() const;
......@@ -82,7 +82,7 @@ protected:
*/
bool checkCurrent();
virtual CollectionListItem *collectionItem() { return this; }
virtual CollectionListItem *collectionItem() override { return this; }
private:
bool m_shuttingDown;
......@@ -113,22 +113,19 @@ public:
CollectionListItem *lookup(const QString &file) const;
virtual CollectionListItem *createItem(const FileHandle &file,
Q3ListViewItem * = 0,
bool = false);
QTreeWidgetItem * = nullptr) override;
void emitVisibleColumnsChanged() { emit signalVisibleColumnsChanged(); }
virtual void clearItems(const PlaylistItemList &items);
virtual void clearItems(const PlaylistItemList &items) override;
void setupTreeViewEntries(ViewMode *viewMode) const;
virtual bool canReload() const { return true; }
virtual bool canReload() const override { return true; }
void saveItemsToCache() const;
public slots:
virtual void paste();
virtual void clear();
virtual void clear() override;
void slotCheckCache();
void slotRemoveItem(const QString &file);
......@@ -136,14 +133,14 @@ public slots:
void slotNewItems(const KFileItemList &items);
void slotRefreshItems(const QList<QPair<KFileItem, KFileItem> > &items);
void slotDeleteItem(const KFileItem &item);
void slotDeleteItems(const KFileItemList &items);
protected:
CollectionList(PlaylistCollection *collection);
virtual ~CollectionList();
virtual void contentsDropEvent(QDropEvent *e);
virtual void contentsDragMoveEvent(QDragMoveEvent *e);
virtual void dropEvent(QDropEvent *e) override;
virtual void dragMoveEvent(QDragMoveEvent *e) override;
// These methods are used by CollectionListItem, which is a friend class.
......@@ -159,7 +156,7 @@ protected:
void addWatched(const QString &file);
void removeWatched(const QString &file);
virtual bool hasItem(const QString &file) const { return m_itemsDict.contains(file); }
virtual bool hasItem(const QString &file) const override { return m_itemsDict.contains(file); }
signals:
void signalCollectionChanged();
......@@ -169,9 +166,8 @@ signals:
*
* \see Playlist::hideColumn()
* \see Playlist::showColumn()
* \see Playlsit::isColumnVisible()
* \see Playlist::isColumnVisible()
*/
void signalVisibleColumnsChanged();
void signalNewTag(const QString &, unsigned);
void signalRemovedTag(const QString &, unsigned);
......@@ -193,7 +189,7 @@ public slots:
void loadNextBatchCachedItems();
/**
* Teardown from cache loading (e.g. splash screen, sorting, etc.). Should
* Teardown from cache loading (e.g. a sort operation). Should
* always be called if startLoadingCachedItems is called.
*/
void completedLoadingCachedItems();
......
......@@ -3,3 +3,6 @@
/* Defined if taglib supports Ogg::Opus::File */
#cmakedefine01 TAGLIB_HAS_OPUSFILE
/* Version */
#define JUK_VERSION "${KDE_APPLICATIONS_VERSION}"
......@@ -17,28 +17,28 @@
#include "coverdialog.h"
#include <KLocalizedString>
#include <kiconloader.h>
#include <kapplication.h>
#include <kmenu.h>
#include <klocale.h>
#include <QTimer>
#include <QMenu>
#include "covericonview.h"
#include "covermanager.h"
#include "collectionlist.h"
#include "juk_debug.h"
using CoverUtility::CoverIconViewItem;
class AllArtistsListViewItem : public QListWidgetItem
{
public:
AllArtistsListViewItem(KListWidget *parent) :
AllArtistsListViewItem(QListWidget *parent) :
QListWidgetItem(i18n("&lt;All Artists&gt;"), parent)
{
}
bool operator< (const QListWidgetItem& other) const
bool operator< (const QListWidgetItem& other) const override
{
Q_UNUSED(other);
return true; // Always be at the top.
......@@ -48,25 +48,25 @@ public:
class CaseInsensitiveItem : public QListWidgetItem
{
public:
CaseInsensitiveItem(KListWidget *parent, const QString &text) :
CaseInsensitiveItem(QListWidget *parent, const QString &text) :
QListWidgetItem(text, parent)
{
}
bool operator< (const QListWidgetItem& other) const
bool operator< (const QListWidgetItem& other) const override
{
return text().toLower().localeAwareCompare(other.text().toLower());
}
};
CoverDialog::CoverDialog(QWidget *parent) :
QWidget(parent, Qt::WType_Dialog)
QWidget(parent, Qt::Dialog)
{
setupUi(this);
setObjectName( QLatin1String("juk_cover_dialog" ));
setObjectName(QLatin1String("juk_cover_dialog"));
m_searchLine->setClearButtonShown(true);
m_searchLine->setClearButtonEnabled(true);
connect(m_artists, SIGNAL(itemClicked(QListWidgetItem*)),
this, SLOT(slotArtistClicked(QListWidgetItem*)));
......@@ -97,24 +97,14 @@ void CoverDialog::show()
QWidget::show();
}
// Here we try to keep the GUI from freezing for too long while we load the
// covers.
// TODO: Make this concurrent on a non-GUI thread
void CoverDialog::loadCovers()
{
CoverDataMapIterator it, end;
int i = 0;
it = CoverManager::begin();
end = CoverManager::end();
auto it = CoverManager::begin();
const auto &end = CoverManager::end();
for(; it != end; ++it) {
(void) new CoverIconViewItem(it.key(), m_covers);
// TODO: Threading!
if(++i == 10) {
i = 0;
kapp->processEvents();
}
(void) new CoverIconViewItem(it->first, m_covers);
}
}
......@@ -138,15 +128,15 @@ void CoverDialog::slotArtistClicked(QListWidgetItem *item)
end = CoverManager::end();
for(; it != end; ++it) {
if(it.value()->artist == artist)
(void) new CoverIconViewItem(it.key(), m_covers);
if(it->second.artist == artist)
(void) new CoverIconViewItem(it->first, m_covers);
}
}
}
void CoverDialog::slotContextRequested(const QPoint &pt)
{
static KMenu *menu = 0;
static QMenu *menu = nullptr;
QListWidgetItem* item = m_covers->currentItem();
......@@ -154,7 +144,7 @@ void CoverDialog::slotContextRequested(const QPoint &pt)
return;
if(!menu) {
menu = new KMenu(this);
menu = new QMenu(this);
menu->addAction(i18n("Remove Cover"), this, SLOT(removeSelectedCover()));
}
......@@ -177,32 +167,26 @@ void CoverDialog::slotSearchPatternChanged(const QString& pattern)
QRegExp filter(pattern, Qt::CaseInsensitive, QRegExp::Wildcard);
QString artist = item->text().toLower();
CoverDataMapIterator it, end;
it = CoverManager::begin();
end = CoverManager::end();
CoverDataMapIterator it = CoverManager::begin();
const CoverDataMapIterator end = CoverManager::end();
// Here, only show cover that match the search pattern.
if (dynamic_cast<AllArtistsListViewItem *>(item)) {
for(; it != end; ++it) {
if (filter.indexIn(it.value()->artist) != -1) {
(void) new CoverIconViewItem(it.key(), m_covers);
if (filter.indexIn(it->second.artist) != -1) {
(void) new CoverIconViewItem(it->first, m_covers);
}
}
}
// Here, only show the covers that match the search pattern and
// that have the same artist as the currently selected one.
else {
for(; it != end; ++it) {
if (it.value()->artist == artist
&& ((filter.indexIn(it.value()->artist) != -1)
|| (filter.indexIn(it.value()->album) != -1))) {
(void) new CoverIconViewItem(it.key(), m_covers);
if (it->second.artist == artist
&& ((filter.indexIn(it->second.artist) != -1)
|| (filter.indexIn(it->second.album) != -1)))
{
(void) new CoverIconViewItem(it->first, m_covers);
}
}
}
......@@ -214,16 +198,14 @@ void CoverDialog::removeSelectedCover()
CoverIconViewItem *coverItem = m_covers->currentItem();
if(!coverItem || !coverItem->isSelected()) {
kWarning() << "No item selected for removeSelectedCover.\n";
qCWarning(JUK_LOG) << "No item selected for removeSelectedCover.\n";
return;
}
if(!CoverManager::removeCover(coverItem->id()))
kError() << "Unable to remove selected cover: " << coverItem->id() << endl;
qCCritical(JUK_LOG) << "Unable to remove selected cover: " << coverItem->id();
else
delete coverItem;
}
#include "coverdialog.moc"
// vim: set et sw=4 tw=0 sta:
......@@ -15,8 +15,8 @@
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef COVERDIALOG_H
#define COVERDIALOG_H
#ifndef JUK_COVERDIALOG_H
#define JUK_COVERDIALOG_H
#include "ui_coverdialogbase.h"
......@@ -28,7 +28,7 @@ class CoverDialog : public QWidget, public Ui::CoverDialogBase
{
Q_OBJECT
public:
CoverDialog(QWidget *parent);
explicit CoverDialog(QWidget *parent);
~CoverDialog();
virtual void show();
......@@ -43,6 +43,6 @@ private slots:
void removeSelectedCover();
};
#endif /* COVERDIALOG_H */
#endif /* JUK_COVERDIALOG_H */
// vim: set et sw=4 tw=0 sta:
<ui version="4.0" >
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CoverDialogBase</class>
<widget class="QWidget" name="CoverDialogBase" >
<property name="geometry" >
<widget class="QWidget" name="CoverDialogBase">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
......@@ -9,61 +10,79 @@
<height>554</height>
</rect>
</property>
<property name="windowTitle" >
<property name="windowTitle">
<string>Cover Manager</string>
</property>
<layout class="QHBoxLayout" >
<property name="margin" >
<layout class="QHBoxLayout">
<property name="spacing">
<number>6</number>
</property>
<property name="leftMargin">
<number>11</number>
</property>
<property name="spacing" >
<number>6</number>
<property name="topMargin">
<number>11</number>
</property>
<property name="rightMargin">
<number>11</number>
</property>
<property name="bottomMargin">
<number>11</number>
</property>
<item>
<widget class="KListWidget" name="m_artists" >