Logo Search packages:      
Sourcecode: zinf version File versions  Download package

gtkmusicbrowser.cpp

#include <assert.h>
#include <stdlib.h>
#include <string>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <gtkmm/stock.h>

using namespace std;

#include "gtkmusicbrowser.h"
#include "playlist.h"
#include "facontext.h"
#include "player.h"
#include "dialogs.h"
#include "musicbrowserui.h"
#include "utility.h"
#include "config.h"
#include "infoeditor.h"

#include "../res/add_track.xpm"
#include "../res/edit_pic.xpm"
#include "../res/catalog_pix.xpm"
#include "../res/import_pic.xpm"

GTKBrowserMusic::GTKBrowserMusic(FAContext *context, MusicBrowser *masterUI, std::string PlaylistURL, bool isMaster)
    : m_menubar(this)
{
      assert(context);
      assert(masterUI);

      //Init Internal Variables
      m_context = context;
      m_parentUI = masterUI;
      m_playlistPath = PlaylistURL;
      m_initialized = false;
      close_doing_hide = false;
      m_isMaster = isMaster;
      
      created_plm = NULL;
      m_layout = NULL;
      m_bookPlaylists = NULL;
      m_treeLibrary = NULL;
      m_toolbar = NULL;
      m_filedialog = NULL;
      
      //Create Pixbufs
      m_add_track_pic = Gdk::Pixbuf::create_from_xpm_data(add_track_pic);
      m_edit_pic = Gdk::Pixbuf::create_from_xpm_data(edit_pic);
      m_catalog_pic = Gdk::Pixbuf::create_from_xpm_data(catalog_pix);
      m_import_files_pic = Gdk::Pixbuf::create_from_xpm_data(import_pic);
      
      ReadPrefs();

      //Get A Playlist Manager To Use
      if(m_isMaster) {
            m_plm = m_context->plm;
            if(Save_Current_Playlist_On_Exit) {
                  int32_t SavedPosition;
                  m_plm->ReadPlaylist(PlaylistURL.c_str());
                  m_context->prefs->GetPrefInt32(kSavedPlaylistPositionPref, &SavedPosition);
                  m_plm->SetCurrentIndex(SavedPosition);
            }
    }
    else {
            //Create New Playlist Manager
            m_plm = new PlaylistManager(m_context);
            m_plm->SetActivePlaylist(kPlaylistKey_ExternalPlaylist);
            created_plm = m_plm;

            //Open Playlist If Any
            if(PlaylistURL.length() > 0)
                  m_plm->ReadPlaylist(PlaylistURL.c_str());
    }
    
      //Set Default Size
      //TODO: Read Size/Position From Prefrences
      set_default_size(400, 300);
}

GTKBrowserMusic::~GTKBrowserMusic()
{
      //Delete Created Objects
      delete created_plm;
      delete m_layout;
      delete m_bookPlaylists;
      delete m_treeLibrary;
      delete m_toolbar;
      delete m_filedialog;
}

void GTKBrowserMusic::ReadPrefs()
{
      m_context->prefs->GetPrefBoolean(kSaveCurrentPlaylistOnExitPref, Save_Current_Playlist_On_Exit);
      //Get Display Mode
      if(m_layout) {
            m_layout->read_prefs();
            m_layout->change_layout();
      }
}

void GTKBrowserMusic::ShowMusicBrowser()
{
    gdk_threads_enter();

      if(m_initialized) {
            show();
            gdk_threads_leave();
        return;
    }

      //Create Child Widgets That Are Always Needed
      m_layout = new MusicLayout(m_context->prefs);
      
      //Set Which Widgets To Display
      ChangeDisplayMode();

      //Show Window
      add(*m_layout);
      show_all();

      m_initialized = true;

      //Highlight Current Index In Playlist
      m_bookPlaylists->CheckCurrentIndex();
      
      gdk_threads_leave();
}


Error GTKBrowserMusic::AcceptEvent(Event* event)
{
      Error returnval = kError_NoErr;
      gdk_threads_enter();

      switch(event->Type()) {
            case INFO_PlaylistCurrentItemInfo:
            case INFO_PlaylistUpdated:
            case INFO_PlaylistItemsUpdated:
                  if(m_bookPlaylists)     returnval = m_bookPlaylists->AcceptEvent(event);
                  break;
            case INFO_PlaylistItemsAdded:
            case INFO_PlaylistItemAdded:
                  if(m_bookPlaylists) {
                        StatusText("Adding files...", 1);
                        UpdateGUI();
                        returnval = m_bookPlaylists->AcceptEvent(event);
                        StatusText("Files added", 1);
                  }
                  break;
            case INFO_PlaylistItemRemoved:
                  if(m_bookPlaylists) {
                        StatusText("Removing files...", 1);
                        UpdateGUI();
                        returnval = m_bookPlaylists->AcceptEvent(event);
                        StatusText("Files removed", 1);
                  }
                  break;
            case INFO_PlaylistItemMoved:
                  if(m_bookPlaylists) {
                        returnval = m_bookPlaylists->AcceptEvent(event);
                        StatusText("Playlist item(s) moved", 1);
                  }
                  break;
            case INFO_PlaylistSorted:
                  if(m_bookPlaylists) {
                        returnval = m_bookPlaylists->AcceptEvent(event);
                        StatusText("Playlist sorted", 1);
                  }
                  break;

            case INFO_PrefsChanged:
                  if(m_bookPlaylists)     m_bookPlaylists->AcceptEvent(event);
                  if(m_treeLibrary) m_treeLibrary->AcceptEvent(event);
                  ReadPrefs();
                  break;

        default:
                  if(m_bookPlaylists) m_bookPlaylists->AcceptEvent(event);
                  if(m_treeLibrary) m_treeLibrary->AcceptEvent(event);
            break;
    }

      gdk_threads_leave();
      return returnval;
}

void GTKBrowserMusic::on_hide()
{
      gdk_threads_leave();
      if(close_doing_hide || Close(true, false)) {
            gdk_threads_enter();    
            Gtk::Window::on_hide();
            gdk_threads_leave();
      }
      gdk_threads_enter();
      
}

bool GTKBrowserMusic::Close(bool in_Main, bool hide_self, bool force)
{
      gdk_threads_enter();

      //Close Open Tabs
      if(m_bookPlaylists) {
            int playlist_num;
            for(playlist_num = (m_bookPlaylists->get_n_pages() - 1); playlist_num > 0; playlist_num--) {
                  if(!CheckClosePlaylist(playlist_num, !force, in_Main)) {
                        //Playlist Wasn't Closed - So Bail Out
                        gdk_threads_leave();
                        return false;
                  }
            }
      }
      //Save Master Playlist
      if(m_isMaster && Save_Current_Playlist_On_Exit)
            m_context->plm->WritePlaylist(m_playlistPath.c_str());
      
      //Hide Window
      if(hide_self) {
            close_doing_hide = true;
            hide();
            close_doing_hide = false;
      }
      
      gdk_threads_leave();
      
      return true;
}

void GTKBrowserMusic::ChangeDisplayMode()
{
      assert(m_layout);
      
      //Get Which Widgets Are Needed
      m_layout->read_prefs();
      
      /*Create Needed Widgets
        Destory Not Needed Widgets
        Set Layout Widgets*/
      if(m_layout->need_menubar()) {
        m_layout->set_menubar(&m_menubar);
    }


      if(m_layout->need_toolbar()) {
            if(!m_toolbar)
                  m_toolbar = new GTKToolbar(this);
            m_toolbar->set_layout(m_layout);
            m_layout->set_toolbar(m_toolbar);
      } else {
            delete m_toolbar;
            m_toolbar = NULL;
      }


      
      if(m_layout->need_playlist()) {
            if(!m_bookPlaylists)
                  m_bookPlaylists = new GTKPlaylistNotebook(m_context, m_plm, this);
            m_bookPlaylists->set_layout(m_layout);
            m_layout->set_playlist(m_bookPlaylists);
      } else {
            delete m_bookPlaylists;
            m_bookPlaylists = NULL;
      }
      
      if(m_layout->need_status_bar()) {
            m_layout->set_status_bar(&m_StatusBar);
      }
      
      if(m_layout->get_library_displayed()) {
            if(!m_treeLibrary)
                  m_treeLibrary = new GTKLibrary(m_context, m_plm, this);
            //Get Library To Fill In Widgets
            m_treeLibrary->set_layout(m_layout);
      } else {
            delete m_treeLibrary;
            m_treeLibrary = NULL;
      }
      
      //Refresh Layout
      m_layout->change_layout();
}

void GTKBrowserMusic::SetCurrentPLM(PlaylistManager *plm)
{
      assert(plm);

      m_plm = plm;
      if(m_treeLibrary) m_treeLibrary->SetPLM(plm);
}

void GTKBrowserMusic::StartPlaying(bool set_index, uint32_t playlist_index)
{
      if(m_isMaster && (m_plm->GetActivePlaylist() == kPlaylistKey_MasterPlaylist)) {
            //Restart playback with new index
            m_context->target->AcceptEvent(new Event(CMD_Stop));
            if(set_index)
                  m_plm->SetCurrentIndex(playlist_index);
            m_context->target->AcceptEvent(new Event(CMD_Play));
    }
}

void GTKBrowserMusic::AddFromLibrary()
{
      if(m_treeLibrary) {
            m_treeLibrary->DoAddTrack();
      }
}

void GTKBrowserMusic::AddFiles()
{
      //Reset Dialog
      delete m_filedialog;
      m_filedialog = new MusicFileSelector(m_context);
      
      //Set Up Dialog
      m_filedialog->set_title("Add files to playlist:");
      m_filedialog->set_select_multiple(true);
      m_filedialog->signal_response().connect( SigC::slot(*this, &GTKBrowserMusic::on_add_files_response) );
      
      //Show Dialog (non-blocking)
      m_filedialog->show();
}

void GTKBrowserMusic::on_add_files_response(int response)
{
      //Hide Dialog
      m_filedialog->hide();
      
      //Check User Selected A File
      if( (response == Gtk::RESPONSE_OK) && !(m_filedialog->get_selections().empty()) ) {
            std::vector<std::string> files;
            std::vector<std::string>::iterator file;
            std::vector<std::string> urls;
            
            //Convert File Paths To URLs, If Valid Tracks
            files = m_filedialog->get_selections();
            for(file = files.begin(); file != files.end(); file++) {
                  char *extension;
                  extension = m_context->player->GetExtension((*file).c_str());
                  if(extension) {
                        //Could Be Valid Track or Playlist
                        if(m_context->player->IsSupportedExtension(extension)) {
                              //Valid Track
                              std::string url;
                              FilePathToURL((*file).c_str(), url);
                              urls.push_back(url);
                        }
                        delete extension;
                  }
            }
            
            //Add URLs To Playlist
            m_plm->AddItems(urls);
        m_plm->insert(m_plm->end(), urls.begin(), urls.end());
      }
}

void GTKBrowserMusic::ImportFiles()
{
      //Reset Dialog
      delete m_filedialog;
      m_filedialog = new MusicFileSelector(m_context);
      
      //Set Up Dialog
      m_filedialog->set_title("Import files into library:");
      m_filedialog->set_select_multiple(true);
      m_filedialog->signal_response().connect( SigC::slot(*this, &GTKBrowserMusic::on_import_files_response) );
      
      //Show Dialog (non-blocking)
      m_filedialog->show();
}

void GTKBrowserMusic::on_import_files_response(int response)
{
      //Hide Dialog
      m_filedialog->hide();
      
      //Check User Selected A File
      if( (response == Gtk::RESPONSE_OK) && !(m_filedialog->get_selections().empty()) ) {
            std::vector<std::string> files;
            std::vector<std::string>::iterator file;
            std::string url;
            std::vector<std::string> track_urls, playlist_urls;
            
            //Convert File Paths To URLs after checking they are valid files
            files = m_filedialog->get_selections();
            for(file = files.begin(); file != files.end(); file++) {
                  char *extension; //Can't Use std::string, as GetExtension may return NULL
                  extension = m_context->player->GetExtension((*file).c_str());
                  if(extension) { 
                        //Is A Either A Supported Track, or Playlist
                        FilePathToURL((*file).c_str(), url);
                        if(m_plm->IsSupportedPlaylistFormat(extension)) {
                              //Is Supported Playlist
                              playlist_urls.push_back(url);
                        } else {
                              //Is Supported Track
                              track_urls.push_back(url);
                        }
                        delete extension;
                  }
            }
            
            //Add Valid Files To Library
            for(file = track_urls.begin(); file != track_urls.end(); file++)
                  m_context->catalog->AddSong((*file).c_str());
            
            for(file = playlist_urls.begin(); file != playlist_urls.end(); file++)
                  m_context->catalog->AddPlaylist((*file).c_str());
      }
}

void GTKBrowserMusic::EditTrack()
{
      if(m_bookPlaylists && m_bookPlaylists->has_focus())
            m_bookPlaylists->DoEditTrack();
      if(m_treeLibrary && m_treeLibrary->has_focus())
            m_treeLibrary->DoEditTrack();
}

void GTKBrowserMusic::TracksToEdit(std::vector<PlaylistItem *> *Tracks)
{
      infoeditor *TagEditor;

      //Set Tracks To Edit - infoeditor will delete vector
      TagEditor = new infoeditor(m_context, m_plm, Tracks);
      
      //Show Editor
      TagEditor->DisplayInfo();
}

void GTKBrowserMusic::TracksToEdit(std::vector<std::string> *URLs)
{
      //Assumes All URLs Are Cached In Catalog
      std::vector<PlaylistItem *> *Tracks;
      Tracks = new std::vector<PlaylistItem *>;
      
      std::vector<std::string>::iterator url;
      for(url = URLs->begin(); url != URLs->end(); url++) {
            Tracks->push_back(m_context->catalog->GetPlaylistItemFromURL((*url).c_str()));
      }
      
      TracksToEdit(Tracks);
}

void GTKBrowserMusic::RemoveFromPlaylist()
{
      m_bookPlaylists->DoRemove();
}

void GTKBrowserMusic::NewPlaylist()
{
      if(m_layout->get_tab_position() == -1) { //Tabs Turned Off
            //Open New Window
            std::string newfilename = "";
            m_parentUI->CreateNewEditor(newfilename, false);
      } else {
            //Open New Tab
            m_bookPlaylists->NewPlaylist();
            StatusText("New playlist created", 1);
    }
}

void GTKBrowserMusic::OpenPlaylist(std::string URL)
{
      bool editplaylist = true;
      
      std::string Filename;
      if(URL.length() > 0) {
            Filename = URL;
      } else {
            MusicFileSelector FileDialog(m_context, "Open Playlist:");
            //Create Option to either play or edit playlist
            Gtk::RadioButton editoption("Edit playlist");
            Gtk::RadioButton_Helpers::Group optiongroup = editoption.get_group();
            Gtk::RadioButton playoption(optiongroup, "Play playlist");
            Gtk::HBox optionarea;
            editoption.set_active(true);
            optionarea.pack_start(editoption);
            optionarea.pack_start(playoption);
            optionarea.show_all();
            
            //Add To Dialog
            FileDialog.get_main_vbox()->pack_end(optionarea);
            
            //Show Dialog
            if(FileDialog.run() == Gtk::RESPONSE_OK) {
                  FilePathToURL(FileDialog.get_filename().c_str(), Filename);
                  if(playoption.get_active()) {
                        //Don't Edit Playlist
                        editplaylist = false;
                  }
            } else 
                  Filename = "";
      }
      
      if((Filename.length() > 0) && editplaylist) {
            if(m_layout->get_tab_position() != -1) { //Tabs Turned On
                  //Open New Tab
                  m_bookPlaylists->OpenPlaylist(Filename);
                  StatusText("Playlist \"" + Filename + "\" loaded", 1);
      }
      else {
                  //Open New Window
                  m_parentUI->CreateNewEditor(Filename, false);
        }
    } else if(Filename.length() > 0) {
            //Replace Current Playlist
            m_context->plm->RemoveAll();
            m_context->plm->ReadPlaylist(Filename.c_str());
            m_context->target->AcceptEvent(new Event(CMD_Stop));
            m_context->target->AcceptEvent(new Event(CMD_Play));
            m_bookPlaylists->set_current_page(0); //Display Main Playlist
      }
}

void GTKBrowserMusic::SavePlaylist(int playlist_num, bool in_main)
{
      if(m_bookPlaylists)     m_bookPlaylists->SavePlaylist(playlist_num, in_main);
}

void GTKBrowserMusic::ClosePlaylist(int playlist_num)
{
      if(m_bookPlaylists && CheckClosePlaylist(playlist_num))
            m_bookPlaylists->ClosePlaylist(playlist_num);
}

bool GTKBrowserMusic::CheckClosePlaylist(int playlist_num, bool allow_cancel, bool in_main)
{
      bool return_val = false;
      
      if(m_bookPlaylists && !m_bookPlaylists->CheckClosePlaylist(playlist_num)) {
            //Create Message Dialog
            MusicMessageDialog Dialog("Do you want to save your changes to " + m_bookPlaylists->get_tab_label_text(playlist_num), Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO);
            if(allow_cancel) {
                  Dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
                  Dialog.set_default_response(Gtk::RESPONSE_CANCEL);
            } else {
                  Dialog.set_default_response(Gtk::RESPONSE_YES);
            }
            //Make Sure Tab Is Displayed
            m_bookPlaylists->show_page(playlist_num);
            show();
            //Show Message Dialog
            switch(Dialog.run(in_main)) {
        case Gtk::RESPONSE_YES:
            SavePlaylist(playlist_num, in_main);
        case Gtk::RESPONSE_NO:
            return_val = true;
            m_bookPlaylists->SetCanClosePlaylist(playlist_num);
            break;
                  
        case Gtk::RESPONSE_CANCEL:
            return_val = false;
            break;
            }
      } else
            return_val = true;
      
      return return_val;
}

void GTKBrowserMusic::SavePlaylistAs(int playlist_num, bool in_main)
{
      if(!m_bookPlaylists) //Make Sure We Have A Playlist To Save
            return;
      
      //Get Filename
      MusicInputDialog FilenameDialog("Save Playlist As:", "Please enter a name to save the playlist as:");
      FilenameDialog.set_entry_text(m_bookPlaylists->get_tab_label_text(playlist_num));
      if(FilenameDialog.run(in_main) == Gtk::RESPONSE_OK) {
            std::string filename = FilenameDialog.get_entry_text();
            std::string url;
            //Add Zinf File Path, And Valid Playlist Extension To Name
            char *zinf_dir = ZinfDir(m_context->prefs);
            PlaylistFormatInfo valid_playlist;
            m_plm->GetSupportedPlaylistFormats(&valid_playlist, 0);
            filename = string(zinf_dir) + DIR_MARKER_STR + filename + "." + string(valid_playlist.GetExtension());
            FilePathToURL(filename.c_str(), url);
            delete zinf_dir;
            //Save Playlist
            m_bookPlaylists->SavePlaylistAs(url, playlist_num);
            StatusText("Playlist saved as \"" + url + "\"", 1);
            //Add Playlist To Library
            m_context->catalog->AddPlaylist(url.c_str());
      }
}

void GTKBrowserMusic::RevertToSavedPlaylist(int playlist_num)
{
      if(m_bookPlaylists) m_bookPlaylists->RevertToSavedPlaylist(playlist_num);
      StatusText("Playlist reloaded", 1);
}

void GTKBrowserMusic::UpdateGUI()
{
      //TODO: Get This To Actually Work, Instead Of Look Like It Should
      gdk_threads_leave();
      
      //Get MainContext And Process All Events
      Glib::RefPtr< Glib::MainContext > gtk_events = Glib::MainContext::get_default();
      
      while(gtk_events->pending()) {
            gtk_events->iteration(false);
      }
      
      gdk_threads_enter();
      gdk_flush();
}

void GTKBrowserMusic::ClearPlaylist(int playlist_num)
{
      if(m_bookPlaylists) m_bookPlaylists->ClearPlaylist(playlist_num);
      StatusText("Playlist cleared", 1);
}

void GTKBrowserMusic::StatusText(Glib::ustring NewText, uint32_t Pane)
{
      
      switch(Pane) {
            case 1:
                  m_StatusBar.SetText1(NewText);
                  //Clear Text After 30 seconds
                  m_TimeoutSignal.disconnect();
                  m_TimeoutSignal = Glib::signal_timeout().connect( SigC::slot(*this, &GTKBrowserMusic::TimedClearStatusText), 30000);
                  break;
        
            case 2:
                  m_StatusBar.SetText2(NewText);
                  break;
    }
}

bool GTKBrowserMusic::TimedClearStatusText()
{
      m_StatusBar.SetText1("");
      return false;
}

void GTKBrowserMusic::UpdateListTime()
{
      ostringstream Text;
      uint32_t Hours, Minutes, Seconds;
      Seconds = m_plm->Time();
      Hours = Seconds / 3600;
      Minutes = (Seconds % 3600) / 60;
      Seconds = Seconds % 60;
      Text << "Playlist Length: ";
      if(Hours > 0) {
            Text << Hours << ":";
    }
      Text << setw(2) << setfill('0') << Minutes << ":" << setw(2) << setfill('0') << Seconds;
      StatusText(Text.str(), 2);
}

void GTKBrowserMusic::SearchMusic(const string&path)
{
    m_context->collection->searchPath(path);
}


/* arch-tag: 0a605564-cec8-4fc7-b2ae-33b75a1625e4 */

Generated by  Doxygen 1.6.0   Back to index