Example #1
0
AlbumCoverSearcher::AlbumCoverSearcher(const QIcon& no_cover_icon,
                                       Application* app, QWidget* parent)
    : QDialog(parent),
      ui_(new Ui_AlbumCoverSearcher),
      app_(app),
      model_(new QStandardItemModel(this)),
      no_cover_icon_(no_cover_icon),
      fetcher_(nullptr),
      id_(0) {
  setWindowModality(Qt::WindowModal);
  ui_->setupUi(this);
  ui_->busy->hide();

  ui_->covers->set_header_text(tr("Covers from %1"));
  ui_->covers->AddSortSpec(Role_ImageDimensions, Qt::DescendingOrder);
  ui_->covers->setItemDelegate(new SizeOverlayDelegate(this));
  ui_->covers->setModel(model_);

  options_.scale_output_image_ = false;
  options_.pad_output_image_ = false;

  connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64, QImage)),
          SLOT(ImageLoaded(quint64, QImage)));

  connect(ui_->search, SIGNAL(clicked()), SLOT(Search()));
  connect(ui_->covers, SIGNAL(doubleClicked(QModelIndex)),
          SLOT(CoverDoubleClicked(QModelIndex)));

  new ForceScrollPerPixel(ui_->covers, this);

  ui_->buttonBox->button(QDialogButtonBox::Cancel)
      ->setShortcut(QKeySequence::Close);
}
void SpotifyServer::MessageArrived(const pb::spotify::Message& message) {
  if (message.has_login_response()) {
    const pb::spotify::LoginResponse& response = message.login_response();
    logged_in_ = response.success();

    if (response.success()) {
      // Send any messages that were queued before the client logged in
      for (const pb::spotify::Message& message : queued_messages_) {
        SendOrQueueMessage(message);
      }
      queued_messages_.clear();
    }

    emit LoginCompleted(response.success(),
                        QStringFromStdString(response.error()),
                        response.error_code());
  } else if (message.has_playlists_updated()) {
    emit PlaylistsUpdated(message.playlists_updated());
  } else if (message.has_load_playlist_response()) {
    const pb::spotify::LoadPlaylistResponse& response =
        message.load_playlist_response();

    switch (response.request().type()) {
      case pb::spotify::Inbox:
        emit InboxLoaded(response);
        break;

      case pb::spotify::Starred:
        emit StarredLoaded(response);
        break;

      case pb::spotify::UserPlaylist:
        emit UserPlaylistLoaded(response);
        break;
    }
  } else if (message.has_playback_error()) {
    emit PlaybackError(QStringFromStdString(message.playback_error().error()));
  } else if (message.has_search_response()) {
    emit SearchResults(message.search_response());
  } else if (message.has_image_response()) {
    const pb::spotify::ImageResponse& response = message.image_response();
    const QString id = QStringFromStdString(response.id());

    if (response.has_data()) {
      emit ImageLoaded(
          id, QImage::fromData(
                  QByteArray(response.data().data(), response.data().size())));
    } else {
      emit ImageLoaded(id, QImage());
    }
  } else if (message.has_sync_playlist_progress()) {
    emit SyncPlaylistProgress(message.sync_playlist_progress());
  } else if (message.has_browse_album_response()) {
    emit AlbumBrowseResults(message.browse_album_response());
  } else if (message.has_browse_toplist_response()) {
    emit ToplistBrowseResults(message.browse_toplist_response());
  }
}
Example #3
0
void SpotifyService::EnsureServerCreated(const QString& username,
                                         const QString& password) {
  if (server_ && blob_process_) {
    return;
  }

  delete server_;
  server_ = new SpotifyServer(this);

  connect(
      server_,
      SIGNAL(LoginCompleted(bool, QString, pb::spotify::LoginResponse_Error)),
      SLOT(LoginCompleted(bool, QString, pb::spotify::LoginResponse_Error)));
  connect(server_, SIGNAL(PlaylistsUpdated(pb::spotify::Playlists)),
          SLOT(PlaylistsUpdated(pb::spotify::Playlists)));
  connect(server_, SIGNAL(InboxLoaded(pb::spotify::LoadPlaylistResponse)),
          SLOT(InboxLoaded(pb::spotify::LoadPlaylistResponse)));
  connect(server_, SIGNAL(StarredLoaded(pb::spotify::LoadPlaylistResponse)),
          SLOT(StarredLoaded(pb::spotify::LoadPlaylistResponse)));
  connect(server_,
          SIGNAL(UserPlaylistLoaded(pb::spotify::LoadPlaylistResponse)),
          SLOT(UserPlaylistLoaded(pb::spotify::LoadPlaylistResponse)));
  connect(server_, SIGNAL(PlaybackError(QString)),
          SIGNAL(StreamError(QString)));
  connect(server_, SIGNAL(SearchResults(pb::spotify::SearchResponse)),
          SLOT(SearchResults(pb::spotify::SearchResponse)));
  connect(server_, SIGNAL(ImageLoaded(QString, QImage)),
          SIGNAL(ImageLoaded(QString, QImage)));
  connect(server_,
          SIGNAL(SyncPlaylistProgress(pb::spotify::SyncPlaylistProgress)),
          SLOT(SyncPlaylistProgress(pb::spotify::SyncPlaylistProgress)));
  connect(server_,
          SIGNAL(ToplistBrowseResults(pb::spotify::BrowseToplistResponse)),
          SLOT(ToplistLoaded(pb::spotify::BrowseToplistResponse)));

  server_->Init();

  login_task_id_ = app_->task_manager()->StartTask(tr("Connecting to Spotify"));

  QString login_username = username;
  QString login_password = password;

  if (username.isEmpty()) {
    QSettings s;
    s.beginGroup(kSettingsGroup);

    login_username = s.value("username").toString();
    login_password = QString();
  }

  server_->Login(login_username, login_password, bitrate_,
                 volume_normalisation_);

  StartBlobProcess();
}
void ArtLoader::Initialised() {
  cover_loader_->Worker()->SetScaleOutputImage(false);
  cover_loader_->Worker()->SetPadOutputImage(false);
  cover_loader_->Worker()->SetDefaultOutputImage(QImage(":nocover.png"));
  connect(cover_loader_->Worker().get(), SIGNAL(ImageLoaded(quint64,QImage)),
          SLOT(TempArtLoaded(quint64,QImage)));
}
Example #5
0
EditTagDialog::EditTagDialog(Application* app, QWidget* parent)
  : QDialog(parent),
    ui_(new Ui_EditTagDialog),
    app_(app),
    album_cover_choice_controller_(new AlbumCoverChoiceController(this)),
    loading_(false),
    ignore_edits_(false),
    tag_fetcher_(new TagFetcher(this)),
    cover_art_id_(0),
    cover_art_is_set_(false),
    results_dialog_(new TrackSelectionDialog(this))
{
  cover_options_.default_output_image_ =
      AlbumCoverLoader::ScaleAndPad(cover_options_, QImage(":nocover.png"));

  connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64,QImage,QImage)),
          SLOT(ArtLoaded(quint64,QImage,QImage)));

  connect(tag_fetcher_, SIGNAL(ResultAvailable(Song, SongList)),
          results_dialog_, SLOT(FetchTagFinished(Song, SongList)),
          Qt::QueuedConnection);
  connect(tag_fetcher_, SIGNAL(Progress(Song,QString)),
          results_dialog_, SLOT(FetchTagProgress(Song,QString)));
  connect(results_dialog_, SIGNAL(SongChosen(Song, Song)),
          SLOT(FetchTagSongChosen(Song, Song)));
  connect(results_dialog_, SIGNAL(finished(int)), tag_fetcher_, SLOT(Cancel()));

  album_cover_choice_controller_->SetApplication(app_);

  ui_->setupUi(this);
  ui_->splitter->setSizes(QList<int>() << 200 << width() - 200);
  ui_->loading_label->hide();

  // An editable field is one that has a label as a buddy.  The label is
  // important because it gets turned bold when the field is changed.
  foreach (QLabel* label, findChildren<QLabel*>()) {
    QWidget* widget = label->buddy();
    if (widget) {
      // Store information about the field
      fields_ << FieldData(label, widget, widget->objectName());

      // Connect the Reset signal
      if (dynamic_cast<ExtendedEditor*>(widget)) {
        connect(widget, SIGNAL(Reset()), SLOT(ResetField()));
      }

      // Connect the edited signal
      if (qobject_cast<QLineEdit*>(widget)) {
        connect(widget, SIGNAL(textChanged(QString)), SLOT(FieldValueEdited()));
      } else if (qobject_cast<QPlainTextEdit*>(widget)) {
        connect(widget, SIGNAL(textChanged()), SLOT(FieldValueEdited()));
      } else if (qobject_cast<QSpinBox*>(widget)) {
        connect(widget, SIGNAL(valueChanged(int)), SLOT(FieldValueEdited()));
      }
    }
  }
void SpotifyService::EnsureServerCreated(const QString& username,
                                         const QString& password) {
  if (server_ && blob_process_) {
    return;
  }

  delete server_;
  server_ = new SpotifyServer(this);

  connect(server_, SIGNAL(LoginCompleted(bool,QString,spotify_pb::LoginResponse_Error)),
                   SLOT(LoginCompleted(bool,QString,spotify_pb::LoginResponse_Error)));
  connect(server_, SIGNAL(PlaylistsUpdated(spotify_pb::Playlists)),
          SLOT(PlaylistsUpdated(spotify_pb::Playlists)));
  connect(server_, SIGNAL(InboxLoaded(spotify_pb::LoadPlaylistResponse)),
          SLOT(InboxLoaded(spotify_pb::LoadPlaylistResponse)));
  connect(server_, SIGNAL(StarredLoaded(spotify_pb::LoadPlaylistResponse)),
          SLOT(StarredLoaded(spotify_pb::LoadPlaylistResponse)));
  connect(server_, SIGNAL(UserPlaylistLoaded(spotify_pb::LoadPlaylistResponse)),
          SLOT(UserPlaylistLoaded(spotify_pb::LoadPlaylistResponse)));
  connect(server_, SIGNAL(PlaybackError(QString)),
          SIGNAL(StreamError(QString)));
  connect(server_, SIGNAL(SearchResults(spotify_pb::SearchResponse)),
          SLOT(SearchResults(spotify_pb::SearchResponse)));
  connect(server_, SIGNAL(ImageLoaded(QString,QImage)),
          SLOT(ImageLoaded(QString,QImage)));
  connect(server_, SIGNAL(SyncPlaylistProgress(spotify_pb::SyncPlaylistProgress)),
          SLOT(SyncPlaylistProgress(spotify_pb::SyncPlaylistProgress)));

  server_->Init();

  login_task_id_ = model()->task_manager()->StartTask(tr("Connecting to Spotify"));

  if (username.isEmpty()) {
    QSettings s;
    s.beginGroup(kSettingsGroup);

    server_->Login(s.value("username").toString(), s.value("password").toString());
  } else {
    server_->Login(username, password);
  }

  StartBlobProcess();
}
Example #7
0
void ImageActor::OnImageSet( Image& image )
{
  // observe image loaded
  if( Dali::ResourceLoading == image.GetLoadingState() && ! image.GetFilename().empty() )
  {
    image.LoadingFinishedSignal().Connect( mLoadedConnection, &ImageActor::ImageLoaded );
  }
  else
  {
    // image already loaded, or generated
    ImageLoaded( Dali::Image(&image) );
  }
}
CurrentArtLoader::CurrentArtLoader(Application* app, QObject* parent)
    : QObject(parent),
      app_(app),
      temp_file_pattern_(QDir::tempPath() + "/clementine-art-XXXXXX.jpg"),
      id_(0) {
  options_.scale_output_image_ = false;
  options_.pad_output_image_ = false;
  options_.default_output_image_ = QImage(":nocover.png");

  connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64, QImage)),
          SLOT(TempArtLoaded(quint64, QImage)));

  connect(app_->playlist_manager(), SIGNAL(CurrentSongChanged(Song)),
          SLOT(LoadArt(Song)));
}
Example #9
0
GlobalSearch::GlobalSearch(Application* app, QObject* parent)
    : QObject(parent),
      app_(app),
      next_id_(1),
      url_provider_(new UrlSearchProvider(app, this)) {
  cover_loader_options_.desired_height_ = SearchProvider::kArtHeight;
  cover_loader_options_.pad_output_image_ = true;
  cover_loader_options_.scale_output_image_ = true;

  connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64, QImage)),
          SLOT(AlbumArtLoaded(quint64, QImage)));
  connect(this, SIGNAL(SearchAsyncSig(int,QString)),
          this, SLOT(DoSearchAsync(int,QString)));

  ConnectProvider(url_provider_);
}
void SoundCloudSearchProvider::Init(SoundCloudService* service) {
  service_ = service;
  SearchProvider::Init(
      "SoundCloud", "soundcloud", IconLoader::Load("soundcloud", 
      IconLoader::Provider), WantsDelayedQueries | ArtIsProbablyRemote | 
      CanShowConfig);

  connect(service_, SIGNAL(SimpleSearchResults(int, SongList)),
          SLOT(SearchDone(int, SongList)));

  cover_loader_options_.desired_height_ = kArtHeight;
  cover_loader_options_.pad_output_image_ = true;
  cover_loader_options_.scale_output_image_ = true;

  connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64, QImage)),
          SLOT(AlbumArtLoaded(quint64, QImage)));
}
CurrentArtLoader::CurrentArtLoader(Application* app, QObject* parent)
    : QObject(parent),
      app_(app),
      temp_file_pattern_(QDir::tempPath() + "/clementine-art-XXXXXX.jpg"),
      id_(0) {
  options_.scale_output_image_ = false;
  options_.pad_output_image_ = false;
  QIcon nocover = IconLoader::Load("nocover", IconLoader::Other);
  options_.default_output_image_ = nocover.pixmap(nocover.availableSizes()
                                                         .last()).toImage();

  connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64, QImage)),
          SLOT(TempArtLoaded(quint64, QImage)));

  connect(app_->playlist_manager(), SIGNAL(CurrentSongChanged(Song)),
          SLOT(LoadArt(Song)));
}
Example #12
0
SpotifyServer* SpotifySearchProvider::server() {
  if (server_)
    return server_;

  if (!service_)
    service_ = InternetModel::Service<SpotifyService>();

  if (service_->login_state() != SpotifyService::LoginState_LoggedIn)
    return NULL;

  server_ = service_->server();
  connect(server_, SIGNAL(SearchResults(pb::spotify::SearchResponse)),
          SLOT(SearchFinishedSlot(pb::spotify::SearchResponse)));
  connect(server_, SIGNAL(ImageLoaded(QString,QImage)),
          SLOT(ArtLoadedSlot(QString,QImage)));
  connect(server_, SIGNAL(AlbumBrowseResults(pb::spotify::BrowseAlbumResponse)),
          SLOT(AlbumBrowseResponse(pb::spotify::BrowseAlbumResponse)));
  connect(server_, SIGNAL(destroyed()), SLOT(ServerDestroyed()));

  return server_;
}
void 
MainWindow::LoadNewImage( QImage image )
///
/// Loads a new image
///
/// @param image
///  The image to be loaded
///
/// @return
///  Nothing
///
{
	// Move the past image to be the previous image
	if( mPreviousImage != NULL )
	{
		delete mPreviousImage;
	}

	mPreviousImage = mCurrentImage;

	// Delete next image if it exists, redo functionality will be reset.
	if( mNextImage != NULL )
	{
		delete mNextImage;
		mNextImage = NULL;
	}

	// Set this image as the current image
	mCurrentImage = new QImage();
	*mCurrentImage = image.copy();

	// Update the state of the GUI
	emit ImageLoaded( mCurrentImage != NULL && !mCurrentImage->isNull() );

	UpdateVisibleImage( image );
	UpdateEditMenuStates();
}
Example #14
0
void PodcastInfoWidget::SetApplication(Application* app) {
  app_ = app;
  connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64,QImage)),
          SLOT(ImageLoaded(quint64,QImage)));
}
void AlbumCoverManager::CoverLoaderInitialised() {
  cover_loader_->Worker()->SetDefaultOutputImage(QImage());
  connect(cover_loader_->Worker().get(), SIGNAL(ImageLoaded(quint64,QImage)),
          SLOT(CoverImageLoaded(quint64,QImage)));
}
Example #16
0
EditTagDialog::EditTagDialog(Application* app, QWidget* parent)
    : QDialog(parent),
      ui_(new Ui_EditTagDialog),
      app_(app),
      album_cover_choice_controller_(new AlbumCoverChoiceController(this)),
      loading_(false),
      ignore_edits_(false),
      tag_fetcher_(new TagFetcher(this)),
      cover_art_id_(0),
      cover_art_is_set_(false),
      results_dialog_(new TrackSelectionDialog(this)) {
  cover_options_.default_output_image_ =
      AlbumCoverLoader::ScaleAndPad(cover_options_, QImage(":nocover.png"));

  connect(app_->album_cover_loader(),
          SIGNAL(ImageLoaded(quint64, QImage, QImage)),
          SLOT(ArtLoaded(quint64, QImage, QImage)));

  connect(tag_fetcher_, SIGNAL(ResultAvailable(Song, SongList)),
          results_dialog_, SLOT(FetchTagFinished(Song, SongList)),
          Qt::QueuedConnection);
  connect(tag_fetcher_, SIGNAL(Progress(Song, QString)), results_dialog_,
          SLOT(FetchTagProgress(Song, QString)));
  connect(results_dialog_, SIGNAL(SongChosen(Song, Song)),
          SLOT(FetchTagSongChosen(Song, Song)));
  connect(results_dialog_, SIGNAL(finished(int)), tag_fetcher_, SLOT(Cancel()));

  album_cover_choice_controller_->SetApplication(app_);

  ui_->setupUi(this);
  ui_->splitter->setSizes(QList<int>() << 200 << width() - 200);
  ui_->loading_label->hide();

  // An editable field is one that has a label as a buddy.  The label is
  // important because it gets turned bold when the field is changed.
  for (QLabel* label : findChildren<QLabel*>()) {
    QWidget* widget = label->buddy();
    if (widget) {
      // Store information about the field
      fields_ << FieldData(label, widget, widget->objectName());

      // Connect the Reset signal
      if (dynamic_cast<ExtendedEditor*>(widget)) {
        connect(widget, SIGNAL(Reset()), SLOT(ResetField()));
      }

      // Connect the edited signal
      if (qobject_cast<QLineEdit*>(widget)) {
        connect(widget, SIGNAL(textChanged(QString)), SLOT(FieldValueEdited()));
      } else if (qobject_cast<QPlainTextEdit*>(widget)) {
        connect(widget, SIGNAL(textChanged()), SLOT(FieldValueEdited()));
      } else if (qobject_cast<QSpinBox*>(widget)) {
        connect(widget, SIGNAL(valueChanged(int)), SLOT(FieldValueEdited()));
      }
    }
  }

  // Set the colour of all the labels on the summary page
  const bool light = palette().color(QPalette::Base).value() > 128;
  const QColor color = palette().color(QPalette::Dark);
  QPalette summary_label_palette(palette());
  summary_label_palette.setColor(
      QPalette::WindowText, light ? color.darker(150) : color.lighter(125));

  for (QLabel* label : ui_->summary_tab->findChildren<QLabel*>()) {
    if (label->property("field_label").toBool()) {
      label->setPalette(summary_label_palette);
    }
  }

  // Pretend the summary text is just a label
  ui_->summary->setMaximumHeight(ui_->art->height() -
                                 ui_->summary_art_button->height() - 4);

  connect(ui_->song_list->selectionModel(),
          SIGNAL(selectionChanged(QItemSelection, QItemSelection)),
          SLOT(SelectionChanged()));
  connect(ui_->button_box, SIGNAL(clicked(QAbstractButton*)),
          SLOT(ButtonClicked(QAbstractButton*)));
  connect(ui_->rating, SIGNAL(RatingChanged(float)), SLOT(SongRated(float)));
  connect(ui_->playcount_reset, SIGNAL(clicked()), SLOT(ResetPlayCounts()));
  connect(ui_->fetch_tag, SIGNAL(clicked()), SLOT(FetchTag()));

  // Set up the album cover menu
  cover_menu_ = new QMenu(this);

  QList<QAction*> actions = album_cover_choice_controller_->GetAllActions();

  connect(album_cover_choice_controller_->cover_from_file_action(),
          SIGNAL(triggered()), this, SLOT(LoadCoverFromFile()));
  connect(album_cover_choice_controller_->cover_to_file_action(),
          SIGNAL(triggered()), this, SLOT(SaveCoverToFile()));
  connect(album_cover_choice_controller_->cover_from_url_action(),
          SIGNAL(triggered()), this, SLOT(LoadCoverFromURL()));
  connect(album_cover_choice_controller_->search_for_cover_action(),
          SIGNAL(triggered()), this, SLOT(SearchForCover()));
  connect(album_cover_choice_controller_->unset_cover_action(),
          SIGNAL(triggered()), this, SLOT(UnsetCover()));
  connect(album_cover_choice_controller_->show_cover_action(),
          SIGNAL(triggered()), this, SLOT(ShowCover()));

  cover_menu_->addActions(actions);

  ui_->summary_art_button->setMenu(cover_menu_);

  ui_->art->installEventFilter(this);
  ui_->art->setAcceptDrops(true);

  // Add the next/previous buttons
  previous_button_ =
      new QPushButton(IconLoader::Load("go-previous"), tr("Previous"), this);
  next_button_ = new QPushButton(IconLoader::Load("go-next"), tr("Next"), this);
  ui_->button_box->addButton(previous_button_, QDialogButtonBox::ResetRole);
  ui_->button_box->addButton(next_button_, QDialogButtonBox::ResetRole);

  connect(previous_button_, SIGNAL(clicked()), SLOT(PreviousSong()));
  connect(next_button_, SIGNAL(clicked()), SLOT(NextSong()));

  // Set some shortcuts for the buttons
  new QShortcut(QKeySequence::Back, previous_button_, SLOT(click()));
  new QShortcut(QKeySequence::Forward, next_button_, SLOT(click()));
  new QShortcut(QKeySequence::MoveToPreviousPage, previous_button_,
                SLOT(click()));
  new QShortcut(QKeySequence::MoveToNextPage, next_button_, SLOT(click()));

  // Show the shortcuts as tooltips
  previous_button_->setToolTip(QString("%1 (%2 / %3)").arg(
      previous_button_->text(),
      QKeySequence(QKeySequence::Back).toString(QKeySequence::NativeText),
      QKeySequence(QKeySequence::MoveToPreviousPage)
          .toString(QKeySequence::NativeText)));
  next_button_->setToolTip(QString("%1 (%2 / %3)").arg(
      next_button_->text(),
      QKeySequence(QKeySequence::Forward).toString(QKeySequence::NativeText),
      QKeySequence(QKeySequence::MoveToNextPage)
          .toString(QKeySequence::NativeText)));

  new TagCompleter(app_->library_backend(), Playlist::Column_Artist,
                   ui_->artist);
  new TagCompleter(app_->library_backend(), Playlist::Column_Album, ui_->album);
  new TagCompleter(app_->library_backend(), Playlist::Column_AlbumArtist,
                   ui_->albumartist);
  new TagCompleter(app_->library_backend(), Playlist::Column_Genre, ui_->genre);
  new TagCompleter(app_->library_backend(), Playlist::Column_Composer,
                   ui_->composer);
  new TagCompleter(app_->library_backend(), Playlist::Column_Performer,
                   ui_->performer);
  new TagCompleter(app_->library_backend(), Playlist::Column_Grouping,
                   ui_->grouping);
}
Example #17
0
void AlbumCoverManager::Init() {
  // View menu
  QActionGroup* filter_group = new QActionGroup(this);
  filter_all_ = filter_group->addAction(tr("All albums"));
  filter_with_covers_ = filter_group->addAction(tr("Albums with covers"));
  filter_without_covers_ = filter_group->addAction(tr("Albums without covers"));
  filter_all_->setCheckable(true);
  filter_with_covers_->setCheckable(true);
  filter_without_covers_->setCheckable(true);
  filter_group->setExclusive(true);
  filter_all_->setChecked(true);

  QMenu* view_menu = new QMenu(this);
  view_menu->addActions(filter_group->actions());

  ui_->view->setMenu(view_menu);

  // Context menu

  QList<QAction*> actions = album_cover_choice_controller_->GetAllActions();

  connect(album_cover_choice_controller_->cover_from_file_action(),
          SIGNAL(triggered()), this, SLOT(LoadCoverFromFile()));
  connect(album_cover_choice_controller_->cover_to_file_action(),
          SIGNAL(triggered()), this, SLOT(SaveCoverToFile()));
  connect(album_cover_choice_controller_->cover_from_url_action(),
          SIGNAL(triggered()), this, SLOT(LoadCoverFromURL()));
  connect(album_cover_choice_controller_->search_for_cover_action(),
          SIGNAL(triggered()), this, SLOT(SearchForCover()));
  connect(album_cover_choice_controller_->unset_cover_action(),
          SIGNAL(triggered()), this, SLOT(UnsetCover()));
  connect(album_cover_choice_controller_->show_cover_action(),
          SIGNAL(triggered()), this, SLOT(ShowCover()));

  connect(cover_exporter_, SIGNAL(AlbumCoversExportUpdate(int, int, int)),
          SLOT(UpdateExportStatus(int, int, int)));

  context_menu_->addActions(actions);
  context_menu_->addSeparator();
  context_menu_->addAction(ui_->action_load);
  context_menu_->addAction(ui_->action_add_to_playlist);

  ui_->albums->installEventFilter(this);

  // Connections
  connect(ui_->artists,
          SIGNAL(currentItemChanged(QListWidgetItem*, QListWidgetItem*)),
          SLOT(ArtistChanged(QListWidgetItem*)));
  connect(ui_->filter, SIGNAL(textChanged(QString)), SLOT(UpdateFilter()));
  connect(filter_group, SIGNAL(triggered(QAction*)), SLOT(UpdateFilter()));
  connect(ui_->view, SIGNAL(clicked()), ui_->view, SLOT(showMenu()));
  connect(ui_->fetch, SIGNAL(clicked()), SLOT(FetchAlbumCovers()));
  connect(ui_->export_covers, SIGNAL(clicked()), SLOT(ExportCovers()));
  connect(cover_fetcher_,
          SIGNAL(AlbumCoverFetched(quint64, QImage, CoverSearchStatistics)),
          SLOT(AlbumCoverFetched(quint64, QImage, CoverSearchStatistics)));
  connect(ui_->action_fetch, SIGNAL(triggered()), SLOT(FetchSingleCover()));
  connect(ui_->albums, SIGNAL(doubleClicked(QModelIndex)),
          SLOT(AlbumDoubleClicked(QModelIndex)));
  connect(ui_->action_add_to_playlist, SIGNAL(triggered()),
          SLOT(AddSelectedToPlaylist()));
  connect(ui_->action_load, SIGNAL(triggered()),
          SLOT(LoadSelectedToPlaylist()));

  // Restore settings
  QSettings s;
  s.beginGroup(kSettingsGroup);

  restoreGeometry(s.value("geometry").toByteArray());
  if (!ui_->splitter->restoreState(s.value("splitter_state").toByteArray())) {
    // Sensible default size for the artists view
    ui_->splitter->setSizes(QList<int>() << 200 << width() - 200);
  }

  connect(app_->album_cover_loader(), SIGNAL(ImageLoaded(quint64, QImage)),
          SLOT(CoverImageLoaded(quint64, QImage)));

  cover_searcher_->Init(cover_fetcher_);

  new ForceScrollPerPixel(ui_->albums, this);
}