Archive / / / / / MainWindow.cc
2008-10-21 13:36:22 UTC
previous next
/* Echo Media Player * Copyright (C) 2008 Shane O'Connell * * [ The original file includes a copyright header in this location describing * the file as being released under the terms of the GNU General Public * License. It has been removed in order to display the file as part of the * archive. ] */ #include "MainWindow.h" #include "TrackSlider.h" #include "../db/Database.h" #include <iostream> using namespace std; MainWindow::MainWindow() { set_title("Echo Media Player"); set_default_size(800, 600); init_actiongroups(); init_main_vbox(); m_refStatusIcon = Gtk::StatusIcon::create(Gtk::Stock::HOME); m_refStatusIcon->signal_activate().connect( sigc::mem_fun(*this, &MainWindow::on_status_icon_click)); m_refStatusIcon->signal_popup_menu().connect( sigc::mem_fun(*this, &MainWindow::on_status_icon_popup)); m_sources_pane.signal_library_opened().connect( sigc::mem_fun(m_tab_pane, &TabPane::open_library)); m_sources_pane.signal_now_playing_opened().connect( sigc::mem_fun(m_tab_pane, &TabPane::open_now_playing)); notify_init("Echo Media Player"); m_notify = NULL; PlaybackManager::signal_track_started().connect( sigc::mem_fun(*this, &MainWindow::show_libnotify_popup)); PlaybackManager::signal_track_started().connect( sigc::mem_fun(*this, &MainWindow::on_media_started)); PlaybackManager::signal_track_stopped().connect( sigc::mem_fun(*this, &MainWindow::on_media_stopped)); show_all_children(); m_progress_pane.hide(); } MainWindow::~MainWindow() { notify_uninit(); } void MainWindow::init_actiongroups() { m_refActionGroup = Gtk::ActionGroup::create(); m_refActionGroup->add(Gtk::Action::create("FileMenu", "_File")); m_refActionGroup->add(Gtk::Action::create("FileNewPlaylist", "New _Playlist"), sigc::mem_fun(m_tab_pane, &TabPane::add_blank_playlist)); m_refActionGroup->add(Gtk::Action::create("FileNewSmartPlaylist", "New _Smart Playlist")); m_refActionGroup->add(Gtk::Action::create("FileOpen", Gtk::Stock::OPEN)); m_refActionGroup->add(Gtk::Action::create("FileOpenURL", "Open _URL")); m_refActionGroup->add( Gtk::Action::create("FileRefreshLibraries", Gtk::Stock::REFRESH, "_Refresh Libraries"), sigc::mem_fun(*this, &MainWindow::on_menu_file_refresh)); m_refActionGroup->add(Gtk::Action::create("FileClose", Gtk::Stock::CLOSE), sigc::mem_fun(*this, &MainWindow::on_menu_file_close)); m_refActionGroup->add(Gtk::Action::create("FileQuit", Gtk::Stock::QUIT), sigc::mem_fun(*this, &MainWindow::on_menu_file_quit)); m_refActionGroup->add(Gtk::Action::create("ViewMenu", "_View")); m_refActionGroup->add(Gtk::ToggleAction::create("ViewBrowser", "_Browser Pane"), sigc::mem_fun(*this, &MainWindow::on_view_library_pane)); m_refActionGroup->add(Gtk::Action::create("ViewFullscreen", "_Fullscreen")); m_refActionGroup->add(Gtk::Action::create("PlaybackMenu", "_Playback")); m_refActionGroup->add(Gtk::Action::create("PlayPause", Gtk::Stock::MEDIA_PLAY), sigc::mem_fun(*this, &MainWindow::on_play)); m_refActionGroup->add(Gtk::Action::create("PreviousTrack", Gtk::Stock::MEDIA_PREVIOUS), sigc::ptr_fun(&PlaybackManager::prev)); m_refActionGroup->add(Gtk::Action::create("NextTrack", Gtk::Stock::MEDIA_NEXT), sigc::ptr_fun(&PlaybackManager::next)); m_refActionGroup->add(Gtk::ToggleAction::create("PlaybackStopWhenFinished", "Stop When _Finished")); Gtk::RadioButtonGroup repeatGroup; m_refActionGroup->add(Gtk::Action::create("RepeatMenu", "_Repeat")); m_refActionGroup->add(Gtk::RadioAction::create(repeatGroup, "RepeatOff", "Repeat _Off")); m_refActionGroup->add(Gtk::RadioAction::create(repeatGroup, "RepeatAll", "Repeat _All")); m_refActionGroup->add(Gtk::RadioAction::create(repeatGroup, "RepeatSingle", "Repeat _Single")); Gtk::RadioButtonGroup shuffleGroup; m_refActionGroup->add(Gtk::Action::create("ShuffleMenu", "_Shuffle")); m_refActionGroup->add( Gtk::RadioAction::create(shuffleGroup, "ShuffleOff", "Shuffle _Off"), sigc::bind(sigc::mem_fun(*this, &MainWindow::set_shuffle), SHUFFLE_NONE)); m_refActionGroup->add( Gtk::RadioAction::create(shuffleGroup, "ShuffleBySong", "Shuffle _All"), sigc::bind(sigc::mem_fun(*this, &MainWindow::set_shuffle), SHUFFLE_ALL)); m_refActionGroup->add( Gtk::RadioAction::create(shuffleGroup, "ShuffleByArtist", "Shuffle By _Artist"), sigc::bind(sigc::mem_fun(*this, &MainWindow::set_shuffle), SHUFFLE_ARTIST)); m_refActionGroup->add( Gtk::RadioAction::create(shuffleGroup, "ShuffleByAlbum", "Shuffle By Al_bum"), sigc::bind(sigc::mem_fun(*this, &MainWindow::set_shuffle), SHUFFLE_ALBUM)); m_refActionGroup->add(Gtk::Action::create("HelpMenu", "_Help")); m_refActionGroup->add(Gtk::Action::create("HelpAbout", Gtk::Stock::ABOUT)); m_refActionGroup->add(Gtk::Action::create("NextTrackMenu", "_Shufflee")); m_refUIManager = Gtk::UIManager::create(); m_refUIManager->insert_action_group(m_refActionGroup); add_accel_group(m_refUIManager->get_accel_group()); Glib::ustring ui_info = "<ui>" " <menubar name='MenuBar'>" " <menu action='FileMenu'>" " <menuitem action='FileNewPlaylist'/>" " <menuitem action='FileNewSmartPlaylist'/>" " <separator/>" " <menuitem action='FileOpen'/>" " <menuitem action='FileOpenURL'/>" " <separator/>" " <menuitem action='FileRefreshLibraries'/>" " <separator/>" " <menuitem action='FileClose'/>" " <menuitem action='FileQuit'/>" " </menu>" " <menu action='ViewMenu'>" " <menuitem action='ViewBrowser'/>" " <menuitem action='ViewFullscreen'/>" " </menu>" " <menu action='PlaybackMenu'>" " <menuitem action='PlayPause'/>" " <menuitem action='NextTrack'/>" " <menuitem action='PreviousTrack'/>" " <separator/>" " <menuitem action='PlaybackStopWhenFinished'/>" " <menu action='RepeatMenu'>" " <menuitem action='RepeatOff'/>" " <separator/>" " <menuitem action='RepeatAll'/>" " <menuitem action='RepeatSingle'/>" " </menu>" " <menu action='ShuffleMenu'>" " <menuitem action='ShuffleOff'/>" " <separator/>" " <menuitem action='ShuffleBySong'/>" " <menuitem action='ShuffleByArtist'/>" " <menuitem action='ShuffleByAlbum'/>" " </menu>" " </menu>" " <menu action='HelpMenu'>" " <menuitem action='HelpAbout'/>" " </menu>" " </menubar>" " <toolbar name='Toolbar'>" " <toolitem action='PreviousTrack'/>" " <toolitem action='PlayPause'/>" " </toolbar>" " <popup name='StatusIconPopup'>" " <menuitem action='PlayPause'/>" " <menuitem action='PreviousTrack'/>" " <menuitem action='NextTrack'/>" " <separator/>" " <menuitem action='FileQuit'/>" " </popup>" " <popup name='NextTrackPopup'>" " <menuitem action='ShuffleOff'/>" " <separator/>" " <menuitem action='ShuffleBySong'/>" " <menuitem action='ShuffleByArtist'/>" " <menuitem action='ShuffleByAlbum'/>" " </popup>" "</ui>"; m_refUIManager->add_ui_from_string(ui_info); } void MainWindow::init_main_vbox() { Gtk::Box* pMainVBox = Gtk::manage(new Gtk::VBox()); add(*pMainVBox); // Add menu Gtk::Widget* pMenuBar = m_refUIManager->get_widget("/MenuBar"); pMainVBox->pack_start(*pMenuBar, Gtk::PACK_SHRINK); // Add toolbar Gtk::Toolbar* pToolbar = static_cast<Gtk::Toolbar*>(m_refUIManager->get_widget("/Toolbar")); pToolbar->set_toolbar_style(Gtk::TOOLBAR_ICONS); Gtk::MenuToolButton* pNextTrackButton = Gtk::manage(new Gtk::MenuToolButton()); m_refActionGroup->get_action("NextTrack")->connect_proxy(*pNextTrackButton); //Gtk::MenuItem* pShuffleMenu = static_cast<Gtk::MenuItem*>( // m_refUIManager->get_widget("/MenuBar/ShuffleMenu")); Gtk::Menu* pShuffleMenu = static_cast<Gtk::Menu*>( m_refUIManager->get_widget("/NextTrackPopup")); pNextTrackButton->set_menu(*pShuffleMenu); pToolbar->append(*pNextTrackButton); pToolbar->append(*Gtk::manage(new Gtk::SeparatorToolItem())); // TODO when track titles are too long this doesn't work Gtk::ToolItem* pTrackInfoItem = Gtk::manage(new Gtk::ToolItem()); TrackInfoPane* pInfoPane = new TrackInfoPane(); // TODO destroy this somewhere pTrackInfoItem->add(*pInfoPane); pTrackInfoItem->set_expand(true); pToolbar->append(*pTrackInfoItem); pToolbar->append(*Gtk::manage(new Gtk::SeparatorToolItem())); Gtk::ToolItem* pScaleToolItem = Gtk::manage(new Gtk::ToolItem()); TrackSlider* track_slider = Gtk::manage(new TrackSlider()); // TODO is this properly destroyed? pScaleToolItem->add(*track_slider); pScaleToolItem->set_expand(true); pToolbar->append(*pScaleToolItem); pToolbar->append(*Gtk::manage(new Gtk::SeparatorToolItem())); //Gtk::ToolItem* pVolumeToolItem = Gtk::manage(new Gtk::ToolItem()); //Gtk::VolumeButton* pVolumeButton = Gtk::manage(new Gtk::VolumeButton()); Gtk::ToolButton* pVolumeButton = Gtk::manage(new Gtk::ToolButton(Gtk::Stock::EXECUTE)); pToolbar->append(*pVolumeButton); pMainVBox->pack_start(*pToolbar, Gtk::PACK_SHRINK); // Add main HPaneds Gtk::VBox* sources_pane_vbox = Gtk::manage(new Gtk::VBox()); sources_pane_vbox->pack_start(m_sources_pane, Gtk::PACK_EXPAND_WIDGET); sources_pane_vbox->pack_start(m_progress_pane, Gtk::PACK_SHRINK); Gtk::HPaned* browser_pane_sizer = Gtk::manage(new Gtk::HPaned()); browser_pane_sizer->add1(m_browser_pane); browser_pane_sizer->add2(m_tab_pane); browser_pane_sizer->set_position(200); Gtk::HPaned* main_pane_sizer = Gtk::manage(new Gtk::HPaned()); main_pane_sizer->add1(*sources_pane_vbox); main_pane_sizer->add2(*browser_pane_sizer); main_pane_sizer->set_position(160); pMainVBox->pack_start(*main_pane_sizer, Gtk::PACK_EXPAND_WIDGET, 2); // Add statusbar Gtk::Statusbar* pStatusbar = Gtk::manage(new Gtk::Statusbar()); pMainVBox->pack_end(*pStatusbar, Gtk::PACK_SHRINK); } void MainWindow::set_shuffle(ShuffleType type) { PlaybackManager::set_shuffle(type); if (type != SHUFFLE_NONE) { // TODO reactivate this after upgrading gtkmm, okay it didn't work //m_refActionGroup->get_action("NextTrack")->property_icon_name().set_value( // Glib::ustring("media-playlist-shuffle")); //cout << "shuffle: " << endl; //Glib::RefPtr<Gdk::Pixbuf> icon = Gtk::IconTheme::get_default()->load_icon( // "media-playlist-shuffle", 24); //Glib::RefPtr<Gtk::Action> action = m_refActionGroup->get_action("NextTrack"); //action->property_stock_id(); //m_refActionGroup->get_action("NextTrack")->set_property("icon-name", // Glib::ustring("media-playlist-shuffle")); } //cout << "shuffle: " << shuffle_all << shuffle_artists << shuffle_albums << endl; } void MainWindow::on_play() { if (PlaybackManager::is_paused()) { PlaybackManager::unpause(); } else { PlaybackManager::pause(); } // TODO this will crash if we click play without previously pausing something } void MainWindow::on_media_stopped(PlaySourceRef playlist, int index, bool is_paused) { Glib::RefPtr<Gtk::Action>::cast_static( m_refActionGroup->get_action("PlayPause"))->property_stock_id().set_value(Gtk::Stock::MEDIA_PLAY); } void MainWindow::on_media_started(PlaySourceRef playlist, int index, bool was_paused) { Glib::RefPtr<Gtk::Action>::cast_static( m_refActionGroup->get_action("PlayPause"))->property_stock_id().set_value(Gtk::Stock::MEDIA_PAUSE); } void MainWindow::on_menu_file_quit() { Gtk::Main::quit(); } void MainWindow::on_menu_file_close() { hide(); } void MainWindow::on_menu_file_refresh() { m_progress_pane.show(); for (std::vector<LibraryRef>::const_iterator iter = Database::get_libraries().begin(); iter != Database::get_libraries().end(); iter++) { m_progress_pane.set_main_text(Glib::ustring::compose("Refreshing '%1'...", (*iter)->get_name())); sigc::connection con = (*iter)->signal_refesh_pulse().connect( sigc::mem_fun(m_progress_pane, &ProgressPane::pulse)); (*iter)->refresh(); con.disconnect(); } m_progress_pane.hide(); } void MainWindow::on_status_icon_click() { if(is_visible()) { hide(); } else { show(); } } void MainWindow::on_status_icon_popup(guint button, guint32 time) { Gtk::Menu* pMenu = static_cast<Gtk::Menu*>( m_refUIManager->get_widget("/StatusIconPopup")); m_refStatusIcon->popup_menu_at_position(*pMenu, button, time); } void MainWindow::show_libnotify_popup(PlaySourceRef playlist, int index, bool was_paused) { // TODO the tooltip that this sets for the status icon doesn't get unset when a song isn't playing // TODO when the mouse keeps the linotify popup open and the song stops, is there a way to close // the popup if another song isn't about to play? // TODO this should only pop up if the user has not manually started a track const Glib::ustring& summary = playlist->get_track(index)->get_title(); // TODO this body doesn't display in the popup if it contains a unicode character (i.e. Tiesto) Glib::ustring body = Glib::ustring::compose("by <i>%1</i> from <i>%2</i>", playlist->get_track(index)->get_artist(), playlist->get_track(index)->get_album()); m_refStatusIcon->set_tooltip( playlist->get_track(index)->get_title() + "\nby " + playlist->get_track(index)->get_artist() + " from " + playlist->get_track(index)->get_album()); if (!m_notify) { m_notify = notify_notification_new_with_status_icon( summary.c_str(), body.c_str(), NULL, m_refStatusIcon->gobj()); notify_notification_add_action(m_notify, "previous", "Previous", &MainWindow::libnotify_action_callback, NULL, NULL); notify_notification_add_action(m_notify, "next", "Next", &MainWindow::libnotify_action_callback, NULL, NULL); } else notify_notification_update(m_notify, summary.c_str(), body.c_str(), NULL); notify_notification_show(m_notify, NULL); // TODO do something with the libnotify error? } void MainWindow::libnotify_action_callback( NotifyNotification* notify, gchar* action_id, gpointer user_data) { if (Glib::ustring(action_id) == "previous") PlaybackManager::prev(); else PlaybackManager::next(); } void MainWindow::on_view_library_pane() { bool show_library = Glib::RefPtr<Gtk::ToggleAction>::cast_static( m_refActionGroup->get_action("ViewBrowser"))->get_active(); if (show_library) { m_browser_pane.show(); } else { m_browser_pane.hide(); } }