hydrogen 1.2.3
Playlist.cpp
Go to the documentation of this file.
1/*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 * Copyright(c) 2008-2024 The hydrogen development team [hydrogen-devel@lists.sourceforge.net]
5 *
6 * http://www.hydrogen-music.org
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY, without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see https://www.gnu.org/licenses
20 *
21 */
22
24#include <core/Hydrogen.h>
27#include <core/Helpers/Legacy.h>
28#include <core/Helpers/Xml.h>
29#include <core/EventQueue.h>
30
31namespace H2Core
32{
33
34Playlist* Playlist::__instance = nullptr;
35
43
45{
46 clear();
47 __instance = nullptr;
48}
49
51{
52 if ( __instance == nullptr ) {
53 __instance = new Playlist();
54 }
55}
56
58{
59 for ( int i = 0; i < __entries.size(); i++ ) {
60 delete __entries[i];
61 }
62 __entries.clear();
63}
64
65Playlist* Playlist::load_file( const QString& pl_path, bool useRelativePaths )
66{
67 XMLDoc doc;
68 if ( !doc.read( pl_path, Filesystem::playlist_xsd_path() ) ) {
69 Playlist* pl = new Playlist();
70 Playlist* ret = Legacy::load_playlist( pl, pl_path );
71 if ( ret == nullptr ) {
72 delete pl; // __instance = 0;
73 return nullptr;
74 }
75 WARNINGLOG( QString( "update playlist %1" ).arg( pl_path ) );
76 pl->save_file( pl_path, pl->getFilename(), true, useRelativePaths );
77 return pl;
78 }
79 XMLNode root = doc.firstChildElement( "playlist" );
80 if ( root.isNull() ) {
81 ERRORLOG( "playlist node not found" );
82 return nullptr;
83 }
84 QFileInfo fileInfo = QFileInfo( pl_path );
85 return Playlist::load_from( &root, fileInfo, useRelativePaths );
86}
87
88Playlist* Playlist::load_from( XMLNode* node, QFileInfo& fileInfo, bool useRelativePaths )
89{
90 QString filename = node->read_string( "name", "", false, false );
91 if ( filename.isEmpty() ) {
92 ERRORLOG( "Playlist has no name, abort" );
93 return nullptr;
94 }
95
96 Playlist* pPlaylist = new Playlist();
97 pPlaylist->setFilename( fileInfo.absoluteFilePath() );
98
99 XMLNode songsNode = node->firstChildElement( "songs" );
100 if ( !songsNode.isNull() ) {
101 XMLNode nextNode = songsNode.firstChildElement( "song" );
102 while ( !nextNode.isNull() ) {
103
104 QString songPath = nextNode.read_string( "path", "", false, false );
105 if ( !songPath.isEmpty() ) {
106 Playlist::Entry* pEntry = new Playlist::Entry();
107 QFileInfo songPathInfo( fileInfo.absoluteDir(), songPath );
108 pEntry->filePath = songPathInfo.absoluteFilePath();
109 pEntry->fileExists = songPathInfo.isReadable();
110 pEntry->scriptPath = nextNode.read_string( "scriptPath", "" );
111 pEntry->scriptEnabled = nextNode.read_bool( "scriptEnabled", false );
112 pPlaylist->add( pEntry );
113 }
114
115 nextNode = nextNode.nextSiblingElement( "song" );
116 }
117 } else {
118 WARNINGLOG( "songs node not found" );
119 }
120 return pPlaylist;
121}
122
123bool Playlist::save_file( const QString& pl_path, const QString& name, bool overwrite, bool useRelativePaths )
124{
125 INFOLOG( QString( "Saving palylist to %1" ).arg( pl_path ) );
126 if( !overwrite && Filesystem::file_exists( pl_path, true ) ) {
127 ERRORLOG( QString( "palylist %1 already exists" ).arg( pl_path ) );
128 return false;
129 }
130
131 setFilename( pl_path );
132
133 XMLDoc doc;
134 XMLNode root = doc.set_root( "playlist", "playlist" );
135 root.write_string( "name", name);
136 XMLNode songs = root.createNode( "songs" );
137 save_to( &songs, useRelativePaths );
138 return doc.write( pl_path );
139}
140
141void Playlist::save_to( XMLNode* node, bool useRelativePaths )
142{
143 for (int i = 0; i < size(); i++ ) {
144 Entry* entry = get( i );
145 QString path = entry->filePath;
146 if ( useRelativePaths ) {
147 path = QDir( Filesystem::playlists_dir() ).relativeFilePath( path );
148 }
149 XMLNode song_node = node->createNode( "song" );
150 song_node.write_string( "path", path );
151 song_node.write_string( "scriptPath", entry->scriptPath );
152 song_node.write_bool( "scriptEnabled", entry->scriptEnabled);
153 }
154}
155
156Playlist* Playlist::load( const QString& filename, bool useRelativePaths )
157{
158 // load_file might set __instance = 0;
159 Playlist* prev = __instance;
160 Playlist* playlist = Playlist::load_file( filename, useRelativePaths );
161
162 if ( playlist != nullptr ) {
163 delete prev;
164 __instance = playlist;
165 } else {
166 __instance = prev;
167 }
168
169 return playlist;
170}
171
172/* This method is called by Event dispatcher thread ( GUI ) */
173void Playlist::activateSong( int songNumber )
174{
175 setSelectedSongNr( songNumber );
176 setActiveSongNumber( songNumber );
177
178 execScript( songNumber );
179}
180
181bool Playlist::getSongFilenameByNumber( int songNumber, QString& filename)
182{
183 bool Success = true;
184
185 if ( size() == 0 || songNumber >= size() ) {
186 Success = false;
187 }
188
189 if( Success) {
190 filename = get( songNumber )->filePath;
191 }
192
193 return Success;
194}
195
196/* This method is called by MIDI thread */
197void Playlist::setNextSongByNumber( int songNumber )
198{
199 if ( size() == 0 || songNumber >= size() ) {
200 return;
201 }
202
203 /* NOTE: we are in MIDI thread and can't just call loadSong from here :( */
205}
206
207void Playlist::execScript( int index)
208{
209 QString file = get( index )->scriptPath;
210
211 if ( !get( index )->scriptEnabled || !QFile( file ).exists() ) {
212 return;
213 }
214
215 std::system( file.toLocal8Bit() );
216
217 return;
218}
219
220QString Playlist::toQString( const QString& sPrefix, bool bShort ) const {
221 QString s = Base::sPrintIndention;
222 QString sOutput;
223 if ( ! bShort ) {
224 sOutput = QString( "%1[Playlist]\n" ).arg( sPrefix )
225 .append( QString( "%1%2filename: %3\n" ).arg( sPrefix ).arg( s ).arg( __filename ) )
226 .append( QString( "%1%2m_nSelectedSongNumber: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nSelectedSongNumber ) )
227 .append( QString( "%1%2m_nActiveSongNumber: %3\n" ).arg( sPrefix ).arg( s ).arg( m_nActiveSongNumber ) )
228 .append( QString( "%1%2entries:\n" ).arg( sPrefix ).arg( s ) );
229 if ( size() > 0 ) {
230 for ( auto ii : __entries ) {
231 sOutput.append( QString( "%1%2Entry:\n" ).arg( sPrefix ).arg( s + s ) )
232 .append( QString( "%1%2filePath: %3\n" ).arg( sPrefix ).arg( s + s + s ).arg( ii->filePath ) )
233 .append( QString( "%1%2fileExists: %3\n" ).arg( sPrefix ).arg( s + s + s ).arg( ii->fileExists ) )
234 .append( QString( "%1%2scriptPath: %3\n" ).arg( sPrefix ).arg( s + s + s ).arg( ii->scriptPath ) )
235 .append( QString( "%1%2scriptEnabled: %3\n" ).arg( sPrefix ).arg( s + s + s ).arg( ii->scriptEnabled ) );
236 }
237 }
238 sOutput.append( QString( "%1%2m_bIsModified: %3\n" ).arg( sPrefix ).arg( s ).arg( m_bIsModified ) );
239 } else {
240 sOutput = QString( "[Playlist]" )
241 .append( QString( " filename: %1" ).arg( __filename ) )
242 .append( QString( ", m_nSelectedSongNumber: %1" ).arg( m_nSelectedSongNumber ) )
243 .append( QString( ", m_nActiveSongNumber: %1" ).arg( m_nActiveSongNumber ) )
244 .append( ", entries: {" );
245 if ( size() > 0 ) {
246 for ( auto ii : __entries ) {
247 sOutput.append( QString( "[filePath: %1" ).arg( ii->filePath ) )
248 .append( QString( ", fileExists: %1" ).arg( ii->fileExists ) )
249 .append( QString( ", scriptPath: %1" ).arg( ii->scriptPath ) )
250 .append( QString( ", scriptEnabled: %1] " ).arg( ii->scriptEnabled ) );
251
252
253 }
254 }
255 sOutput.append( QString( "}, m_bIsModified: %1\n" ).arg( m_bIsModified ) );
256 }
257
258 return sOutput;
259}
260};
#define INFOLOG(x)
Definition Object.h:237
#define WARNINGLOG(x)
Definition Object.h:238
#define ERRORLOG(x)
Definition Object.h:239
static QString sPrintIndention
String used to format the debugging string output of some core classes.
Definition Object.h:127
static EventQueue * get_instance()
Returns a pointer to the current EventQueue singleton stored in __instance.
Definition EventQueue.h:224
void push_event(const EventType type, const int nValue)
Queues the next event into the EventQueue.
static QString playlist_xsd_path()
returns the path to the playlist pattern XSD (xml schema definition) file
static QString playlists_dir()
returns user playlist path
static bool file_exists(const QString &path, bool silent=false)
returns true if the given path is an existing regular file
static Playlist * load_playlist(Playlist *pl, const QString &pl_path)
load playlist from a file
Definition Legacy.cpp:245
Drumkit info.
Definition Playlist.h:37
void add(Entry *entry)
Definition Playlist.h:134
static Playlist * __instance
Object holding the current Playlist singleton.
Definition Playlist.h:105
void setNextSongByNumber(int SongNumber)
Definition Playlist.cpp:197
std::vector< Entry * > __entries
Definition Playlist.h:108
int m_nSelectedSongNumber
Definition Playlist.h:110
int m_nActiveSongNumber
Definition Playlist.h:111
void save_to(XMLNode *node, bool useRelativePaths)
Definition Playlist.cpp:141
static void create_instance()
If __instance equals 0, a new Playlist singleton will be created and stored in it.
Definition Playlist.cpp:50
void activateSong(int SongNumber)
Definition Playlist.cpp:173
void execScript(int index)
Definition Playlist.cpp:207
void setFilename(const QString &filename)
Definition Playlist.h:164
void setSelectedSongNr(int songNumber)
Definition Playlist.h:144
Entry * get(int idx)
Definition Playlist.h:128
QString toQString(const QString &sPrefix="", bool bShort=true) const override
Formatted string version for debugging purposes.
Definition Playlist.cpp:220
void setActiveSongNumber(int ActiveSongNumber)
Definition Playlist.h:154
QString __filename
Definition Playlist.h:106
bool save_file(const QString &pl_path, const QString &name, bool overwrite, bool useRelativePaths)
Definition Playlist.cpp:123
static Playlist * load_from(XMLNode *root, QFileInfo &fileInfo, bool useRelativePaths)
Definition Playlist.cpp:88
const QString & getFilename()
Definition Playlist.h:159
static Playlist * load(const QString &filename, bool useRelativePaths)
Definition Playlist.cpp:156
static Playlist * load_file(const QString &pl_path, bool useRelativePaths)
Definition Playlist.cpp:65
int size() const
Definition Playlist.h:123
bool getSongFilenameByNumber(int songNumber, QString &fileName)
Definition Playlist.cpp:181
XMLDoc is a subclass of QDomDocument with read and write methods.
Definition Xml.h:182
XMLNode set_root(const QString &node_name, const QString &xmlns=nullptr)
create the xml header and root node
Definition Xml.cpp:391
bool read(const QString &filepath, const QString &schemapath=nullptr, bool bSilent=false)
read the content of an xml file
Definition Xml.cpp:296
bool write(const QString &filepath)
write itself into a file
Definition Xml.cpp:370
XMLNode is a subclass of QDomNode with read and write values methods.
Definition Xml.h:39
bool read_bool(const QString &node, bool default_value, bool inexistent_ok=true, bool empty_ok=true, bool bSilent=false)
reads a boolean stored into a child node
Definition Xml.cpp:184
QString read_string(const QString &node, const QString &default_value, bool inexistent_ok=true, bool empty_ok=true, bool bSilent=false)
reads a string stored into a child node
Definition Xml.cpp:95
XMLNode createNode(const QString &name)
create a new XMLNode that has to be appended into de XMLDoc
Definition Xml.cpp:63
void write_string(const QString &node, const QString &value)
write a string into a child node
Definition Xml.cpp:269
void write_bool(const QString &node, const bool value)
write a boolean into a child node
Definition Xml.cpp:288
@ EVENT_PLAYLIST_LOADSONG
Definition EventQueue.h:100