/* * Copyright 2014 (c) Anna Schumaker. */ #include #include #include #include #include #include #include static std::map queue_mapping; static sort_t sort_fields[] = { SORT_TRACK, SORT_TITLE, SORT_LENGTH, SORT_ARTIST, SORT_ALBUM, SORT_YEAR, SORT_GENRE, SORT_COUNT, SORT_PLAYED }; /** * * Tab class basics * */ Tab :: Tab(Queue *pq) : tab_sorting_count(0), tab_pq(pq), tab_size(NULL) { tab_model = Glib::RefPtr(new QueueModel(tab_pq)); queue_mapping[tab_pq] = this; } Tab :: ~Tab() {} void Tab :: tab_finish_init() { tab_filter = Gtk::TreeModelFilter::create(tab_model); tab_filter->set_visible_func(sigc::mem_fun(*this, &Tab::on_filter_visible)); tab_search->signal_key_release_event().connect(sigc::mem_fun(*this, &Tab::on_entry_key_released)); tab_search->signal_changed().connect(sigc::mem_fun(*this, &Tab::on_entry_changed)); tab_treeview->set_model(tab_filter); tab_treeview->signal_row_activated().connect(sigc::mem_fun(*this, &Tab :: on_row_activated)); tab_treeview->signal_key_press_event().connect(sigc::mem_fun(*this, &Tab :: on_key_pressed)); tab_treeview->signal_button_press_event().connect(sigc::mem_fun(*this, &Tab :: on_button_pressed), false); std::vector columns = tab_treeview->get_columns(); for (unsigned int i = 0; i < columns.size(); i++) { columns[i]->signal_clicked().connect(sigc::bind ( sigc::mem_fun(*this, &Tab::on_column_clicked), i)); } } /** * * Tab internal helper functions * */ void Tab :: tab_init_random() { tab_random->set_active(tab_pq->has_flag(Q_RANDOM)); tab_random->signal_toggled().connect(sigc::mem_fun(*this, &Tab::on_random_toggled)); } void Tab :: tab_init_repeat() { tab_repeat->set_active(tab_pq->has_flag(Q_REPEAT)); tab_repeat->signal_toggled().connect(sigc::mem_fun(*this, &Tab::on_repeat_toggled)); } void Tab :: tab_toggle_button(Gtk::ToggleButton *button, queue_flags flag) { if (button->get_active()) tab_pq->set_flag(flag); else tab_pq->unset_flag(flag); } int Tab :: tab_page_num() { Gtk::Notebook *notebook = get_widget("o_notebook"); return notebook->page_num(*tab_widget); } bool Tab :: tab_is_cur() { Gtk::Notebook *notebook = get_widget("o_notebook"); return notebook->page_num(*tab_widget) == notebook->get_current_page(); } void Tab :: tab_runtime_changed() { if (tab_is_cur()) get_widget("o_queue_time")->set_text(tab_pq->length_str()); } void Tab :: tab_display_sorting() { std::string text = ""; if ((tab_sorting_count > 0) && tab_is_cur()) text = "Sorting within " + tab_sorting_title; get_widget("o_sorting_indicator")->set_text(text); } void Tab :: tab_dec_sort_count() { tab_sorting_count--; tab_display_sorting(); } void Tab :: tab_set_size() { if (tab_size) { std::stringstream ss; ss << tab_pq->size(); tab_size->set_text(ss.str()); } } void Tab :: tab_unmap() { queue_mapping.erase(tab_pq); } void Tab :: tab_focus_search() { tab_search->grab_focus(); } void Tab :: tab_selected_ids(std::vector &ids) { Glib::RefPtr sel = tab_treeview->get_selection(); std::vector rows = sel->get_selected_rows(); Gtk::TreeModel::Path path; for (unsigned int i = 0; i < rows.size(); i++) { path = tab_filter->convert_path_to_child_path(rows[i]); ids.push_back(tab_model->path_to_id(path)); } sel->unselect_all(); } void Tab :: tab_queue_add(Queue *pq) { std::vector ids; tab_selected_ids(ids); for (unsigned int i = 0; i < ids.size(); i++) pq->add(tagdb :: lookup(ids[i])); } bool Tab :: tab_queue_selected(bool random) { if (deck :: get_queues().size() >= 10) return true; Queue *pq = deck :: create(random); on_pq_created(pq, deck :: get_queues().size() - 1); tab_queue_add(pq); return true; } bool Tab :: tab_add_to_queue(unsigned int n) { if (n >= deck :: get_queues().size()) return true; //Queue *pq = deck :: get(n); //tab_queue_add(pq); return true; } bool Tab :: tab_add_to_playlist(const std::string &playlist) { std::vector ids; tab_selected_ids(ids); for (unsigned int i = 0; i < ids.size(); i++) playlist :: add(tagdb :: lookup(ids[i]), playlist); return true; } bool Tab :: tab_favorite_selected() { return tab_add_to_playlist("Favorites"); } void Tab :: tab_ban_selected() { tab_add_to_playlist("Banned"); } /** * * Tab callback functions * */ void Tab :: on_post_init() {} void Tab :: on_track_added(unsigned int row) { tab_model->on_row_inserted(row); tab_set_size(); tab_runtime_changed(); } void Tab :: on_track_deleted(unsigned int row) { tab_model->on_row_deleted(row); tab_set_size(); tab_runtime_changed(); } void Tab :: on_track_changed(unsigned int row) { tab_model->on_row_changed(row); tab_runtime_changed(); } bool Tab :: on_key_press_event(const std::string &key) { if (key >= "0" && key <= "9") return tab_add_to_queue(atoi(key.c_str())); else if (key == "f") return tab_favorite_selected(); else if (key == "q" || key == "r") return tab_queue_selected(key == "r"); else return false; return true; } void Tab :: on_show_rc_menu() { std::string item; unsigned int size = deck :: get_queues().size(); if (size == 0) { get_widget("o_add_to_pq")->hide(); return; } get_widget("o_add_to_pq")->show(); if (size == 10) get_widget("o_new_pq")->hide(); else get_widget("o_new_pq")->show(); for (unsigned int i = 0; i < 10; i++) { item = "o_pq_"; item += '0' + i; if (i < size) get_widget(item)->show(); else get_widget(item)->hide(); } } /** * * GTK-MM callback functions * */ void Tab :: on_random_toggled() { tab_toggle_button(tab_random, Q_RANDOM); } void Tab :: on_repeat_toggled() { tab_toggle_button(tab_repeat, Q_REPEAT); } void Tab :: on_row_activated(const Gtk::TreePath &path, Gtk::TreeViewColumn *col) { Gtk::TreePath model_path = tab_filter->convert_path_to_child_path(path); tab_model->on_path_selected(model_path); } bool Tab :: on_key_pressed(GdkEventKey *event) { std::string key = gdk_keyval_name(event->keyval); if (key.size() >= 3) { if (key.substr(0, 3) == "KP_") key = key.substr(3); } return on_key_press_event(key); } void Tab :: on_column_clicked(unsigned int col) { if (tab_sorting_count == 0) { tab_sorting_title = tab_treeview->get_column(col)->get_title(); tab_pq->sort(sort_fields[col], true); } else tab_pq->sort(sort_fields[col], false); tab_sorting_count++; tab_display_sorting(); Glib::signal_timeout().connect_seconds_once( sigc::mem_fun(*this, &Tab::tab_dec_sort_count), 2); } bool Tab :: on_button_pressed(GdkEventButton *button) { if (button->button != 3) return false; Gtk::TreeModel::Path path; if (tab_treeview->get_path_at_pos(button->x, button->y, path)) tab_treeview->get_selection()->select(path); on_show_rc_menu(); get_widget("o_rc_menu")->popup(button->button, button->time); return true; } /** * * Tab filtering functions * */ bool Tab :: on_filter_visible(const Gtk::TreeIter &iter) { unsigned int pq_id; std::set::iterator it; if (tab_search->get_text_length() == 0) return true; pq_id = tab_model->iter_to_id(iter); it = visible_ids.find(tab_pq->operator[](pq_id)->id); return it != visible_ids.end(); } bool Tab :: on_entry_key_released(GdkEventKey *event) { std::string key = gdk_keyval_name(event->keyval); return key == "space"; } void Tab :: on_entry_changed() { filter :: search(tab_search->get_text(), visible_ids); tab_filter->refilter(); } /** * * Global functions * */ Tab *find_tab(Queue *pq) { std::map::iterator it; it = queue_mapping.find(pq); if (it != queue_mapping.end()) return it->second; return NULL; } static Tab *find_tab(int num) { std::map::iterator it; for (it = queue_mapping.begin(); it != queue_mapping.end(); it++) { if (it->second->tab_page_num() == num) return it->second; } return NULL; } static Tab *cur_tab() { std::map::iterator it; for (it = queue_mapping.begin(); it != queue_mapping.end(); it++) { if (it->second->tab_is_cur()) return it->second; } return NULL; } static void on_track_added(Queue *pq, unsigned int row) { Tab *tab = find_tab(pq); if (tab) tab->on_track_added(row); } static void on_track_deleted(Queue *pq, unsigned int row) { Tab *tab = find_tab(pq); if (tab) tab->on_track_deleted(row); } static void on_track_changed(Queue *pq, unsigned int row) { Tab *tab = find_tab(pq); if (tab) tab->on_track_changed(row); } static void on_switch_page(Gtk::Widget *page, int num) { Tab *tab = find_tab(num); if (tab) { tab->tab_runtime_changed(); tab->tab_display_sorting(); } else get_widget("o_queue_time")->set_text(""); } void tab_focus_search() { int page = get_widget("o_notebook")->get_current_page(); Tab *tab = find_tab(page); if (tab) tab->tab_focus_search(); } static void on_new_pq() { Tab *tab = cur_tab(); if (tab) tab->tab_queue_selected(false); } static void on_add_to_favs() { Tab *tab = cur_tab(); if (tab) tab->tab_favorite_selected(); } static void on_add_to_banned() { Tab *tab = cur_tab(); if (tab) tab->tab_ban_selected(); } static void on_add_to_queue(unsigned int n) { Tab *tab = cur_tab(); if (tab) tab->tab_add_to_queue(n); } static void init_menu_item(const std::string &pq, unsigned int n) { get_widget(pq)->signal_activate().connect( sigc::bind (sigc::ptr_fun(on_add_to_queue), n)); } void init_tabs() { struct Callbacks *cb = get_callbacks(); cb->on_queue_track_add = on_track_added; cb->on_queue_track_del = on_track_deleted; cb->on_queue_track_changed = on_track_changed; /* Notebook signals */ struct Gtk::Notebook *notebook = get_widget("o_notebook"); notebook->signal_switch_page().connect(sigc::ptr_fun(on_switch_page)); /* Menu signals */ get_widget("o_rc_menu")->show_all(); get_widget("o_new_pq")->signal_activate().connect( sigc::ptr_fun(on_new_pq)); get_widget("o_add_to_favorites")->signal_activate().connect( sigc::ptr_fun(on_add_to_favs)); get_widget("o_add_to_banned")->signal_activate().connect( sigc::ptr_fun(on_add_to_banned)); for (unsigned int i = 0; i < 10; i++) { std::string pq = "o_pq_"; pq += '0' + i; init_menu_item(pq, i); } /* Initialize other tabs */ init_collection_tab(); init_history_tab(); init_playlist_tab(); init_queue_tabs(); } void post_init_tabs() { std::map::iterator it; for (it = queue_mapping.begin(); it != queue_mapping.end(); it++) it->second->on_post_init(); unsigned int tab = 0; //for (tab = 0; tab < deck::get_queues().size(); tab++) { // if ((deck :: get(tab)->has_flag(Q_ENABLED))) // break; //} get_widget("o_notebook")->set_current_page(tab); post_init_queue_tabs(); } void cleanup_tabs() { while (queue_mapping.size() > 0) delete queue_mapping.begin()->second; }