From 2c00c806f3fcb766455ff2f5a3f774a107b3a493 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20=C3=96nnerby?= Date: Wed, 17 Sep 2008 19:58:22 +0000 Subject: [PATCH] Created a (temporary) musik::core::MessageQueue Started on playlist functionality. --- src/core/Library/Base.cpp | 3 + src/core/MessageQueue.cpp | 93 +++++++++++++++++++ src/core/MessageQueue.h | 81 ++++++++++++++++ src/core/Query/PlaylistSave.cpp | 37 +++++--- src/core/Query/PlaylistSave.h | 2 +- src/core/Query/Playlists.cpp | 2 + src/core/core.vcproj | 8 ++ src/core/server/Connection.cpp | 4 +- src/core/tracklist/Playlist.cpp | 1 + src/core/xml/Writer.cpp | 2 +- src/cube/LibraryWindowController.cpp | 29 +++++- src/cube/LibraryWindowController.hpp | 30 +++--- src/cube/MainMenuController.cpp | 3 + src/cube/SourcesCategory.cpp | 13 ++- src/cube/SourcesCategory.hpp | 2 +- src/cube/SourcesController.cpp | 35 +++++++ src/cube/SourcesController.hpp | 16 +++- src/cube/SourcesListModel.cpp | 6 ++ src/cube/SourcesListModel.hpp | 1 + src/cube/SourcesModel.cpp | 62 ++++++++++++- src/cube/SourcesModel.hpp | 52 ++++++++--- src/cube/TracklistController.cpp | 15 ++- src/cube/TracklistController.hpp | 11 ++- src/cube/TracklistModel.cpp | 6 +- src/cube/TracklistModel.hpp | 5 +- src/cube/cube.vcproj | 22 ++++- src/cube/dialog/NewPlaylistController.cpp | 89 ++++++++++++++++++ src/cube/dialog/NewPlaylistController.hpp | 79 ++++++++++++++++ src/cube/dialog/NewPlaylistView.cpp | 108 ++++++++++++++++++++++ src/cube/dialog/NewPlaylistView.hpp | 69 ++++++++++++++ 30 files changed, 820 insertions(+), 66 deletions(-) create mode 100644 src/core/MessageQueue.cpp create mode 100644 src/core/MessageQueue.h create mode 100644 src/cube/dialog/NewPlaylistController.cpp create mode 100644 src/cube/dialog/NewPlaylistController.hpp create mode 100644 src/cube/dialog/NewPlaylistView.cpp create mode 100644 src/cube/dialog/NewPlaylistView.hpp diff --git a/src/core/Library/Base.cpp b/src/core/Library/Base.cpp index 5d68346e1..6fb6f0bca 100644 --- a/src/core/Library/Base.cpp +++ b/src/core/Library/Base.cpp @@ -180,6 +180,9 @@ utfstring Library::Base::GetDBPath(){ ////////////////////////////////////////// bool Library::Base::AddQuery( const Query::Base &query,unsigned int options ){ + if(this->Exited()){ + return false; + } // Start by making a copy Query::Ptr queryCopy( query.copy() ); diff --git a/src/core/MessageQueue.cpp b/src/core/MessageQueue.cpp new file mode 100644 index 000000000..52b901c29 --- /dev/null +++ b/src/core/MessageQueue.cpp @@ -0,0 +1,93 @@ +////////////////////////////////////////////////////////////////////////////// +// +// License Agreement: +// +// The following are Copyright © 2008, Daniel Önnerby +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#include "pch.hpp" + +#include + +////////////////////////////////////////////////////////////////////////////// + +using namespace musik::core; + +////////////////////////////////////////////////////////////////////////////// + +MessageQueue MessageQueue::sInstance; + +/*MessageQueue& MessageQueue::Instance(){ + return MessageQueue::sInstance; +}*/ + +MessageQueue::MessageQueue(void) +{ +} + +MessageQueue::~MessageQueue(void) +{ +} + +MessageQueue::ControllerEventSignal& MessageQueue::EventController(){ + return MessageQueue::sInstance.controllerEvent; +} + +MessageQueue::EventSignal& MessageQueue::MessageEvent(const char* identifier){ + return MessageQueue::sInstance.eventMap[identifier]; +} + +void MessageQueue::SendMessage(const char* identifier,void* data){ + { + EventSignalMap::iterator eventSignal = MessageQueue::sInstance.eventMap.find(identifier); + if(eventSignal!=MessageQueue::sInstance.eventMap.end()){ + // First call the controllers + MessageQueue::sInstance.controllerEvent(identifier,data); + } + } + { + // Just in case the controller would change the eventMap, lets find the eventSignal again. + EventSignalMap::iterator eventSignal = MessageQueue::sInstance.eventMap.find(identifier); + if(eventSignal!=MessageQueue::sInstance.eventMap.end()){ + // Call the evenSignals + eventSignal->second(data); + } + } +} + +MessageQueueData::MessageQueueData(){ +} + +MessageQueueData::~MessageQueueData(){ +} + + diff --git a/src/core/MessageQueue.h b/src/core/MessageQueue.h new file mode 100644 index 000000000..97a18306f --- /dev/null +++ b/src/core/MessageQueue.h @@ -0,0 +1,81 @@ +////////////////////////////////////////////////////////////////////////////// +// +// License Agreement: +// +// The following are Copyright © 2008, Daniel Önnerby +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#pragma once + +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////// + +namespace musik { namespace core { + +////////////////////////////////////////////////////////////////////////////// + +struct MessageQueueData{ + MessageQueueData(); + virtual ~MessageQueueData(); +}; + +class MessageQueue { + + public: + typedef sigslot::signal2 ControllerEventSignal; + typedef sigslot::signal1 EventSignal; + + static ControllerEventSignal& EventController(); + static EventSignal& MessageEvent(const char* identifier); + static void SendMessage(const char* identifier,void* data=NULL); + + + private: + ~MessageQueue(); + MessageQueue(); + + //static MessageQueue& Instance(); + private: + // The one and only instance + static MessageQueue sInstance; + + typedef std::map EventSignalMap; + EventSignalMap eventMap; + ControllerEventSignal controllerEvent; +}; + +////////////////////////////////////////////////////////////////////////////// +} } // musik::core +////////////////////////////////////////////////////////////////////////////// diff --git a/src/core/Query/PlaylistSave.cpp b/src/core/Query/PlaylistSave.cpp index 1e508eb1e..ad3a909fd 100644 --- a/src/core/Query/PlaylistSave.cpp +++ b/src/core/Query/PlaylistSave.cpp @@ -55,16 +55,17 @@ Query::PlaylistSave::PlaylistSave(void){ Query::PlaylistSave::~PlaylistSave(void){ } -void Query::PlaylistSave::SavePlaylist(int playlistId,utfstring playlistName,musik::core::tracklist::IRandomAccess &tracklist){ +void Query::PlaylistSave::SavePlaylist(const utfstring playlistName,int playlistId,musik::core::tracklist::IRandomAccess *tracklist){ this->playlistId = playlistId; this->playlistName = playlistName; - for(int i(0);itracks.push_back(track->id); - } - } + this->tracks.clear(); + + if(tracklist){ + for(int i(0);iSize();++i){ + this->tracks.push_back((*tracklist)[i]->id); + } + } } bool Query::PlaylistSave::ParseQuery(Library::Base *library,db::Connection &db){ @@ -72,11 +73,13 @@ bool Query::PlaylistSave::ParseQuery(Library::Base *library,db::Connection &db){ db::ScopedTransaction transaction(db); { - db::Statement updatePlaylist("INSERT OR REPLACE INT playlists (id,name) VALUES (?,?)",db); - if(this->playlistId==0){ + db::Statement updatePlaylist("INSERT OR REPLACE INTO playlists (id,name,user_id) VALUES (?,?,?)",db); + if(this->playlistId!=0){ updatePlaylist.BindInt(0,this->playlistId); } updatePlaylist.BindTextUTF(1,this->playlistName); + updatePlaylist.BindInt(2,library->userId); + if( updatePlaylist.Step()==db::Done ){ if(this->playlistId==0){ this->playlistId = db.LastInsertedId(); @@ -114,12 +117,18 @@ Query::Ptr Query::PlaylistSave::copy() const{ } bool Query::PlaylistSave::RunCallbacks(Library::Base *library){ - boost::mutex::scoped_lock lock(library->libraryMutex); - if( (this->status & Status::Ended)!=0){ + bool callCallbacks(false); + { + boost::mutex::scoped_lock lock(library->libraryMutex); + if( (this->status & Status::Ended)!=0){ + callCallbacks = true; + } + } + + if(callCallbacks){ this->PlaylistSaved(this->playlistId); - return true; - } - return false; + } + return callCallbacks; } diff --git a/src/core/Query/PlaylistSave.h b/src/core/Query/PlaylistSave.h index 1150ab638..cdad2fc0c 100644 --- a/src/core/Query/PlaylistSave.h +++ b/src/core/Query/PlaylistSave.h @@ -64,7 +64,7 @@ namespace musik{ namespace core{ PlaylistSave(void); ~PlaylistSave(void); - void SavePlaylist(int playlistId,utfstring playlistName,musik::core::tracklist::IRandomAccess &tracklist); + void SavePlaylist(const utfstring playlistName,int playlistId=0,musik::core::tracklist::IRandomAccess *tracklist=NULL); sigslot::signal1 PlaylistSaved; diff --git a/src/core/Query/Playlists.cpp b/src/core/Query/Playlists.cpp index c8fd32c02..361cbdc04 100644 --- a/src/core/Query/Playlists.cpp +++ b/src/core/Query/Playlists.cpp @@ -61,6 +61,8 @@ bool Query::Playlists::ParseQuery(Library::Base *library,db::Connection &db){ db::Statement stmt("SELECT id,name FROM playlists WHERE user_id=?",db); + stmt.BindInt(0,library->userId); + while(stmt.Step()==db::Row){ tracklist::Ptr playlist( new tracklist::Playlist( stmt.ColumnInt(0), diff --git a/src/core/core.vcproj b/src/core/core.vcproj index bf167b4aa..5683e8f49 100644 --- a/src/core/core.vcproj +++ b/src/core/core.vcproj @@ -212,6 +212,14 @@ RelativePath=".\Crypt.h" > + + + + diff --git a/src/core/server/Connection.cpp b/src/core/server/Connection.cpp index f5d112df7..e7c34d8aa 100644 --- a/src/core/server/Connection.cpp +++ b/src/core/server/Connection.cpp @@ -272,7 +272,7 @@ void Connection::WriteThread(){ this->waitCondition.wait(lock); } - if(!this->outgoingQueries.empty()){ + if(!this->outgoingQueries.empty() && !this->exit){ sendQuery = this->outgoingQueries.front(); } } @@ -329,12 +329,12 @@ void Connection::Exit(){ { boost::mutex::scoped_lock lock(this->libraryMutex); if(!this->exit){ + this->exit = true; if(this->socket.is_open()){ this->socket.close(); } this->server->RemoveUserSession(this->userSession); } - this->exit = true; } this->waitCondition.notify_all(); this->authCondition.notify_all(); diff --git a/src/core/tracklist/Playlist.cpp b/src/core/tracklist/Playlist.cpp index 7993699a3..319384347 100644 --- a/src/core/tracklist/Playlist.cpp +++ b/src/core/tracklist/Playlist.cpp @@ -48,6 +48,7 @@ using namespace musik::core::tracklist; Playlist::Playlist(int id,utfstring name,musik::core::LibraryPtr library) :Standard() ,id(0) +,name(name) { this->SetLibrary(library); diff --git a/src/core/xml/Writer.cpp b/src/core/xml/Writer.cpp index e0e20f615..e991e304a 100644 --- a/src/core/xml/Writer.cpp +++ b/src/core/xml/Writer.cpp @@ -174,7 +174,7 @@ void Writer::Send(){ try{ // Time to send the buffer - if(!sendBuffer.empty()){ + if(!sendBuffer.empty() && this->socket->is_open()){ boost::asio::write(*(this->socket),boost::asio::buffer(sendBuffer)); // Log //std::ofstream logFile("mc2_Writer.log",std::ios::app); diff --git a/src/cube/LibraryWindowController.cpp b/src/cube/LibraryWindowController.cpp index 411d29ee4..d9a68a2c1 100644 --- a/src/cube/LibraryWindowController.cpp +++ b/src/cube/LibraryWindowController.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -79,6 +80,8 @@ void LibraryWindowController::OnViewCreated(Window* window) this->UpdateLibraryTabs(); LibraryFactory::Instance().LibrariesUpdated.connect(this,&LibraryWindowController::UpdateLibraryTabs); + // Connect to the MessageQueue + musik::core::MessageQueue::EventController().connect(this,&LibraryWindowController::OnLibraryMessage); } void LibraryWindowController::UpdateLibraryTabs(){ @@ -95,15 +98,15 @@ void LibraryWindowController::UpdateLibraryTabs(){ // check if library already exist bool found(false); - for(LibraryWindowVector::iterator libraryWindow=this->libraries.begin();libraryWindow!=this->libraries.end() && !found;++libraryWindow){ - if( (*libraryWindow)->library->Identifier()==libraryId ){ + for(SourcesMap::iterator libraryWindow=this->libraries.begin();libraryWindow!=this->libraries.end() && !found;++libraryWindow){ + if( libraryWindow->second->library->Identifier()==libraryId ){ found = true; } } if(!found){ SourcesView* sourcesView = new SourcesView(); - this->libraries.push_back(SourcesControllerPtr(new SourcesController(*sourcesView,*library))); + this->libraries[sourcesView] = SourcesControllerPtr(new SourcesController(*sourcesView,*library)); this->view.AddTab( (*library)->Identifier() ,sourcesView); } @@ -115,3 +118,23 @@ void LibraryWindowController::OnResize(Window* window, Size size) RedrawLock redrawLock(&this->view); // this->clientView->Resize(this->mainWindow.ClientSize()); } + +SourcesController* LibraryWindowController::CurrentSourceController(){ + SourcesView *sourcesView = (SourcesView*)this->view.ActiveWindow(); + + SourcesMap::iterator foundLibrary = this->libraries.find(sourcesView); + if(foundLibrary!=this->libraries.end()){ + return foundLibrary->second.get(); + } + return NULL; +} + +void LibraryWindowController::OnLibraryMessage(const char* identifier,void* data){ + if(!data){ + SourcesController* sourcesController = this->CurrentSourceController(); + if(sourcesController){ + musik::core::MessageQueue::SendMessage(identifier,sourcesController->library.get()); + } + } +} + diff --git a/src/cube/LibraryWindowController.hpp b/src/cube/LibraryWindowController.hpp index 720057c2b..197f76828 100644 --- a/src/cube/LibraryWindowController.hpp +++ b/src/cube/LibraryWindowController.hpp @@ -48,11 +48,13 @@ namespace win32cpp{ } namespace musik { namespace cube { class LibraryWindowView; + class SourcesView; + class SourcesController; } } ////////////////////////////////////////////////////////////////////////////// #include -#include +#include #include #include @@ -69,23 +71,27 @@ namespace musik { namespace cube { class LibraryWindowController : public EventHandler { -public: /*ctor*/ LibraryWindowController(LibraryWindowView& view); -public: /*dtor*/ ~LibraryWindowController(); + public: + LibraryWindowController(LibraryWindowView& view); + ~LibraryWindowController(); -protected: - void OnViewCreated(Window* window); - void OnResize(Window* window, Size size); + protected: + void OnViewCreated(Window* window); + void OnResize(Window* window, Size size); - void UpdateLibraryTabs(); + void UpdateLibraryTabs(); - LibraryWindowView& view; -// SourcesController* sourcesController; + void OnLibraryMessage(const char* identifier,void* data); - typedef boost::shared_ptr SourcesControllerPtr; - typedef std::vector LibraryWindowVector; + LibraryWindowView& view; - LibraryWindowVector libraries; + typedef boost::shared_ptr SourcesControllerPtr; + typedef std::map SourcesMap; + SourcesMap libraries; + public: + + SourcesController* CurrentSourceController(); }; diff --git a/src/cube/MainMenuController.cpp b/src/cube/MainMenuController.cpp index 2edc01acd..238eb7dbf 100644 --- a/src/cube/MainMenuController.cpp +++ b/src/cube/MainMenuController.cpp @@ -38,12 +38,14 @@ #include "pch.hpp" #include +#include #include #include #include #include #include + ////////////////////////////////////////////////////////////////////////////// using namespace musik::cube; @@ -140,6 +142,7 @@ void MainMenuController::OnHelpAbout(MenuItemRef menuItem) } void MainMenuController::OnNewPlaylist(MenuItemRef menuItem){ + musik::core::MessageQueue::SendMessage("NewPlaylist"); } diff --git a/src/cube/SourcesCategory.cpp b/src/cube/SourcesCategory.cpp index fb703f1e2..6158d037e 100644 --- a/src/cube/SourcesCategory.cpp +++ b/src/cube/SourcesCategory.cpp @@ -75,7 +75,16 @@ SourcesItemRef SourcesCategory::Add(SourcesItemRef item) return item; } -SourcesItemRef SourcesCategory::Remove(SourcesItemRef item) +void SourcesCategory::Remove(SourcesItemRef item) { - throw NotImplementedException(); + for(SourcesItemList::iterator it=this->items.begin();it!=this->items.end();){ + if(item==*it){ + it = this->items.erase(it); + }else{ + ++it; + } + } + this->CountChanged((int) this->items.size()); + + //throw NotImplementedException(); } \ No newline at end of file diff --git a/src/cube/SourcesCategory.hpp b/src/cube/SourcesCategory.hpp index 0b9109c85..1e40a5c28 100644 --- a/src/cube/SourcesCategory.hpp +++ b/src/cube/SourcesCategory.hpp @@ -66,7 +66,7 @@ public: uistring Caption() const; public: int Count() const; public: SourcesItemRef ItemAt(int index) const; public: SourcesItemRef Add(SourcesItemRef item); -public: SourcesItemRef Remove(SourcesItemRef item); +public: void Remove(SourcesItemRef item); private: typedef std::vector SourcesItemList; private: uistring caption; diff --git a/src/cube/SourcesController.cpp b/src/cube/SourcesController.cpp index e74bbe95b..6d737ffbf 100644 --- a/src/cube/SourcesController.cpp +++ b/src/cube/SourcesController.cpp @@ -39,6 +39,10 @@ #include #include #include +#include + +#include +#include ////////////////////////////////////////////////////////////////////////////// @@ -68,6 +72,8 @@ using namespace musik::cube; library->OnQueryQueueStart.connect(this,&SourcesController::QueryQueueStart); library->OnQueryQueueEnd.connect(this,&SourcesController::QueryQueueEnd); + musik::core::MessageQueue::MessageEvent("NewPlaylist").connect(this,&SourcesController::OnNewPlaylist); + } void SourcesController::OnViewCreated(Window* window) @@ -75,6 +81,9 @@ void SourcesController::OnViewCreated(Window* window) this->model.CategoryAdded.connect(this, &SourcesController::OnModelCategoryAdded); this->model.CategoryRemoved.connect(this, &SourcesController::OnModelCategoryRemoved); this->model.Load(); + + this->UpdatePlaylists(); + } void SourcesController::OnModelCategoryAdded(CategoryRef category) @@ -118,6 +127,32 @@ void SourcesController::QueryQueueLoop(){ this->library->RunCallbacks(); } +void SourcesController::OnNewPlaylist(void* data){ + if(data==this->library.get()){ + win32cpp::TopLevelWindow popupDialog(_(_T("New Playlist"))); + popupDialog.SetMinimumSize(Size(300, 150)); + + dialog::NewPlaylistController newPlaylist(popupDialog,this->library); + + popupDialog.ShowModal(TopLevelWindow::FindFromAncestor(&this->view)); + + this->UpdatePlaylists(); + } +} + +void SourcesController::UpdatePlaylists(){ + musik::core::Query::Playlists playlistQuery; + playlistQuery.PlaylistList.connect(this,&SourcesController::OnPlaylists); + this->library->AddQuery(playlistQuery); +} + +void SourcesController::OnPlaylists(std::vector trackLists){ + this->model.OnPlaylists(trackLists); + + this->listController->sourcesListModel->Update(); +// this->view.Redraw(); +} + ////////////////////////////////////////////////////////////////////////////// // SourcesController::ListController ////////////////////////////////////////////////////////////////////////////// diff --git a/src/cube/SourcesController.hpp b/src/cube/SourcesController.hpp index 7c234ee38..27b34735d 100644 --- a/src/cube/SourcesController.hpp +++ b/src/cube/SourcesController.hpp @@ -73,10 +73,11 @@ public: musik::core::LibraryPtr library; private: - void OnViewCreated(Window* window); - void OnActiveItemChanged(ItemRef newItem); - void OnModelCategoryAdded(CategoryRef category); - void OnModelCategoryRemoved(CategoryRef category); + void OnViewCreated(Window* window); + void OnActiveItemChanged(ItemRef newItem); + void OnModelCategoryAdded(CategoryRef category); + void OnModelCategoryRemoved(CategoryRef category); + void OnNewPlaylist(void* data); protected: SourcesView& view; @@ -87,6 +88,9 @@ protected: void QueryQueueStart(); void QueryQueueEnd(); void QueryQueueLoop(); + + void UpdatePlaylists(); + void OnPlaylists(std::vector trackLists); }; ////////////////////////////////////////////////////////////////////////////// @@ -104,7 +108,9 @@ private: void OnListCreated(Window* window); private: void OnListSelectionChanged(ListView* listView); private: ListView& listView; -private: ListModelRef sourcesListModel; +private: + friend class SourcesController; + ListModelRef sourcesListModel; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/src/cube/SourcesListModel.cpp b/src/cube/SourcesListModel.cpp index 5d696a4d9..6433aa887 100644 --- a/src/cube/SourcesListModel.cpp +++ b/src/cube/SourcesListModel.cpp @@ -172,6 +172,12 @@ CategoryRef SourcesListModel::RemoveCategory(CategoryRef category) throw InvalidSourcesCategoryException(); } +void SourcesListModel::Update(){ + this->IndexCategories(); + this->SetRowCount(this->VisibleItemCount()); +} + + void SourcesListModel::IndexCategories() { this->categoryIndexMap.clear(); diff --git a/src/cube/SourcesListModel.hpp b/src/cube/SourcesListModel.hpp index 8537eb3e9..b83ec9d6e 100644 --- a/src/cube/SourcesListModel.hpp +++ b/src/cube/SourcesListModel.hpp @@ -81,6 +81,7 @@ public: /*ctor*/ SourcesListModel(); public: CategoryRef AddCategory(CategoryRef category); public: CategoryRef RemoveCategory(CategoryRef category); public: void SelectedRowChanged(int newIndex); +public: void Update(); // private API private: int VisibleItemCount(); diff --git a/src/cube/SourcesModel.cpp b/src/cube/SourcesModel.cpp index 14c37cd44..d5fd6a2e6 100644 --- a/src/cube/SourcesModel.cpp +++ b/src/cube/SourcesModel.cpp @@ -45,6 +45,8 @@ #include #include +#include + #include using namespace musik::cube; @@ -116,7 +118,7 @@ class NowPlayingItem: public SourcesItem private: /*ctor*/ NowPlayingItem(musik::core::LibraryPtr library) - : controller(view,NULL,library->NowPlaying()) + : controller(view,NULL,library->NowPlaying(),TracklistController::HighlightActive|TracklistController::Deletable) { } @@ -139,6 +141,39 @@ private: TracklistView view; private: TracklistController controller; }; +////////////////////////////////////////////////////////////////////////////// + +class PlaylistItem: public SourcesItem +{ +private: + + /*ctor*/ PlaylistItem(musik::core::tracklist::Ptr playlist) + : controller(view,NULL,playlist,TracklistController::HighlightActive|TracklistController::Deletable) + { + } + +public: /*dtor*/ ~PlaylistItem() + { + } + +public: static SourcesItemRef Create(musik::core::tracklist::Ptr playlist) + { + return SourcesItemRef(new PlaylistItem(playlist)); + } + +public: virtual uistring Caption() { + musik::core::tracklist::Playlist* playlist = (musik::core::tracklist::Playlist*)(this->controller.Tracklist().get()); + return playlist->Name(); + } +public: virtual Window* View() + { + return &this->view; + } + +private: TracklistView view; +private: TracklistController controller; +}; + ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// #include @@ -180,7 +215,7 @@ typedef SourcesListModel::CategoryRef CategoryRef; { } -void SourcesModel::Load() +void SourcesModel::Load() { CategoryRef viewCategory(new Category(_(_T("View")))); viewCategory->Add(BrowseItem::Create(this->library)); @@ -221,3 +256,26 @@ void SourcesModel::RemoveCategory(CategoryRef category) this->categories.erase(it); this->CategoryRemoved(category); } + +void SourcesModel::OnPlaylists(SourcesModel::PlaylistVector &playlists){ + // Start by removing the old ones + for(PlaylistItemMap::iterator it=this->playlistItemsMap.begin();it!=this->playlistItemsMap.end();++it){ + // Remove the item from the category + this->playlistCategory->Remove(it->second); + } + + // Clear the map + this->playlistItemsMap.clear(); + + // Start creating the new playlists + for(SourcesModel::PlaylistVector::iterator playlist=playlists.begin();playlist!=playlists.end();++playlist){ + // Create the sourcesItem + SourcesItemRef sourceItem = PlaylistItem::Create(*playlist); + playlistCategory->Add(sourceItem); + + this->playlistItemsMap[*playlist] = sourceItem; + + } + +} + diff --git a/src/cube/SourcesModel.hpp b/src/cube/SourcesModel.hpp index 0c425518d..1aef84b7e 100644 --- a/src/cube/SourcesModel.hpp +++ b/src/cube/SourcesModel.hpp @@ -40,8 +40,10 @@ #include #include +#include #include +#include ////////////////////////////////////////////////////////////////////////////// @@ -49,30 +51,50 @@ using namespace win32cpp; namespace musik { namespace cube { +// Forward +class SourcesController; + ////////////////////////////////////////////////////////////////////////////// class SourcesModel { -public: typedef SourcesItemRef ItemRef; -public: typedef SourcesCategoryRef CategoryRef; -private: typedef std::vector CategoryList; -private: class InvalidCategoryException: public Exception { }; + public: + typedef SourcesItemRef ItemRef; + typedef SourcesCategoryRef CategoryRef; + private: + typedef std::vector CategoryList; + + class InvalidCategoryException: public Exception { }; -public: sigslot::signal1 CategoryAdded; -public: sigslot::signal1 CategoryRemoved; + sigslot::signal1 CategoryAdded; + sigslot::signal1 CategoryRemoved; -public: /*ctor*/ SourcesModel(musik::core::LibraryPtr library); - musik::core::LibraryPtr library; + public: + /*ctor*/ SourcesModel(musik::core::LibraryPtr library); + musik::core::LibraryPtr library; -public: void Load(); + public: + void Load(); -protected: void AddCategory(CategoryRef category); -protected: void RemoveCategory(CategoryRef category); -protected: void OnActiveItemChanged(ItemRef); + protected: + void AddCategory(CategoryRef category); + void RemoveCategory(CategoryRef category); + void OnActiveItemChanged(ItemRef); + + typedef std::vector PlaylistVector; + + typedef std::map PlaylistItemMap; + PlaylistItemMap playlistItemsMap; + + private: + ItemRef activeItem; + CategoryList categories; + CategoryRef playlistCategory; + + protected: + friend class SourcesController; + void OnPlaylists(PlaylistVector &playlists); -private: ItemRef activeItem; -private: CategoryList categories; -private: CategoryRef playlistCategory; }; ////////////////////////////////////////////////////////////////////////////// diff --git a/src/cube/TracklistController.cpp b/src/cube/TracklistController.cpp index 6d3cbad64..25e328ec6 100644 --- a/src/cube/TracklistController.cpp +++ b/src/cube/TracklistController.cpp @@ -55,9 +55,11 @@ using namespace musik::cube; /*ctor*/ TracklistController::TracklistController( TracklistView& view, musik::core::Query::ListBase *connectedQuery, - musik::core::tracklist::Ptr tracklist) + musik::core::tracklist::Ptr tracklist, + unsigned int options) : view(view) -, model(new TracklistModel(connectedQuery, tracklist)) +, model(new TracklistModel(connectedQuery, tracklist,options)) +, options(options) { this->view.Handle() ? this->OnViewCreated(&view) @@ -72,6 +74,15 @@ using namespace musik::cube; } +musik::core::tracklist::Ptr TracklistController::Tracklist(){ + TracklistModel* model = (TracklistModel*)this->model.get(); + if(model){ + return model->tracklist; + } + return musik::core::tracklist::Ptr(); +} + + void TracklistController::OnViewCreated(Window* window) { typedef ListView::Column Column; diff --git a/src/cube/TracklistController.hpp b/src/cube/TracklistController.hpp index bb9ebd81e..c790a3800 100644 --- a/src/cube/TracklistController.hpp +++ b/src/cube/TracklistController.hpp @@ -65,6 +65,11 @@ namespace musik { namespace cube { class TracklistController : public EventHandler { +public: + enum Options:unsigned int{ + HighlightActive=1, + Deletable=2 + }; private: typedef ListView::ColumnRef ColumnRef; typedef std::vector ColumnList; @@ -74,7 +79,10 @@ public: /*ctor*/ TracklistController( TracklistView& listView, musik::core::Query::ListBase *connectedQuery, - musik::core::tracklist::Ptr tracklist); + musik::core::tracklist::Ptr tracklist, + unsigned int options=0); + + musik::core::tracklist::Ptr Tracklist(); private: void OnViewCreated(Window* window); @@ -91,6 +99,7 @@ private: ColumnList columns; win32cpp::MenuRef contextMenu; musik::core::Query::SortTracks sortQuery; + unsigned int options; }; diff --git a/src/cube/TracklistModel.cpp b/src/cube/TracklistModel.cpp index cb908a62b..8b0ed34ef 100644 --- a/src/cube/TracklistModel.cpp +++ b/src/cube/TracklistModel.cpp @@ -43,6 +43,7 @@ #include "pch.hpp" #include #include +#include #include #include @@ -58,8 +59,9 @@ using namespace musik::cube; ////////////////////////////////////////////////////////////////////////////// -/*ctor*/ TracklistModel::TracklistModel(musik::core::Query::ListBase *connectedQuery,musik::core::tracklist::Ptr setTracklist) +/*ctor*/ TracklistModel::TracklistModel(musik::core::Query::ListBase *connectedQuery,musik::core::tracklist::Ptr setTracklist,unsigned int options) : currentPosition(-1) +, options(options) { this->tracklist = setTracklist; @@ -103,7 +105,7 @@ uistring TracklistModel::CellValueToString(int rowIndex, ColumnRef co return win32cpp::Escape(result); break; } - if(rowIndex==this->currentPosition){ + if(rowIndex==this->currentPosition && this->options&TracklistController::HighlightActive){ return win32cpp::Escape(value)+_T("***"); } return win32cpp::Escape(value); diff --git a/src/cube/TracklistModel.hpp b/src/cube/TracklistModel.hpp index 322b838e9..1108f0f50 100644 --- a/src/cube/TracklistModel.hpp +++ b/src/cube/TracklistModel.hpp @@ -68,7 +68,8 @@ public: // public API TracklistModel( musik::core::Query::ListBase *connectedQuery, - musik::core::tracklist::Ptr setTracklist); + musik::core::tracklist::Ptr setTracklist, + unsigned int options); void ConnectToQuery(musik::core::Query::ListBase *connectedQuery); void OnRowActivated(int row); @@ -86,7 +87,7 @@ protected: void OnPositionChanged(int activeRow,int oldActiveRow); int currentPosition; - + unsigned int options; public: musik::core::tracklist::Ptr tracklist; // FIXME: no public fields! diff --git a/src/cube/cube.vcproj b/src/cube/cube.vcproj index ac1d0faf0..a4cd503c5 100644 --- a/src/cube/cube.vcproj +++ b/src/cube/cube.vcproj @@ -102,7 +102,7 @@ /> + + + + + + + + + + +#include +#include +#include + +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////// + +using namespace musik::cube::dialog; +using namespace win32cpp; + +////////////////////////////////////////////////////////////////////////////// + +NewPlaylistController::NewPlaylistController(win32cpp::TopLevelWindow &mainWindow,musik::core::LibraryPtr library) +:mainWindow(mainWindow) +,library(library) +{ + this->view = new NewPlaylistView(); + this->mainWindow.AddChild(this->view); + + this->view->Handle() + ? this->OnViewCreated(this->view) + : this->view->Created.connect(this, &NewPlaylistController::OnViewCreated); + +} + +NewPlaylistController::~NewPlaylistController(){ +} + +void NewPlaylistController::OnViewCreated(Window* window) +{ + this->view->cancelButton->Pressed.connect(this,&NewPlaylistController::OnCancel); + this->view->okButton->Pressed.connect(this,&NewPlaylistController::OnOK); +} + +void NewPlaylistController::OnCancel(win32cpp::Button* button){ + this->mainWindow.Close(); +} + +void NewPlaylistController::OnOK(win32cpp::Button* button){ + + musik::core::Query::PlaylistSave savePlaylistQuery; + savePlaylistQuery.SavePlaylist( this->view->name->Caption() ); + + this->library->AddQuery(savePlaylistQuery,musik::core::Query::UnCanceable); + + this->mainWindow.Close(); +} diff --git a/src/cube/dialog/NewPlaylistController.hpp b/src/cube/dialog/NewPlaylistController.hpp new file mode 100644 index 000000000..779a37776 --- /dev/null +++ b/src/cube/dialog/NewPlaylistController.hpp @@ -0,0 +1,79 @@ +////////////////////////////////////////////////////////////////////////////// +// +// License Agreement: +// +// The following are Copyright © 2007, mC2 Team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#pragma once + +////////////////////////////////////////////////////////////////////////////// +// Forward declare +namespace win32cpp{ + class Window; + class Button; +} +////////////////////////////////////////////////////////////////////////////// + +#include +#include + +#include +#include + +////////////////////////////////////////////////////////////////////////////// + +namespace musik { namespace cube { namespace dialog{ + +////////////////////////////////////////////////////////////////////////////// + +class NewPlaylistController : public win32cpp::EventHandler{ + + public: + NewPlaylistController(win32cpp::TopLevelWindow &mainWindow,musik::core::LibraryPtr library); + ~NewPlaylistController(); + + private: + void OnViewCreated(win32cpp::Window* window); + void OnCancel(win32cpp::Button* button); + void OnOK(win32cpp::Button* button); + + win32cpp::TopLevelWindow &mainWindow; + + NewPlaylistView *view; + + musik::core::LibraryPtr library; +}; + +////////////////////////////////////////////////////////////////////////////// + +} } } // musik::cube::dialog diff --git a/src/cube/dialog/NewPlaylistView.cpp b/src/cube/dialog/NewPlaylistView.cpp new file mode 100644 index 000000000..a098e9628 --- /dev/null +++ b/src/cube/dialog/NewPlaylistView.cpp @@ -0,0 +1,108 @@ +////////////////////////////////////////////////////////////////////////////// +// +// License Agreement: +// +// The following are Copyright © 2007, mC2 Team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// + +#include "pch.hpp" +#include + +#include + +#include +#include +#include +#include +#include + +////////////////////////////////////////////////////////////////////////////// + +using namespace musik::cube::dialog; +using namespace win32cpp; + +////////////////////////////////////////////////////////////////////////////// + +NewPlaylistView::NewPlaylistView() +: Frame(NULL,FramePadding(6)) +{ +} + +void NewPlaylistView::OnCreated() +{ + FontRef boldFont(Font::Create()); + boldFont->SetBold(true); + + // Top Row layout + LinearLayout* topRowLayout = new LinearLayout(LinearRowLayout); + topRowLayout->SetDefaultChildFill(false); + topRowLayout->SetDefaultChildAlignment(win32cpp::ChildAlignMiddle); + + Label *label; + Size labelSize(80,0); + + // First rows column layout + LinearLayout* firstColumnLayout = new LinearLayout(LinearColumnLayout); + firstColumnLayout->SetDefaultChildFill(false); + firstColumnLayout->SetDefaultChildAlignment(win32cpp::ChildAlignCenter); + + label = firstColumnLayout->AddChild(new Label(_T("New Playlist"))); + label->SetFont(boldFont); + topRowLayout->AddChild(firstColumnLayout); + + + // Second rows column layout + LinearLayout* secondColumnLayout = new LinearLayout(LinearColumnLayout); + secondColumnLayout->SetDefaultChildAlignment(win32cpp::ChildAlignTop); + + label = secondColumnLayout->AddChild(new Label(_T("Name:") )); + label->Resize(labelSize); + this->name = secondColumnLayout->AddChild(new EditView(160,20 )); + topRowLayout->AddChild(secondColumnLayout); + + + + // Last rows column layout + LinearLayout* bottomButtonLayout = new LinearLayout(LinearColumnLayout); + bottomButtonLayout->SetDefaultChildFill(false); + this->cancelButton = bottomButtonLayout->AddChild(new Button(_T("Cancel"))); + this->okButton = bottomButtonLayout->AddChild(new Button(_T("OK"))); + this->cancelButton->Resize(60,20); + this->okButton->Resize(60,20); + topRowLayout->AddChild(bottomButtonLayout); + topRowLayout->SetChildAlignment(bottomButtonLayout,ChildAlignRight); + + + + this->AddChild(topRowLayout); + +} diff --git a/src/cube/dialog/NewPlaylistView.hpp b/src/cube/dialog/NewPlaylistView.hpp new file mode 100644 index 000000000..fe5735ab3 --- /dev/null +++ b/src/cube/dialog/NewPlaylistView.hpp @@ -0,0 +1,69 @@ +////////////////////////////////////////////////////////////////////////////// +// +// License Agreement: +// +// The following are Copyright © 2007, mC2 Team +// +// All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// +// * Redistributions of source code must retain the above copyright notice, +// this list of conditions and the following disclaimer. +// +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// +// * Neither the name of the author nor the names of other contributors may +// be used to endorse or promote products derived from this software +// without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +// POSSIBILITY OF SUCH DAMAGE. +// +////////////////////////////////////////////////////////////////////////////// +#pragma once + +////////////////////////////////////////////////////////////////////////////// +// Forward declare +namespace win32cpp{ + class Button; + class EditView; +} +////////////////////////////////////////////////////////////////////////////// + +#include + +////////////////////////////////////////////////////////////////////////////// + +namespace musik { namespace cube { namespace dialog { + +////////////////////////////////////////////////////////////////////////////// +// forward +////////////////////////////////////////////////////////////////////////////// + +class NewPlaylistView: public win32cpp::Frame{ + public: + NewPlaylistView(); + + virtual void OnCreated(); + + win32cpp::Button *okButton, *cancelButton; + win32cpp::EditView *name; +}; + +////////////////////////////////////////////////////////////////////////////// + +} } } // musik::cube::dialog +