diff --git a/livesupport/src/modules/storageClient/include/LiveSupport/Storage/StorageClientInterface.h b/livesupport/src/modules/storageClient/include/LiveSupport/Storage/StorageClientInterface.h index dfcf0ea71..1fabd7767 100644 --- a/livesupport/src/modules/storageClient/include/LiveSupport/Storage/StorageClientInterface.h +++ b/livesupport/src/modules/storageClient/include/LiveSupport/Storage/StorageClientInterface.h @@ -71,6 +71,14 @@ using namespace Core; class StorageClientInterface { public: + /** + * A virtual destructor, as this class has virtual functions. + */ + virtual + ~StorageClientInterface(void) throw () + { + } + /** * Return the version string from the storage. * @@ -635,12 +643,38 @@ class StorageClientInterface = 0; /** - * A virtual destructor, as this class has virtual functions. + * Upload an audio clip or playlist to the network hub. + * The progress of the upload process can be monitored with + * checkTransport(). + * + * @param sessionId the session ID from the authentication client. + * @param id the ID of the Playable object to be uploaded. + * @return a token which identifies this task. + * @exception XmlRpcException if there is a problem with the XML-RPC + * call. */ - virtual - ~StorageClientInterface(void) throw () - { - } + virtual Ptr::Ref + uploadToHub(Ptr::Ref sessionId, + Ptr::Ref id) + throw (XmlRpcException) + = 0; + + /** + * Download an audio clip or playlist from the network hub. + * The progress of the upload process can be monitored with + * checkTransport(). + * + * @param sessionId the session ID from the authentication client. + * @param id the ID of the Playable object to be downloaded. + * @return a token which identifies this task. + * @exception XmlRpcException if there is a problem with the XML-RPC + * call. + */ + virtual Ptr::Ref + downloadFromHub(Ptr::Ref sessionId, + Ptr::Ref id) + throw (XmlRpcException) + = 0; }; diff --git a/livesupport/src/modules/storageClient/src/TestStorageClient.cxx b/livesupport/src/modules/storageClient/src/TestStorageClient.cxx index 23ec76bca..b529751f5 100644 --- a/livesupport/src/modules/storageClient/src/TestStorageClient.cxx +++ b/livesupport/src/modules/storageClient/src/TestStorageClient.cxx @@ -1108,3 +1108,29 @@ TestStorageClient :: cancelTransport(Ptr::Ref sessionId, { } + +/*------------------------------------------------------------------------------ + * Upload an audio clip or playlist to the network hub. + *----------------------------------------------------------------------------*/ +Ptr::Ref +TestStorageClient :: uploadToHub(Ptr::Ref sessionId, + Ptr::Ref id) + throw (XmlRpcException) +{ + Ptr::Ref token(new Glib::ustring("fake token")); + return token; +} + + +/*------------------------------------------------------------------------------ + * Download an audio clip or playlist from the network hub. + *----------------------------------------------------------------------------*/ +Ptr::Ref +TestStorageClient :: downloadFromHub(Ptr::Ref sessionId, + Ptr::Ref id) + throw (XmlRpcException) +{ + Ptr::Ref token(new Glib::ustring("fake token")); + return token; +} + diff --git a/livesupport/src/modules/storageClient/src/TestStorageClient.h b/livesupport/src/modules/storageClient/src/TestStorageClient.h index 7d6a37723..1f457ffc3 100644 --- a/livesupport/src/modules/storageClient/src/TestStorageClient.h +++ b/livesupport/src/modules/storageClient/src/TestStorageClient.h @@ -754,6 +754,38 @@ class TestStorageClient : cancelTransport(Ptr::Ref sessionId, Ptr::Ref token) throw (XmlRpcException); + + /** + * Upload an audio clip or playlist to the network hub. + * The progress of the upload process can be monitored with + * checkTransport(). + * + * @param sessionId the session ID from the authentication client. + * @param id the ID of the Playable object to be uploaded. + * @return a token which identifies this task. + * @exception XmlRpcException if there is a problem with the XML-RPC + * call. + */ + virtual Ptr::Ref + uploadToHub(Ptr::Ref sessionId, + Ptr::Ref id) + throw (XmlRpcException); + + /** + * Download an audio clip or playlist from the network hub. + * The progress of the upload process can be monitored with + * checkTransport(). + * + * @param sessionId the session ID from the authentication client. + * @param id the ID of the Playable object to be downloaded. + * @return a token which identifies this task. + * @exception XmlRpcException if there is a problem with the XML-RPC + * call. + */ + virtual Ptr::Ref + downloadFromHub(Ptr::Ref sessionId, + Ptr::Ref id) + throw (XmlRpcException); }; diff --git a/livesupport/src/modules/storageClient/src/WebStorageClient.cxx b/livesupport/src/modules/storageClient/src/WebStorageClient.cxx index 87f36cc18..940f6e446 100644 --- a/livesupport/src/modules/storageClient/src/WebStorageClient.cxx +++ b/livesupport/src/modules/storageClient/src/WebStorageClient.cxx @@ -827,6 +827,62 @@ const std::string doTransportActionTokenParamName = "trtok"; *----------------------------------------------------------------------------*/ const std::string doTransportActionActionParamName = "action"; + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ storage server constants: uploadToHub */ + +/*------------------------------------------------------------------------------ + * The name of the upload to hub method on the storage server + *----------------------------------------------------------------------------*/ +const std::string uploadToHubMethodName = "locstor.upload2Hub"; + +/*------------------------------------------------------------------------------ + * The name of the session ID parameter in the input structure + *----------------------------------------------------------------------------*/ +const std::string uploadToHubSessionIdParamName = "sessid"; + +/*------------------------------------------------------------------------------ + * The name of the token parameter in the input structure + *----------------------------------------------------------------------------*/ +const std::string uploadToHubUniqueIdParamName = "gunid"; + +/*------------------------------------------------------------------------------ + * The name of the 'with or without content' parameter in the input structure + *----------------------------------------------------------------------------*/ +const std::string uploadToHubWithContentParamName = "withContent"; + +/*------------------------------------------------------------------------------ + * The name of the token parameter in the output structure + *----------------------------------------------------------------------------*/ +const std::string uploadToHubTokenParamName = "trtok"; + + +/* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ storage server constants: downloadFromHub */ + +/*------------------------------------------------------------------------------ + * The name of the download from hub method on the storage server + *----------------------------------------------------------------------------*/ +const std::string downloadFromHubMethodName = "locstor.downloadFromHub"; + +/*------------------------------------------------------------------------------ + * The name of the session ID parameter in the input structure + *----------------------------------------------------------------------------*/ +const std::string downloadFromHubSessionIdParamName = "sessid"; + +/*------------------------------------------------------------------------------ + * The name of the token parameter in the input structure + *----------------------------------------------------------------------------*/ +const std::string downloadFromHubUniqueIdParamName = "gunid"; + +/*------------------------------------------------------------------------------ + * The name of the 'with or without content' parameter in the input structure + *----------------------------------------------------------------------------*/ +const std::string downloadFromHubWithContentParamName = "withContent"; + +/*------------------------------------------------------------------------------ + * The name of the token parameter in the output structure + *----------------------------------------------------------------------------*/ +const std::string downloadFromHubTokenParamName = "trtok"; + } /* =============================================== local function prototypes */ @@ -2508,3 +2564,69 @@ WebStorageClient :: cancelTransport(Ptr::Ref sessionId, execute(doTransportActionMethodName, parameters, result); } + +/*------------------------------------------------------------------------------ + * Upload an audio clip or playlist to the network hub. + *----------------------------------------------------------------------------*/ +Ptr::Ref +WebStorageClient :: uploadToHub(Ptr::Ref sessionId, + Ptr::Ref id) + throw (XmlRpcException) +{ + XmlRpcValue parameters; + XmlRpcValue result; + + parameters.clear(); + parameters[uploadToHubSessionIdParamName] + = sessionId->getId(); + parameters[uploadToHubUniqueIdParamName] + = std::string(*id); + parameters[uploadToHubWithContentParamName] + = true; + + execute(uploadToHubMethodName, parameters, result); + + checkStruct(uploadToHubMethodName, + result, + uploadToHubTokenParamName, + XmlRpcValue::TypeString); + + Ptr::Ref token(new Glib::ustring( + result[uploadToHubTokenParamName] )); + + return token; +} + + +/*------------------------------------------------------------------------------ + * Download an audio clip or playlist from the network hub. + *----------------------------------------------------------------------------*/ +Ptr::Ref +WebStorageClient :: downloadFromHub(Ptr::Ref sessionId, + Ptr::Ref id) + throw (XmlRpcException) +{ + XmlRpcValue parameters; + XmlRpcValue result; + + parameters.clear(); + parameters[downloadFromHubSessionIdParamName] + = sessionId->getId(); + parameters[downloadFromHubUniqueIdParamName] + = std::string(*id); + parameters[downloadFromHubWithContentParamName] + = true; + + execute(downloadFromHubMethodName, parameters, result); + + checkStruct(downloadFromHubMethodName, + result, + downloadFromHubTokenParamName, + XmlRpcValue::TypeString); + + Ptr::Ref token(new Glib::ustring( + result[downloadFromHubTokenParamName] )); + + return token; +} + diff --git a/livesupport/src/modules/storageClient/src/WebStorageClient.h b/livesupport/src/modules/storageClient/src/WebStorageClient.h index 78612ceaa..89da5a103 100644 --- a/livesupport/src/modules/storageClient/src/WebStorageClient.h +++ b/livesupport/src/modules/storageClient/src/WebStorageClient.h @@ -846,6 +846,38 @@ class WebStorageClient : cancelTransport(Ptr::Ref sessionId, Ptr::Ref token) throw (XmlRpcException); + + /** + * Upload an audio clip or playlist to the network hub. + * The progress of the upload process can be monitored with + * checkTransport(). + * + * @param sessionId the session ID from the authentication client. + * @param id the ID of the Playable object to be uploaded. + * @return a token which identifies this task. + * @exception XmlRpcException if there is a problem with the XML-RPC + * call. + */ + virtual Ptr::Ref + uploadToHub(Ptr::Ref sessionId, + Ptr::Ref id) + throw (XmlRpcException); + + /** + * Download an audio clip or playlist from the network hub. + * The progress of the upload process can be monitored with + * checkTransport(). + * + * @param sessionId the session ID from the authentication client. + * @param id the ID of the Playable object to be downloaded. + * @return a token which identifies this task. + * @exception XmlRpcException if there is a problem with the XML-RPC + * call. + */ + virtual Ptr::Ref + downloadFromHub(Ptr::Ref sessionId, + Ptr::Ref id) + throw (XmlRpcException); }; diff --git a/livesupport/src/modules/widgets/include/LiveSupport/Widgets/Notebook.h b/livesupport/src/modules/widgets/include/LiveSupport/Widgets/Notebook.h index faaa086ac..ce6044585 100644 --- a/livesupport/src/modules/widgets/include/LiveSupport/Widgets/Notebook.h +++ b/livesupport/src/modules/widgets/include/LiveSupport/Widgets/Notebook.h @@ -281,14 +281,6 @@ class Notebook : public Gtk::Alignment virtual void pagesAdded(void) throw (); - /** - * Make a specific page active. - * - * @param pageNo the index of the page to make active. - */ - virtual void - activatePage(unsigned int pageNo) throw (); - public: /** @@ -311,6 +303,14 @@ class Notebook : public Gtk::Alignment virtual void appendPage(Gtk::Widget & widget, const Glib::ustring & label) throw (); + + /** + * Make a specific page active. + * + * @param pageNo the index of the page to make active. + */ + virtual void + activatePage(unsigned int pageNo) throw (); }; diff --git a/livesupport/src/products/gLiveSupport/etc/Makefile.in b/livesupport/src/products/gLiveSupport/etc/Makefile.in index 5840081d8..3f50906dc 100644 --- a/livesupport/src/products/gLiveSupport/etc/Makefile.in +++ b/livesupport/src/products/gLiveSupport/etc/Makefile.in @@ -267,7 +267,8 @@ G_LIVESUPPORT_OBJS = ${TMP_DIR}/GLiveSupport.o \ ${TMP_DIR}/BackupList.o \ ${TMP_DIR}/BackupView.o \ ${TMP_DIR}/ExportPlaylistWindow.o \ - ${TMP_DIR}/ExportFormatRadioButtons.o + ${TMP_DIR}/ExportFormatRadioButtons.o \ + ${TMP_DIR}/TransportList.o G_LIVESUPPORT_RES = ${TMP_DIR}/${PACKAGE_NAME}_root.res \ ${TMP_DIR}/${PACKAGE_NAME}_en.res \ diff --git a/livesupport/src/products/gLiveSupport/src/GLiveSupport.cxx b/livesupport/src/products/gLiveSupport/src/GLiveSupport.cxx index 16e70cdd6..f31d8567e 100644 --- a/livesupport/src/products/gLiveSupport/src/GLiveSupport.cxx +++ b/livesupport/src/products/gLiveSupport/src/GLiveSupport.cxx @@ -1604,3 +1604,16 @@ GLiveSupport :: stopSchedulerClient(void) throw () system(schedulerDaemonStopCommand->c_str()); } + +/*------------------------------------------------------------------------------ + * Upload a Playable object to the network hub. + *----------------------------------------------------------------------------*/ +void +LiveSupport :: GLiveSupport :: +GLiveSupport :: uploadToHub(Ptr::Ref playable) + throw () +{ + masterPanel->updateSearchWindow(playable); +} + + diff --git a/livesupport/src/products/gLiveSupport/src/GLiveSupport.h b/livesupport/src/products/gLiveSupport/src/GLiveSupport.h index 73ac77e6d..e1d08a502 100644 --- a/livesupport/src/products/gLiveSupport/src/GLiveSupport.h +++ b/livesupport/src/products/gLiveSupport/src/GLiveSupport.h @@ -1210,6 +1210,17 @@ class GLiveSupport : public LocalizedConfigurable, */ void stopSchedulerClient(void) throw(); + + /** + * Upload a Playable object to the network hub. + * + * This opens the Transports tab in the Search window, and adds the + * new upload task to it. + * + * @param playable the audio clip or playlist to be uploaded. + */ + void + uploadToHub(Ptr::Ref playable) throw (); }; /* ================================================= external data structures */ diff --git a/livesupport/src/products/gLiveSupport/src/GuiWindow.cxx b/livesupport/src/products/gLiveSupport/src/GuiWindow.cxx index 7f8737589..68324602a 100644 --- a/livesupport/src/products/gLiveSupport/src/GuiWindow.cxx +++ b/livesupport/src/products/gLiveSupport/src/GuiWindow.cxx @@ -138,6 +138,10 @@ GuiWindow :: on_show (void) throw () { gLiveSupport->getWindowPosition(shared_from_this()); + if (windowOpenerButton) { + windowOpenerButton->setSelected(true); + } + WhiteWindow::on_show(); } diff --git a/livesupport/src/products/gLiveSupport/src/LiveModeWindow.cxx b/livesupport/src/products/gLiveSupport/src/LiveModeWindow.cxx index 2915e5eb3..14ca5635e 100644 --- a/livesupport/src/products/gLiveSupport/src/LiveModeWindow.cxx +++ b/livesupport/src/products/gLiveSupport/src/LiveModeWindow.cxx @@ -187,6 +187,10 @@ LiveModeWindow :: LiveModeWindow (Ptr::Ref gLiveSupport, *getResourceUstring("exportPlaylistMenuItem"), sigc::mem_fun(*this, &LiveModeWindow::onExportPlaylist))); + contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( + *getResourceUstring("uploadToHubMenuItem"), + sigc::mem_fun(*this, + &LiveModeWindow::onUploadToHub))); } catch (std::invalid_argument &e) { std::cerr << e.what() << std::endl; std::exit(1); @@ -399,6 +403,23 @@ LiveModeWindow :: onExportPlaylist(void) throw () } +/*------------------------------------------------------------------------------ + * Signal handler for "upload to hub" in the context menu. + *----------------------------------------------------------------------------*/ +void +LiveModeWindow :: onUploadToHub(void) throw () +{ + Glib::RefPtr + refSelection = treeView->get_selection(); + Gtk::TreeModel::iterator iter = refSelection->get_selected(); + + if (iter) { + Ptr::Ref playable = (*iter)[modelColumns.playableColumn]; + gLiveSupport->uploadToHub(playable); + } +} + + /*------------------------------------------------------------------------------ * Event handler called when the the window gets hidden. *----------------------------------------------------------------------------*/ diff --git a/livesupport/src/products/gLiveSupport/src/LiveModeWindow.h b/livesupport/src/products/gLiveSupport/src/LiveModeWindow.h index 528290a7c..bd8c5e83c 100644 --- a/livesupport/src/products/gLiveSupport/src/LiveModeWindow.h +++ b/livesupport/src/products/gLiveSupport/src/LiveModeWindow.h @@ -199,6 +199,13 @@ class LiveModeWindow : public GuiWindow virtual void onExportPlaylist(void) throw (); + /** + * Signal handler for the "upload to hub" menu item selected from + * the entry context menu. + */ + virtual void + onUploadToHub(void) throw (); + /** * Event handler called when the the window gets hidden. * diff --git a/livesupport/src/products/gLiveSupport/src/MasterPanelWindow.cxx b/livesupport/src/products/gLiveSupport/src/MasterPanelWindow.cxx index e276024a7..5c31a5d45 100644 --- a/livesupport/src/products/gLiveSupport/src/MasterPanelWindow.cxx +++ b/livesupport/src/products/gLiveSupport/src/MasterPanelWindow.cxx @@ -570,7 +570,8 @@ MasterPanelWindow :: updateSchedulerWindow( * The event when the Search button has been clicked. *----------------------------------------------------------------------------*/ void -MasterPanelWindow :: updateSearchWindow(void) throw () +MasterPanelWindow :: updateSearchWindow(Ptr::Ref playable) + throw () { if (!searchWindow.get()) { Ptr::Ref bundle; @@ -585,8 +586,13 @@ MasterPanelWindow :: updateSearchWindow(void) throw () bundle, searchButton)); } - - if (!searchWindow->is_visible()) { + + bool dontWantUploadOrItWasOK = true; + if (playable) { + dontWantUploadOrItWasOK = searchWindow->uploadToHub(playable); + } + + if (dontWantUploadOrItWasOK && !searchWindow->is_visible()) { searchWindow->show(); } } diff --git a/livesupport/src/products/gLiveSupport/src/MasterPanelWindow.h b/livesupport/src/products/gLiveSupport/src/MasterPanelWindow.h index 2a74689a4..d7cd627ec 100644 --- a/livesupport/src/products/gLiveSupport/src/MasterPanelWindow.h +++ b/livesupport/src/products/gLiveSupport/src/MasterPanelWindow.h @@ -460,6 +460,9 @@ class MasterPanelWindow : public Gtk::Window, public LocalizedObject /** * Update the Live Mode window. + * + * @param playable (optional) add this item to the bottom of + * the live mode window. */ void updateLiveModeWindow(Ptr::Ref playable @@ -491,10 +494,15 @@ class MasterPanelWindow : public Gtk::Window, public LocalizedObject throw (); /** - * Update the Search Window + * Update the Search Window. + * + * @param playable (optional) add this item to the pending "upload + * to hub" tasks displayed in the Transports tab. */ void - updateSearchWindow(void) throw (); + updateSearchWindow(Ptr::Ref playable + = Ptr::Ref()) + throw (); /** * Update the Options Window diff --git a/livesupport/src/products/gLiveSupport/src/ScratchpadWindow.cxx b/livesupport/src/products/gLiveSupport/src/ScratchpadWindow.cxx index 944bf8e50..e799d2663 100644 --- a/livesupport/src/products/gLiveSupport/src/ScratchpadWindow.cxx +++ b/livesupport/src/products/gLiveSupport/src/ScratchpadWindow.cxx @@ -197,6 +197,10 @@ ScratchpadWindow :: ScratchpadWindow ( *getResourceUstring("addToLiveModeMenuItem"), sigc::mem_fun(*this, &ScratchpadWindow::onAddToLiveMode))); + audioClipMenuList.push_back(Gtk::Menu_Helpers::MenuElem( + *getResourceUstring("uploadToHubMenuItem"), + sigc::mem_fun(*this, + &ScratchpadWindow::onUploadToHub))); } catch (std::invalid_argument &e) { std::cerr << e.what() << std::endl; std::exit(1); @@ -246,6 +250,10 @@ ScratchpadWindow :: ScratchpadWindow ( *getResourceUstring("exportPlaylistMenuItem"), sigc::mem_fun(*this, &ScratchpadWindow::onExportPlaylist))); + playlistMenuList.push_back(Gtk::Menu_Helpers::MenuElem( + *getResourceUstring("uploadToHubMenuItem"), + sigc::mem_fun(*this, + &ScratchpadWindow::onUploadToHub))); } catch (std::invalid_argument &e) { std::cerr << e.what() << std::endl; std::exit(1); @@ -508,6 +516,17 @@ ScratchpadWindow :: onExportPlaylist(void) throw () } +/*------------------------------------------------------------------------------ + * Signal handler for "upload to hub" in the context menu. + *----------------------------------------------------------------------------*/ +void +ScratchpadWindow :: onUploadToHub(void) throw () +{ + Ptr::Ref playable = currentRow[modelColumns.playableColumn]; + gLiveSupport->uploadToHub(playable); +} + + /*------------------------------------------------------------------------------ * Signal handler for the user double-clicking or pressing Enter. *----------------------------------------------------------------------------*/ diff --git a/livesupport/src/products/gLiveSupport/src/ScratchpadWindow.h b/livesupport/src/products/gLiveSupport/src/ScratchpadWindow.h index e57a06547..f01a176e4 100644 --- a/livesupport/src/products/gLiveSupport/src/ScratchpadWindow.h +++ b/livesupport/src/products/gLiveSupport/src/ScratchpadWindow.h @@ -320,6 +320,13 @@ class ScratchpadWindow : public GuiWindow, virtual void onExportPlaylist(void) throw (); + /** + * Signal handler for the "upload to hub" menu item selected from + * the entry context menu. + */ + virtual void + onUploadToHub(void) throw (); + /** * Event handler called when the the window gets hidden. * diff --git a/livesupport/src/products/gLiveSupport/src/SearchWindow.cxx b/livesupport/src/products/gLiveSupport/src/SearchWindow.cxx index eac2676bf..551b97ac9 100644 --- a/livesupport/src/products/gLiveSupport/src/SearchWindow.cxx +++ b/livesupport/src/products/gLiveSupport/src/SearchWindow.cxx @@ -39,7 +39,6 @@ #include "LiveSupport/Core/TimeConversion.h" #include "LiveSupport/Widgets/WidgetFactory.h" -#include "LiveSupport/Widgets/ScrolledNotebook.h" #include "LiveSupport/Widgets/Button.h" #include "LiveSupport/Widgets/ZebraTreeView.h" @@ -94,8 +93,9 @@ SearchWindow :: SearchWindow (Ptr::Ref gLiveSupport, Gtk::Box * simpleSearchView = constructSimpleSearchView(); Gtk::Box * advancedSearchView = constructAdvancedSearchView(); Gtk::Box * browseView = constructBrowseView(); + Gtk::Box * transportsView = constructTransportsView(); - ScrolledNotebook * searchInput = Gtk::manage(new ScrolledNotebook); + searchInput = Gtk::manage(new ScrolledNotebook); try { set_title(*getResourceUstring("windowTitle")); searchInput->appendPage(*simpleSearchView, *getResourceUstring( @@ -104,6 +104,8 @@ SearchWindow :: SearchWindow (Ptr::Ref gLiveSupport, "advancedSearchTab")); searchInput->appendPage(*browseView, *getResourceUstring( "browseTab")); + searchInput->appendPage(*transportsView, *getResourceUstring( + "transportsTab")); } catch (std::invalid_argument &e) { std::cerr << e.what() << std::endl; std::exit(1); @@ -286,6 +288,34 @@ SearchWindow :: constructBrowseView(void) throw () } +/*------------------------------------------------------------------------------ + * Construct the advanced search view. + *----------------------------------------------------------------------------*/ +Gtk::VBox* +SearchWindow :: constructTransportsView(void) throw () +{ + Ptr::Ref wf = WidgetFactory::getInstance(); + + try { + transportList = Gtk::manage(new TransportList( + gLiveSupport, + gLiveSupport->getBundle("transportList") )); + } catch (std::invalid_argument &e) { + std::cerr << e.what() << std::endl; + std::exit(1); + } + + ScrolledWindow * scrolledWindow = Gtk::manage(new ScrolledWindow); + scrolledWindow->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + scrolledWindow->add(*transportList); + + Gtk::VBox * view = Gtk::manage(new Gtk::VBox); + view->pack_start(*scrolledWindow); + + return view; +} + + /*------------------------------------------------------------------------------ * Construct the search results display. *----------------------------------------------------------------------------*/ @@ -325,31 +355,10 @@ SearchWindow :: constructSearchResultsView(void) throw () *this, &SearchWindow::onEntryClicked)); searchResultsTreeView->signal_row_activated().connect(sigc::mem_fun( *this, &SearchWindow::onDoubleClick)); - - // create the right-click entry context menu - contextMenu = Gtk::manage(new Gtk::Menu()); - Gtk::Menu::MenuList& contextMenuList = contextMenu->items(); - - // register the signal handlers for the context menu - try { - contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( - *getResourceUstring("addToScratchpadMenuItem"), - sigc::mem_fun(*this, - &SearchWindow::onAddToScratchpad))); - contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( - *getResourceUstring("addToLiveModeMenuItem"), - sigc::mem_fun(*this, - &SearchWindow::onAddToLiveMode))); - contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( - *getResourceUstring("exportPlaylistMenuItem"), - sigc::mem_fun(*this, - &SearchWindow::onExportPlaylist))); - } catch (std::invalid_argument &e) { - std::cerr << e.what() << std::endl; - std::exit(1); - } - - contextMenu->accelerate(*this); + + constructAudioClipContextMenu(); + constructPlaylistContextMenu(); + constructRemoteContextMenu(); // put the tree view inside a scrolled window ScrolledWindow * view = Gtk::manage(new ScrolledWindow); @@ -422,10 +431,7 @@ void SearchWindow :: onSearch(Ptr::Ref criteria) throw () { - Ptr::Ref searchWhere - = searchWhereEntry->getActiveKey(); - - if (*searchWhere == searchWhereLocalKey) { + if (searchIsLocal()) { localSearch(criteria); } else { remoteSearchOpen(criteria); @@ -658,17 +664,23 @@ SearchWindow :: onEntryClicked (GdkEventButton * event) throw () (*iter)[modelColumns.playableColumn]; if (playable) { - switch (playable->getType()) { - case Playable::AudioClipType: - contextMenu->popup(event->button, event->time); - break; - - case Playable::PlaylistType: - contextMenu->popup(event->button, event->time); - break; + if (searchIsLocal()) { + switch (playable->getType()) { + case Playable::AudioClipType: + audioClipContextMenu->popup(event->button, + event->time); + break; + + case Playable::PlaylistType: + playlistContextMenu->popup(event->button, + event->time); + break; - default: - break; + default: + break; + } + } else { + remoteContextMenu->popup(event->button, event->time); } } } @@ -720,7 +732,7 @@ SearchWindow :: onAddToLiveMode(void) throw () * Signal handler for "export playlist" in the context menu. *----------------------------------------------------------------------------*/ void -SearchWindow :: onExportPlaylist(void) throw () +SearchWindow :: onExportPlaylist(void) throw () { Glib::RefPtr refSelection = searchResultsTreeView->get_selection(); @@ -744,6 +756,75 @@ SearchWindow :: onExportPlaylist(void) throw () } +/*------------------------------------------------------------------------------ + * Signal handler for "upload to hub" in the context menu. + *----------------------------------------------------------------------------*/ +void +SearchWindow :: onUploadToHub(void) throw () +{ + Glib::RefPtr + refSelection = searchResultsTreeView->get_selection(); + Gtk::TreeModel::iterator + iter = refSelection->get_selected(); + + if (iter) { + Ptr::Ref playable = (*iter)[modelColumns.playableColumn]; + if (playable) { + uploadToHub(playable); + } + } +} + + +/*------------------------------------------------------------------------------ + * Add the Playable object to the list of pending "upload to hub" + * tasks displayed in the Transports tab. + *----------------------------------------------------------------------------*/ +bool +SearchWindow :: uploadToHub(Ptr::Ref playable) throw () +{ + try { + searchInput->activatePage(3); + transportList->addUpload(playable); + + } catch (XmlRpcException &e) { + gLiveSupport->displayMessageWindow(formatMessage("uploadToHubErrorMsg", + e.what() )); + return false; + } + + return true; +} + + +/*------------------------------------------------------------------------------ + * Signal handler for "download from hub" in the context menu. + *----------------------------------------------------------------------------*/ +void +SearchWindow :: onDownloadFromHub(void) throw () +{ + Glib::RefPtr + refSelection = searchResultsTreeView->get_selection(); + Gtk::TreeModel::iterator + iter = refSelection->get_selected(); + + if (iter) { + Ptr::Ref playable = (*iter)[modelColumns.playableColumn]; + if (playable) { + try { + searchInput->activatePage(3); + transportList->addDownload(playable); + + } catch (XmlRpcException &e) { + gLiveSupport->displayMessageWindow(formatMessage( + "downloadFromHubErrorMsg", e.what() )); + return; + } + } + } +} + + /*------------------------------------------------------------------------------ * Signal handler for the user double-clicking or pressing Enter. *----------------------------------------------------------------------------*/ @@ -771,15 +852,29 @@ SearchWindow :: on_hide(void) throw () /*------------------------------------------------------------------------------ - * Change the displayed search results (local or remote). + * Check the status of the "search where" input box. *----------------------------------------------------------------------------*/ -void -SearchWindow :: onSearchWhereChanged(void) throw () +bool +SearchWindow :: searchIsLocal(void) throw () { Ptr::Ref searchWhere = searchWhereEntry->getActiveKey(); if (*searchWhere == searchWhereLocalKey) { + return true; + } else { + return false; + } +} + + +/*------------------------------------------------------------------------------ + * Change the displayed search results (local or remote). + *----------------------------------------------------------------------------*/ +void +SearchWindow :: onSearchWhereChanged(void) throw () +{ + if (searchIsLocal()) { searchResultsTreeView->set_model(localSearchResults); } else { searchResultsTreeView->set_model(remoteSearchResults); @@ -794,5 +889,95 @@ void SearchWindow :: onTimer(void) throw () { remoteSearchClose(); + transportList->updateSilently(); } + +/*------------------------------------------------------------------------------ + * Construct the right-click context menu for local audio clips. + *----------------------------------------------------------------------------*/ +void +SearchWindow :: constructAudioClipContextMenu(void) throw () +{ + audioClipContextMenu = Gtk::manage(new Gtk::Menu()); + Gtk::Menu::MenuList& contextMenuList = audioClipContextMenu->items(); + + try { + contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( + *getResourceUstring("addToScratchpadMenuItem"), + sigc::mem_fun(*this, + &SearchWindow::onAddToScratchpad))); + contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( + *getResourceUstring("addToLiveModeMenuItem"), + sigc::mem_fun(*this, + &SearchWindow::onAddToLiveMode))); + contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( + *getResourceUstring("uploadToHubMenuItem"), + sigc::mem_fun(*this, + &SearchWindow::onUploadToHub))); + } catch (std::invalid_argument &e) { + std::cerr << e.what() << std::endl; + std::exit(1); + } + + audioClipContextMenu->accelerate(*this); +} + + +/*------------------------------------------------------------------------------ + * Construct the right-click context menu for local playlists. + *----------------------------------------------------------------------------*/ +void +SearchWindow :: constructPlaylistContextMenu(void) throw () +{ + playlistContextMenu = Gtk::manage(new Gtk::Menu()); + Gtk::Menu::MenuList& contextMenuList = playlistContextMenu->items(); + + try { + contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( + *getResourceUstring("addToScratchpadMenuItem"), + sigc::mem_fun(*this, + &SearchWindow::onAddToScratchpad))); + contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( + *getResourceUstring("addToLiveModeMenuItem"), + sigc::mem_fun(*this, + &SearchWindow::onAddToLiveMode))); + contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( + *getResourceUstring("exportPlaylistMenuItem"), + sigc::mem_fun(*this, + &SearchWindow::onExportPlaylist))); + contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( + *getResourceUstring("uploadToHubMenuItem"), + sigc::mem_fun(*this, + &SearchWindow::onUploadToHub))); + } catch (std::invalid_argument &e) { + std::cerr << e.what() << std::endl; + std::exit(1); + } + + playlistContextMenu->accelerate(*this); +} + + +/*------------------------------------------------------------------------------ + * Construct the right-click context menu for remote audio clips & playlists. + *----------------------------------------------------------------------------*/ +void +SearchWindow :: constructRemoteContextMenu(void) throw () +{ + remoteContextMenu = Gtk::manage(new Gtk::Menu()); + Gtk::Menu::MenuList& contextMenuList = remoteContextMenu->items(); + + try { + contextMenuList.push_back(Gtk::Menu_Helpers::MenuElem( + *getResourceUstring("downloadFromHubMenuItem"), + sigc::mem_fun(*this, + &SearchWindow::onDownloadFromHub))); + } catch (std::invalid_argument &e) { + std::cerr << e.what() << std::endl; + std::exit(1); + } + + remoteContextMenu->accelerate(*this); +} + diff --git a/livesupport/src/products/gLiveSupport/src/SearchWindow.h b/livesupport/src/products/gLiveSupport/src/SearchWindow.h index 2b3be37a8..37d1aeef3 100644 --- a/livesupport/src/products/gLiveSupport/src/SearchWindow.h +++ b/livesupport/src/products/gLiveSupport/src/SearchWindow.h @@ -50,11 +50,13 @@ #include "LiveSupport/Widgets/Button.h" #include "LiveSupport/Widgets/PlayableTreeModelColumnRecord.h" #include "LiveSupport/Widgets/ScrolledWindow.h" +#include "LiveSupport/Widgets/ScrolledNotebook.h" #include "GuiWindow.h" #include "AdvancedSearchEntry.h" #include "BrowseEntry.h" #include "GLiveSupport.h" #include "ExportPlaylistWindow.h" +#include "TransportList.h" namespace LiveSupport { @@ -101,6 +103,11 @@ class SearchWindow : public GuiWindow */ BrowseEntry * browseEntry; + /** + * The list of transports in progress. + */ + TransportList * transportList; + /** * The Export Playlist pop-up window. */ @@ -146,6 +153,14 @@ class SearchWindow : public GuiWindow Gtk::VBox* constructBrowseView(void) throw (); + /** + * Construct the advanced search view. + * + * @return a pointer to the new box (already Gtk::manage()'ed) + */ + Gtk::VBox* + constructTransportsView(void) throw (); + /** * Construct the search results display. * @@ -154,6 +169,25 @@ class SearchWindow : public GuiWindow ScrolledWindow * constructSearchResultsView(void) throw (); + /** + * Construct the right-click context menu for local audio clips. + */ + void + constructAudioClipContextMenu(void) throw (); + + /** + * Construct the right-click context menu for local playlists. + */ + void + constructPlaylistContextMenu(void) throw (); + + /** + * Construct the right-click context menu for remote audio clips + * and playlists. + */ + void + constructRemoteContextMenu(void) throw (); + /** * Event handler for the simple Search button getting clicked. */ @@ -181,6 +215,12 @@ class SearchWindow : public GuiWindow void onSearch(Ptr::Ref criteria) throw (); + /** + * Check the status of the "search where" input box. + */ + bool + searchIsLocal(void) throw (); + /** * Change the displayed search results (local or remote). */ @@ -258,6 +298,18 @@ class SearchWindow : public GuiWindow virtual void onExportPlaylist(void) throw (); + /** + * Signal handler for "upload to hub" in the context menu. + */ + virtual void + onUploadToHub(void) throw (); + + /** + * Signal handler for "download from hub" in the context menu. + */ + virtual void + onDownloadFromHub(void) throw (); + /** * Event handler called when the the window gets hidden. * @@ -330,16 +382,30 @@ class SearchWindow : public GuiWindow */ ZebraTreeView * searchResultsTreeView; + /** + * The notebook for the various tabs in the window. + */ + ScrolledNotebook * searchInput; + /** * The transport token used when a remote search is pending. */ Ptr::Ref remoteSearchToken; /** - * The pop-up context menu for found items. + * The pop-up context menu for local audio clips. */ - Gtk::Menu * contextMenu; + Gtk::Menu * audioClipContextMenu; + /** + * The pop-up context menu for local playlists. + */ + Gtk::Menu * playlistContextMenu; + + /** + * The pop-up context menu for remote audio clips and playlists. + */ + Gtk::Menu * remoteContextMenu; /** * Display a (usually error) message in the search results tree view. @@ -382,6 +448,16 @@ class SearchWindow : public GuiWindow */ void onTimer(void) throw (); + + /** + * Add the Playable object to the list of pending "upload to hub" + * tasks displayed in the Transports tab. + * + * @param playable the object to be uploaded to the hub. + * @return true on success. + */ + bool + uploadToHub(Ptr::Ref playable) throw (); }; /* ================================================= external data structures */ diff --git a/livesupport/src/products/gLiveSupport/src/TransportList.cxx b/livesupport/src/products/gLiveSupport/src/TransportList.cxx new file mode 100644 index 000000000..0d75565e3 --- /dev/null +++ b/livesupport/src/products/gLiveSupport/src/TransportList.cxx @@ -0,0 +1,496 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2004 Media Development Loan Fund + + This file is part of the LiveSupport project. + http://livesupport.campware.org/ + To report bugs, send an e-mail to bugs@campware.org + + LiveSupport 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 Foundation; either version 2 of the License, or + (at your option) any later version. + + LiveSupport is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LiveSupport; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Author : $Author: fgerlits $ + Version : $Revision$ + Location : $URL: svn+ssh://fgerlits@code.campware.org/home/svn/repo/livesupport/trunk/livesupport/src/products/gLiveSupport/src/TransportList.cxx $ + +------------------------------------------------------------------------------*/ + +/* ============================================================ include files */ + +#ifdef HAVE_CONFIG_H +#include "configure.h" +#endif + +#include "LiveSupport/Core/TimeConversion.h" +#include "TransportList.h" + + +using namespace LiveSupport::Core; +using namespace LiveSupport::Storage; +using namespace LiveSupport::Widgets; +using namespace LiveSupport::GLiveSupport; + +/* =================================================== local data structures */ + + +/* ================================================ local constants & macros */ + +namespace { + +/*------------------------------------------------------------------------------ + * The localization key for the 'working' status. + *----------------------------------------------------------------------------*/ +const Glib::ustring workingStatusKey = "workingStatus"; + +/*------------------------------------------------------------------------------ + * The localization key for the 'success' status. + *----------------------------------------------------------------------------*/ +const Glib::ustring successStatusKey = "successStatus"; + +/*------------------------------------------------------------------------------ + * The localization key for the 'fault' status. + *----------------------------------------------------------------------------*/ +const Glib::ustring faultStatusKey = "faultStatus"; + +/*------------------------------------------------------------------------------ + * The name of the user preference for storing the list of transports. + *----------------------------------------------------------------------------*/ +const Glib::ustring userPreferencesKeyName = "activeTransports"; + +/*------------------------------------------------------------------------------ + * The symbol for an upload. + *----------------------------------------------------------------------------*/ +const Glib::ustring uploadSymbol = "⇧"; + +/*------------------------------------------------------------------------------ + * The symbol for a download. + *----------------------------------------------------------------------------*/ +const Glib::ustring downloadSymbol = "⇩"; + +} + +/* =============================================== local function prototypes */ + + +/* ============================================================= module code */ + +/*------------------------------------------------------------------------------ + * Constructor. + *----------------------------------------------------------------------------*/ +TransportList :: TransportList (Ptr::Ref gLiveSupport, + Ptr::Ref bundle) + throw () + : LocalizedObject(bundle), + gLiveSupport(gLiveSupport) +{ + Ptr::Ref widgetFactory = WidgetFactory::getInstance(); + + // create the tree view + treeModel = Gtk::ListStore::create(modelColumns); + treeView = Gtk::manage(widgetFactory->createTreeView(treeModel)); + treeView->set_enable_search(false); + + // Add the TreeView's view columns: + try { + treeView->appendColumn("", + modelColumns.directionColumn, 20); + treeView->appendColumn(*getResourceUstring("titleColumnLabel"), + modelColumns.titleColumn, 300); + treeView->appendColumn(*getResourceUstring("dateColumnLabel"), + modelColumns.dateColumn, 180); + treeView->appendColumn(*getResourceUstring("statusColumnLabel"), + modelColumns.statusDisplayColumn, 50); + } catch (std::invalid_argument &e) { + std::cerr << e.what() << std::endl; + std::exit(1); + } + + // register the signal handler for treeview entries being clicked + treeView->signal_button_press_event().connect_notify(sigc::mem_fun(*this, + &TransportList::onEntryClicked)); + + // create the right-click entry context menu + uploadMenu = Gtk::manage(new Gtk::Menu()); + downloadMenu = Gtk::manage(new Gtk::Menu()); + Gtk::Menu::MenuList& uploadMenuList = uploadMenu->items(); + Gtk::Menu::MenuList& downloadMenuList = downloadMenu->items(); + + try{ + uploadMenuList.push_back(Gtk::Menu_Helpers::MenuElem( + *getResourceUstring("cancelUploadMenuItem"), + sigc::mem_fun(*this, + &TransportList::onCancelTransport))); + downloadMenuList.push_back(Gtk::Menu_Helpers::MenuElem( + *getResourceUstring("cancelDownloadMenuItem"), + sigc::mem_fun(*this, + &TransportList::onCancelTransport))); + } catch (std::invalid_argument &e) { + std::cerr << e.what() << std::endl; + std::exit(1); + } + + uploadMenu->accelerate(*this); + downloadMenu->accelerate(*this); + + // add the tree view to this widget + Gtk::VBox::pack_start(*treeView); + + userPreferencesKey.reset(new const Glib::ustring(userPreferencesKeyName)); +} + + +/*------------------------------------------------------------------------------ + * Add a new upload task to the list. + *----------------------------------------------------------------------------*/ +void +TransportList :: addUpload(Ptr::Ref playable) + throw (XmlRpcException) +{ + Ptr::Ref + storage = gLiveSupport->getStorageClient(); + Ptr::Ref sessionId = gLiveSupport->getSessionId(); + + Ptr::Ref token = storage->uploadToHub(sessionId, + playable->getId()); + + Gtk::TreeRow row = *treeModel->append(); + row[modelColumns.directionColumn] = uploadSymbol; + row[modelColumns.titleColumn] = *playable->getTitle(); + row[modelColumns.dateColumn] = *TimeConversion::nowString(); + row[modelColumns.statusColumn] = workingStatusKey; + row[modelColumns.statusDisplayColumn] + = *getResourceUstring(workingStatusKey); + row[modelColumns.tokenColumn] = token; +} + + +/*------------------------------------------------------------------------------ + * Add a new download task to the list. + *----------------------------------------------------------------------------*/ +void +TransportList :: addDownload(Ptr::Ref playable) + throw (XmlRpcException) +{ + Ptr::Ref + storage = gLiveSupport->getStorageClient(); + Ptr::Ref sessionId = gLiveSupport->getSessionId(); + + Ptr::Ref token = storage->downloadFromHub( + sessionId, + playable->getId()); + + Gtk::TreeRow row = *treeModel->append(); + row[modelColumns.directionColumn] = downloadSymbol; + row[modelColumns.titleColumn] = *playable->getTitle(); + row[modelColumns.dateColumn] = *TimeConversion::nowString(); + row[modelColumns.statusColumn] = workingStatusKey; + row[modelColumns.statusDisplayColumn] + = *getResourceUstring(workingStatusKey); + row[modelColumns.tokenColumn] = token; +} + + +/*------------------------------------------------------------------------------ + * Add an item with an already existing token to the list. + *----------------------------------------------------------------------------*/ +void +TransportList :: add(const Glib::ustring & title, + const Glib::ustring & date, + const Glib::ustring & token, + bool isUpload) + throw (XmlRpcException) +{ + Ptr::Ref + storage = gLiveSupport->getStorageClient(); + Ptr::Ref sessionId = gLiveSupport->getSessionId(); + + Ptr::Ref tokenPtr(new Glib::ustring(token)); + Ptr::Ref errorMsg(new Glib::ustring); + StorageClientInterface::TransportState + state = storage->checkTransport(tokenPtr, + errorMsg); + + Gtk::TreeRow row = *treeModel->append(); + row[modelColumns.directionColumn] = isUpload ? uploadSymbol + : downloadSymbol; + row[modelColumns.titleColumn] = title; + row[modelColumns.dateColumn] = date; + row[modelColumns.tokenColumn] = tokenPtr; + setStatus(row, state, errorMsg); +} + + +/*------------------------------------------------------------------------------ + * Remove the currently selected item from the list. + *----------------------------------------------------------------------------*/ +void +TransportList :: removeSelected(void) throw (XmlRpcException) +{ + Glib::RefPtr selection = treeView->get_selection(); + Gtk::TreeIter iter = selection->get_selected(); + if (!iter) { + return; + } + + Ptr::Ref + storage = gLiveSupport->getStorageClient(); + Ptr::Ref sessionId = gLiveSupport->getSessionId(); + + storage->cancelTransport(sessionId, + iter->get_value(modelColumns.tokenColumn)); + + treeModel->erase(iter); +} + + +/*------------------------------------------------------------------------------ + * Query the storage server about the status of the pending transport. + *----------------------------------------------------------------------------*/ +bool +TransportList :: updateSelected(void) throw (XmlRpcException) +{ + Glib::RefPtr selection = treeView->get_selection(); + Gtk::TreeIter iter = selection->get_selected(); + if (!iter) { + return false; + } else { + return update(iter); + } +} + + +/*------------------------------------------------------------------------------ + * Query the storage server about the status of the pending transport. + *----------------------------------------------------------------------------*/ +bool +TransportList :: update(void) throw (XmlRpcException) +{ + bool didSomething = false; + + for (Gtk::TreeIter it = treeModel->children().begin(); + it != treeModel->children().end(); ++it) { + didSomething |= update(it); + } + + return didSomething; +} + + +/*------------------------------------------------------------------------------ + * Query the storage server about the status of the pending transport. + *----------------------------------------------------------------------------*/ +bool +TransportList :: updateSilently(void) throw () +{ + bool didSomething = false; + + for (Gtk::TreeIter it = treeModel->children().begin(); + it != treeModel->children().end(); ++it) { + try { + didSomething |= update(it); + } catch (XmlRpcException &e) { + } + } + + return didSomething; +} + + +/*------------------------------------------------------------------------------ + * Query the storage server about the status of the pending transport. + *----------------------------------------------------------------------------*/ +bool +TransportList :: update(Gtk::TreeIter iter) throw (XmlRpcException) +{ + if (iter->get_value(modelColumns.statusColumn) != workingStatusKey) { + return false; + } + + Ptr::Ref + storage = gLiveSupport->getStorageClient(); + Ptr::Ref errorMsg(new Glib::ustring); + StorageClientInterface::TransportState + status = storage->checkTransport( + iter->get_value(modelColumns.tokenColumn), + errorMsg); + + return setStatus(iter, status, errorMsg); +} + + +/*------------------------------------------------------------------------------ + * Set the status of the row pointed to by an iterator. + *----------------------------------------------------------------------------*/ +bool +TransportList :: setStatus(Gtk::TreeIter iter, + StorageClientInterface::TransportState status, + Ptr::Ref errorMsg) + throw () +{ + switch (status) { + case StorageClientInterface::initState: + + case StorageClientInterface::pendingState: + iter->set_value(modelColumns.statusColumn, + workingStatusKey); + iter->set_value(modelColumns.statusDisplayColumn, + *getResourceUstring(workingStatusKey)); + return false; + + case StorageClientInterface::finishedState: + + case StorageClientInterface::closedState: + iter->set_value(modelColumns.statusColumn, + successStatusKey); + iter->set_value(modelColumns.statusDisplayColumn, + *getResourceUstring(successStatusKey)); + return true; + + case StorageClientInterface::failedState: + iter->set_value(modelColumns.statusColumn, + faultStatusKey); + iter->set_value(modelColumns.statusDisplayColumn, + *formatMessage(faultStatusKey, *errorMsg)); + return false; + + default: std::cerr << "Impossible status: '" << status + << "' in TransportList::setStatus()." + << std::endl; + return false; + } +} + + +/*------------------------------------------------------------------------------ + * Return the contents of the transport list. + *----------------------------------------------------------------------------*/ +Ptr::Ref +TransportList :: getContents(void) throw () +{ + std::ostringstream contentsStream; + Gtk::TreeModel::const_iterator it; + Ptr::Ref token; + + for (it = treeModel->children().begin(); + it != treeModel->children().end(); ++it) { + Gtk::TreeRow row = *it; + if (row[modelColumns.statusColumn] == workingStatusKey) { + if (row[modelColumns.directionColumn] == uploadSymbol) { + contentsStream << "up\n"; + } else { + contentsStream << "down\n"; + } + contentsStream << row[modelColumns.titleColumn] << '\n'; + contentsStream << row[modelColumns.dateColumn] << '\n'; + token = row[modelColumns.tokenColumn]; + contentsStream << *token << '\n'; + } + } + + Ptr::Ref contents(new Glib::ustring( + contentsStream.str() )); + return contents; +} + + +/*------------------------------------------------------------------------------ + * Restore the contents of the transport list. + *----------------------------------------------------------------------------*/ +void +TransportList :: setContents(Ptr::Ref contents) + throw () +{ + std::istringstream contentsStream(contents->raw()); + + treeModel->clear(); + while (!contentsStream.eof()) { + std::string direction; + std::string title; + std::string date; + std::string token; + + std::getline(contentsStream, direction); + if (contentsStream.fail()) { + break; + } + std::getline(contentsStream, title); + if (contentsStream.fail()) { + break; + } + std::getline(contentsStream, date); + if (contentsStream.fail()) { + break; + } + std::getline(contentsStream, token); + if (contentsStream.fail()) { + break; + } + + try { + add(title, date, token, (direction == "up")); + + } catch (XmlRpcException &e) { + } + } +} + + +/*------------------------------------------------------------------------------ + * Event handler for an entry being clicked in the list. + *----------------------------------------------------------------------------*/ +void +TransportList :: onEntryClicked(GdkEventButton * event) throw () +{ + if (event->type == GDK_BUTTON_PRESS && event->button == 3) { + Gtk::TreePath currentPath; + Gtk::TreeViewColumn * column; + int cell_x, + cell_y; + bool foundValidRow = treeView->get_path_at_pos( + int(event->x), int(event->y), + currentPath, column, + cell_x, cell_y); + + if (foundValidRow) { + Gtk::TreeIter iter = treeModel->get_iter(currentPath); + if (iter) { + Gtk::TreeRow row = *iter; + if (row[modelColumns.directionColumn] == uploadSymbol) { + uploadMenu->popup(event->button, event->time); + } else { + downloadMenu->popup(event->button, event->time); + } + } + } + } +} + + +/*------------------------------------------------------------------------------ + * Event handler for "cancel" selected from the pop-up menu. + *----------------------------------------------------------------------------*/ +void +TransportList :: onCancelTransport(void) throw () +{ + try { + removeSelected(); + + } catch (XmlRpcException &e) { + gLiveSupport->displayMessageWindow(formatMessage( + "cannotCancelTransportMsg", + e.what() )); + } +} + diff --git a/livesupport/src/products/gLiveSupport/src/TransportList.h b/livesupport/src/products/gLiveSupport/src/TransportList.h new file mode 100644 index 000000000..dbf4d8707 --- /dev/null +++ b/livesupport/src/products/gLiveSupport/src/TransportList.h @@ -0,0 +1,403 @@ +/*------------------------------------------------------------------------------ + + Copyright (c) 2004 Media Development Loan Fund + + This file is part of the LiveSupport project. + http://livesupport.campware.org/ + To report bugs, send an e-mail to bugs@campware.org + + LiveSupport 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 Foundation; either version 2 of the License, or + (at your option) any later version. + + LiveSupport is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with LiveSupport; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + + Author : $Author: fgerlits $ + Version : $Revision$ + Location : $URL: svn+ssh://fgerlits@code.campware.org/home/svn/repo/livesupport/trunk/livesupport/src/products/gLiveSupport/src/TransportList.h $ + +------------------------------------------------------------------------------*/ +#ifndef TransportList_h +#define TransportList_h + +#ifndef __cplusplus +#error This is a C++ include file +#endif + + +/* ============================================================ include files */ + +#ifdef HAVE_CONFIG_H +#include "configure.h" +#endif + +#include + +#include "LiveSupport/Core/Ptr.h" +#include "LiveSupport/Core/UniqueId.h" +#include "LiveSupport/Core/LocalizedObject.h" +#include "LiveSupport/Core/XmlRpcException.h" +#include "LiveSupport/Widgets/Button.h" +#include "LiveSupport/Widgets/ScrolledWindow.h" +#include "LiveSupport/Widgets/ZebraTreeModelColumnRecord.h" +#include "LiveSupport/Widgets/ZebraTreeView.h" +#include "GLiveSupport.h" + +namespace LiveSupport { +namespace GLiveSupport { + +using namespace LiveSupport::Core; +using namespace LiveSupport::Widgets; + +/* ================================================================ constants */ + + +/* =================================================================== macros */ + + +/* =============================================================== data types */ + +/** + * The list of pending transports. + * + * This is a Gtk::VBox containing a TreeView with the following columns: + *
    + *
  • shown: + *
      + *
    • the direction of the transfer (upload or download)
    • + *
    • the title of the transported file
    • + *
    • transport date
    • + *
    • transport status (localized; contains the fault string, if any)
    • + *
  • + *
  • hidden: + *
      + *
    • token
    • + *
    • transport status (not localized: + * "working" / "success" / "fault")
    • + *
  • + *
+ * + * The TransportList is contained in the SearchWindow. + * + * @author $Author: fgerlits $ + * @version $Revision$ + */ +class TransportList : public Gtk::VBox, + public LocalizedObject, + public ContentsStorable +{ + private: + /** + * The user preferences key. + */ + Ptr::Ref userPreferencesKey; + + /** + * Set the status of the row pointed to by an iterator. + * + * @param iter points to the row we want to set the status of. + * @param status the new status ("working", "success" or "fault"). + * @param errorMessage the error message (for status "fault"); + * optional + * @return true if the status is "success", false otherwise. + */ + bool + setStatus(Gtk::TreeIter iter, + StorageClientInterface::TransportState status, + Ptr::Ref errorMsg + = Ptr::Ref()) + throw (); + + /** + * Add an item with an already existing token to the list. + * + * @param title the title of the transport. + * @param date the date of the transport. + * @param token the token for this transport. + * @param isUpload true if this is an upload transfer; + * false if this is a download transfer. + * @exception XmlRpcException thrown by the storage client. + */ + void + add(const Glib::ustring & title, + const Glib::ustring & date, + const Glib::ustring & token, + bool isUpload) + throw (XmlRpcException); + + /** + * Query the storage server about the status of the given row. + * If its status is 'working', call getTransportInfo + * on it, and change its displayed status, if needed. + * + * @param iter points to the row to be updated. + * @return true if getTransportInfo was called, and it returned + * 'success'; false in all other cases. + * @exception XmlRpcException thrown by the storage client. + */ + bool + update(Gtk::TreeIter iter) throw (XmlRpcException); + + + protected: + /** + * The GLiveSupport object, holding the state of the application. + */ + Ptr::Ref gLiveSupport; + + /** + * The columns model needed by ZebraTreeView. + * + * @author $Author: fgerlits $ + * @version $Revision$ + */ + class ModelColumns : public ZebraTreeModelColumnRecord + { + public: + /** + * The column for the direction of the transport (up/down). + */ + Gtk::TreeModelColumn directionColumn; + + /** + * The column for the title of the transported file. + */ + Gtk::TreeModelColumn titleColumn; + + /** + * The column for the date of the transport. + */ + Gtk::TreeModelColumn dateColumn; + + /** + * The column for the status of the transport (not localized). + */ + Gtk::TreeModelColumn statusColumn; + + /** + * The column for the status of the transport (localized). + */ + Gtk::TreeModelColumn statusDisplayColumn; + + /** + * The column for the token corresponding to the transport. + */ + Gtk::TreeModelColumn::Ref> + tokenColumn; + + /** + * Constructor. + */ + ModelColumns(void) throw () + { + add(directionColumn); + add(titleColumn); + add(dateColumn); + add(statusColumn); + add(statusDisplayColumn); + add(tokenColumn); + } + }; + + + /** + * The column model. + */ + ModelColumns modelColumns; + + /** + * The tree model, as a GTK reference. + */ + Glib::RefPtr treeModel; + + /** + * The tree view. + */ + ZebraTreeView * treeView; + + /** + * The pop-up menu for uploads. + */ + Gtk::Menu * uploadMenu; + + /** + * The pop-up menu for downloads. + */ + Gtk::Menu * downloadMenu; + + /** + * Event handler for an entry being clicked in the list. + * This is used to pop up the right-click context menu. + * + * @param event the button event recieved + */ + void + onEntryClicked(GdkEventButton * event) throw (); + + /** + * Event handler for "cancel" selected from the pop-up menu. + */ + void + onCancelTransport(void) throw (); + + + public: + /** + * Constructor. + * + * @param gLiveSupport the gLiveSupport object, containing + * all the vital info. + * @param bundle the resource bundle holding the localized + * resources for this window. + */ + TransportList(Ptr::Ref gLiveSupport, + Ptr::Ref bundle) throw (); + + /** + * Virtual destructor. + */ + virtual + ~TransportList(void) throw () + { + } + + /** + * Add a new upload task to the list. + * + * @param playable the playable object to be uploaded to the + * network hub. + * @exception XmlRpcException thrown by the storage client. + */ + void + addUpload(Ptr::Ref playable) + throw (XmlRpcException); + + /** + * Add a new download task to the list. + * + * The playable parameter can be an incomplete object; + * all it needs to have is a unique ID, a type (audio clip or + * playlist), and a title. + * + * @param playable the playable object to be downloaded from the + * network hub. + * @exception XmlRpcException thrown by the storage client. + */ + void + addDownload(Ptr::Ref playable) + throw (XmlRpcException); + + /** + * Remove the currently selected item from the list. + * + * The doTransportAction storage function is + * called on the transport task with the cancel parameter, + * and it is removed from the tree model. + * + * @exception XmlRpcException thrown by the storage client. + */ + void + removeSelected(void) throw (XmlRpcException); + + /** + * Query the storage server about the status of the selected row. + * + * If its status is 'working', call getTransportInfo + * on it, and change its displayed status, if needed. + * + * @return true if getTransportInfo was called, and it returned + * 'success'; false in all other cases. + * @exception XmlRpcException thrown by the storage client. + */ + bool + updateSelected(void) throw (XmlRpcException); + + /** + * Query the storage server about the status of the pending transport. + * + * If there is a transport with status 'working', call getTransportInfo + * on it, and change its displayed status, if needed. + * + * @return true if getTransportInfo was called, and it returned + * at least one 'success'; false in all other cases. + * @exception XmlRpcException thrown by the storage client. + */ + bool + update(void) throw (XmlRpcException); + + /** + * Query the storage server about the status of the pending transport. + * + * If there is a transport with status 'working', call getTransportInfo + * on it, and change its displayed status, if needed. + * + * This is the same as update(), except it does not throw any + * exceptions (just ignores them). + * + * @return true if getTransportInfo was called, and it returned + * at least one 'success'; false in all other cases. + */ + bool + updateSilently(void) throw (); + + /** + * Return the contents of the transport list. + * + * The format is a newline-separated list of transport directions, + * titles, dates and tokens. + * E.g.: "up title1 date1 token1 down title2 date2 token2". + * + * @return the contents of the transport list as a string. + */ + Ptr::Ref + getContents(void) throw (); + + /** + * Restore the contents of the transport list. + * + * The current contents are discarded, and replaced with the items + * listed in the 'contents' parameter. + * The format is a newline-separated list of transport directions, + * titles, dates and tokens. + * E.g.: "up title1 date1 token1 down title2 date2 token2". + * + * @param contents the new contents of the transport list as a string. + */ + void + setContents(Ptr::Ref contents) throw (); + + /** + * Return the user preferences key. + * + * The contents of the window will be stored in the user preferences + * under this key. + * + * @return the user preference key. + */ + Ptr::Ref + getUserPreferencesKey(void) throw () + { + return userPreferencesKey; + } +}; + +/* ================================================= external data structures */ + + +/* ====================================================== function prototypes */ + + +} // namespace GLiveSupport +} // namespace LiveSupport + +#endif // TransportList_h + diff --git a/livesupport/src/products/gLiveSupport/var/root.txt b/livesupport/src/products/gLiveSupport/var/root.txt index 010b2e04d..0b8c29650 100644 --- a/livesupport/src/products/gLiveSupport/var/root.txt +++ b/livesupport/src/products/gLiveSupport/var/root.txt @@ -76,6 +76,7 @@ root:table cueMenuItem:string { "Pre_view" } addToLiveModeMenuItem:string { "Add To _Live Mode" } exportPlaylistMenuItem:string { "E_xport Playlist" } + uploadToHubMenuItem:string { "Upload to the network hub" } cannotEditPlaylistMsg:string { "Could not open playlist for editing." } @@ -192,6 +193,7 @@ root:table simpleSearchTab:string { "Search" } advancedSearchTab:string { "Advanced Search" } browseTab:string { "Browse" } + transportsTab:string { "Transfers" } searchButtonLabel:string { "Search" } @@ -205,9 +207,13 @@ root:table addToScratchpadMenuItem:string { "_Add To Scratchpad" } addToLiveModeMenuItem:string { "Add To _Live Mode" } exportPlaylistMenuItem:string { "E_xport Playlist" } + uploadToHubMenuItem:string { "Upload to the network hub" } + downloadFromHubMenuItem:string { "Download from the network hub" } pleaseWaitMsg:string { "Please wait..." } remoteSearchErrorMsg:string { "Search failed: {0}." } + uploadToHubErrorMsg:string { "Uploading to hub failed: {0}." } + downloadFromHubErrorMsg:string { "Downloading from hub failed: {0}." } } advancedSearchEntry:table { @@ -237,6 +243,7 @@ root:table removeMenuItem:string { "_Remove" } playMenuItem:string { "_Play" } exportPlaylistMenuItem:string { "E_xport Playlist" } + uploadToHubMenuItem:string { "Upload to the network hub" } cuePlayerLabel:string { "Preview" } } @@ -338,6 +345,22 @@ root:table saveExportErrorMsg:string { "Could not save the exported playlist." } } + transportList:table + { + workingStatus:string { "in progress" } + successStatus:string { "ready" } + faultStatus:string { "error: {0}" } + + titleColumnLabel:string { "Title" } + dateColumnLabel:string { "Date" } + statusColumnLabel:string { "Status" } + + cancelUploadMenuItem:string { "Cancel upload" } + cancelDownloadMenuItem:string { "Cancel download" } + + cannotCancelTransportMsg:string { "Canceling failed: {0}." } + } + metadataTypes:table { title:string { "Title" }