1 /*
2 * Hydrogen
3 * Copyright(c) 2002-2008 by Alex >Comix< Cominu [comix@users.sourceforge.net]
4 *
5 * http://www.hydrogen-music.org
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY, without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 *
21 */
22
23
24 #include "PlaylistDialog.h"
25 #include "../HydrogenApp.h"
26 #include "../InstrumentRack.h"
27 #include "SoundLibrary/SoundLibraryPanel.h"
28 #include "SongEditor/SongEditorPanel.h"
29 #include "Widgets/PixmapWidget.h"
30
31 #include <hydrogen/helpers/files.h>
32 #include <hydrogen/helpers/filesystem.h>
33 #include <hydrogen/h2_exception.h>
34 #include <hydrogen/Preferences.h>
35 #include <hydrogen/hydrogen.h>
36 #include <hydrogen/timeline.h>
37 #include <hydrogen/event_queue.h>
38 #include <hydrogen/basics/playlist.h>
39
40 #include "../Widgets/Button.h"
41
42 #include <QTreeWidget>
43 #include <QDomDocument>
44 #include <QMessageBox>
45 #include <QHeaderView>
46 #include <QFileDialog>
47 #include <vector>
48 #include <cstdlib>
49 #include <iostream>
50 #include <fstream>
51 #include <memory>
52
53 using namespace H2Core;
54 using namespace std;
55
56 const char* PlaylistDialog::__class_name = "PlaylistDialog";
57
PlaylistDialog(QWidget * pParent)58 PlaylistDialog::PlaylistDialog ( QWidget* pParent )
59 : QDialog ( pParent )
60 , Object ( __class_name )
61 {
62
63 setupUi ( this );
64 INFOLOG ( "INIT" );
65 setWindowTitle ( tr ( "Playlist Browser" ) + QString(" - ") + Playlist::get_instance()->getFilename() );
66 setFixedSize ( width(), height() );
67
68 installEventFilter( this );
69
70 // menubar
71 QMenuBar *m_pMenubar = new QMenuBar( this );
72
73 // Playlist menu
74 QMenu *m_pPlaylistMenu = m_pMenubar->addMenu( tr( "&Playlist" ) );
75
76 m_pPlaylistMenu->addAction( tr( "Add song to Play&list" ), this, SLOT( addSong() ), QKeySequence( "Ctrl+A" ) );
77 m_pPlaylistMenu->addAction( tr( "Add ¤t song to Playlist" ), this, SLOT( addCurrentSong() ), QKeySequence( "Ctrl+Alt+A" ) );
78 m_pPlaylistMenu->addSeparator(); // -----
79 m_pPlaylistMenu->addAction( tr( "&Remove selected song from Playlist" ), this, SLOT( removeFromList() ), QKeySequence::Delete );
80 m_pPlaylistMenu->addAction( tr( "&New Playlist" ), this, SLOT( clearPlaylist() ), QKeySequence( "Ctrl+N" ) );
81 m_pPlaylistMenu->addSeparator();
82 m_pPlaylistMenu->addAction( tr( "&Open Playlist" ), this, SLOT( loadList() ), QKeySequence( "Ctrl+O" ) );
83 m_pPlaylistMenu->addSeparator();
84 m_pPlaylistMenu->addAction( tr( "&Save Playlist" ), this, SLOT( saveList() ), QKeySequence( "Ctrl+S" ) );
85 m_pPlaylistMenu->addAction( tr( "Save Playlist &as" ), this, SLOT( saveListAs() ), QKeySequence( "Ctrl+Shift+S" ) );
86
87 #ifdef WIN32
88 //no scripts under windows
89 #else
90 // Script menu
91 QMenu *m_pScriptMenu = m_pMenubar->addMenu( tr( "&Scripts" ) );
92
93 m_pScriptMenu->addAction( tr( "&Add Script to selected song" ), this, SLOT( loadScript() ), QKeySequence( "" ) );
94 m_pScriptMenu->addAction( tr( "&Edit selected Script" ), this, SLOT( editScript() ), QKeySequence( "" ) );
95 m_pScriptMenu->addSeparator();
96 m_pScriptMenu->addAction( tr( "&Remove selected Script" ), this, SLOT( removeScript() ), QKeySequence( "" ) );
97 m_pScriptMenu->addSeparator();
98 m_pScriptMenu->addAction( tr( "&Create a new Script" ), this, SLOT( newScript() ), QKeySequence( "" ) );
99 #endif
100
101 // CONTROLS
102 PixmapWidget *pControlsPanel = new PixmapWidget( nullptr );
103 pControlsPanel->setFixedSize( 119, 32 );
104 pControlsPanel->setPixmap( "/playerControlPanel/playlist_background_Control.png" );
105 vboxLayout->addWidget( pControlsPanel );
106
107 // Rewind button
108 m_pRwdBtn = new Button(
109 pControlsPanel,
110 "/playerControlPanel/btn_rwd_on.png",
111 "/playerControlPanel/btn_rwd_off.png",
112 "/playerControlPanel/btn_rwd_over.png",
113 QSize(21, 15)
114 );
115 m_pRwdBtn->move(6, 6);
116 m_pRwdBtn->setToolTip( tr("Rewind") );
117 connect(m_pRwdBtn, SIGNAL(clicked(Button*)), this, SLOT(rewindBtnClicked(Button*)));
118
119 // Play button
120 m_pPlayBtn = new ToggleButton(
121 pControlsPanel,
122 "/playerControlPanel/btn_play_on.png",
123 "/playerControlPanel/btn_play_off.png",
124 "/playerControlPanel/btn_play_over.png",
125 QSize(33, 17)
126 );
127 m_pPlayBtn->move(33, 6);
128 m_pPlayBtn->setPressed(false);
129 m_pPlayBtn->setToolTip( tr("Play/ Pause/ Load selected song") );
130 connect(m_pPlayBtn, SIGNAL(clicked(Button*)), this, SLOT(nodePlayBTN(Button*)));
131
132 // Stop button
133 m_pStopBtn = new Button(
134 pControlsPanel,
135 "/playerControlPanel/btn_stop_on.png",
136 "/playerControlPanel/btn_stop_off.png",
137 "/playerControlPanel/btn_stop_over.png",
138 QSize(21, 15)
139 );
140 m_pStopBtn->move(65, 6);
141 m_pStopBtn->setToolTip( tr("Stop") );
142 connect(m_pStopBtn, SIGNAL(clicked(Button*)), this, SLOT(nodeStopBTN(Button*)));
143
144 // Fast forward button
145 m_pFfwdBtn = new Button(
146 pControlsPanel,
147 "/playerControlPanel/btn_ffwd_on.png",
148 "/playerControlPanel/btn_ffwd_off.png",
149 "/playerControlPanel/btn_ffwd_over.png",
150 QSize(21, 15)
151 );
152 m_pFfwdBtn->move(92, 6);
153 m_pFfwdBtn->setToolTip( tr("Fast Forward") );
154 connect(m_pFfwdBtn, SIGNAL(clicked(Button*)), this, SLOT(ffWDBtnClicked(Button*)));
155
156 #ifdef WIN32
157 QStringList headers;
158 headers << tr ( "Song list" );
159 QTreeWidgetItem* header = new QTreeWidgetItem ( headers );
160 m_pPlaylistTree->setHeaderItem ( header );
161 m_pPlaylistTree->setAlternatingRowColors( true );
162
163 /*addSongBTN->setEnabled ( true );
164 loadListBTN->setEnabled ( true );
165 removeFromListBTN->setEnabled ( false );
166 removeFromListBTN->setEnabled ( false );
167 saveListBTN->setEnabled ( false );
168 saveListAsBTN->setEnabled ( false );
169 loadScriptBTN->hide();
170 removeScriptBTN->hide();
171 editScriptBTN->hide();
172 newScriptBTN->hide();
173 clearPlBTN->setEnabled ( false );*/
174
175 QVBoxLayout *pSideBarLayout = new QVBoxLayout(sideBarWidget);
176 pSideBarLayout->setSpacing(0);
177 pSideBarLayout->setMargin(0);
178
179 #else
180 QStringList headers;
181 headers << tr ( "Song list" ) << tr ( "Script" ) << tr ( "exec Script" );
182 QTreeWidgetItem* header = new QTreeWidgetItem ( headers );
183 m_pPlaylistTree->setHeaderItem ( header );
184 m_pPlaylistTree->header()->resizeSection ( 0, 405 );
185 m_pPlaylistTree->header()->resizeSection ( 1, 405 );
186 m_pPlaylistTree->header()->resizeSection ( 2, 15 );
187 m_pPlaylistTree->setAlternatingRowColors( true );
188
189
190 QVBoxLayout *pSideBarLayout = new QVBoxLayout(sideBarWidget);
191 pSideBarLayout->setSpacing(0);
192 pSideBarLayout->setMargin(0);
193 #endif
194
195 // zoom-in btn
196 Button *pUpBtn = new Button(
197 nullptr,
198 "/songEditor/btn_up_on.png",
199 "/songEditor/btn_up_off.png",
200 "/songEditor/btn_up_over.png",
201 QSize(18, 13)
202 );
203
204 pUpBtn->setFontSize(7);
205 pUpBtn->setToolTip( tr( "sort" ) );
206 connect(pUpBtn, SIGNAL(clicked(Button*)), this, SLOT(o_upBClicked()) );
207 pSideBarLayout->addWidget(pUpBtn);
208
209 // zoom-in btn
210 Button *pDownBtn = new Button(
211 nullptr,
212 "/songEditor/btn_down_on.png",
213 "/songEditor/btn_down_off.png",
214 "/songEditor/btn_down_over.png",
215 QSize(18, 13)
216 );
217
218 pDownBtn->setFontSize(7);
219 pDownBtn->setToolTip( tr( "sort" ) );
220 connect(pDownBtn, SIGNAL(clicked(Button*)), this, SLOT(o_downBClicked()));
221 pSideBarLayout->addWidget(pDownBtn);
222
223 //restore the playlist
224 Playlist* pPlaylist = Playlist::get_instance();
225 if( pPlaylist->size() > 0 ){
226 for ( uint i = 0; i < pPlaylist->size(); ++i ){
227 QTreeWidgetItem* pPlaylistItem = new QTreeWidgetItem ( m_pPlaylistTree );
228
229 pPlaylistItem->setText( 0, pPlaylist->get( i )->filePath );
230 pPlaylistItem->setText( 1, pPlaylist->get( i )->scriptPath );
231
232 if ( pPlaylist->get( i )->scriptEnabled ) {
233 pPlaylistItem->setCheckState( 2, Qt::Checked );
234 } else {
235 pPlaylistItem->setCheckState( 2, Qt::Unchecked );
236 }
237 }
238
239 //restore the selected item
240 int selected = Playlist::get_instance()->getActiveSongNumber();
241 int Selected = Playlist::get_instance()->getSelectedSongNr();
242 if( selected == -1 && Selected == -1 ) return;
243
244 int aselected = 0;
245 if( selected == -1 ){
246 aselected = Selected;
247 } else {
248 aselected = selected ;
249 }
250
251 QTreeWidgetItem* m_pPlaylistItem = m_pPlaylistTree->topLevelItem ( aselected );
252 m_pPlaylistItem->setBackground( 0, QColor( 50, 50, 50) );
253 m_pPlaylistItem->setBackground( 1, QColor( 50, 50, 50) );
254 m_pPlaylistItem->setBackground( 2, QColor( 50, 50, 50) );
255 }
256
257 timer = new QTimer( this );
258 connect(timer, SIGNAL(timeout() ), this, SLOT( updateActiveSongNumber() ) );
259 timer->start( 1000 ); // update player control at 1 fps
260 }
261
~PlaylistDialog()262 PlaylistDialog::~PlaylistDialog()
263 {
264 INFOLOG ( "DESTROY" );
265 }
266
keyPressEvent(QKeyEvent * ev)267 void PlaylistDialog::keyPressEvent( QKeyEvent* ev )
268 {
269 if(ev->key() == Qt::Key_Escape) {
270 HydrogenApp::get_instance()->showPlaylistDialog();
271 }
272 }
273
closeEvent(QCloseEvent * ev)274 void PlaylistDialog::closeEvent( QCloseEvent* ev )
275 {
276 HydrogenApp::get_instance()->showPlaylistDialog();
277 }
278
addSong()279 void PlaylistDialog::addSong()
280 {
281 QFileDialog fd(this);
282 fd.setWindowTitle( tr( "Add Song to PlayList" ) );
283 fd.setFileMode( QFileDialog::ExistingFiles );
284 fd.setNameFilter( Filesystem::songs_filter_name );
285 fd.setDirectory( Filesystem::songs_dir() );
286
287 if ( fd.exec() != QDialog::Accepted ) {
288 return;
289 }
290
291 foreach( QString filePath, fd.selectedFiles() ) {
292 updatePlayListNode( filePath );
293 }
294 }
295
addCurrentSong()296 void PlaylistDialog::addCurrentSong()
297 {
298 Song * pSong = Hydrogen::get_instance()->getSong();
299 QString filename = pSong->get_filename();
300
301 if (filename == "") {
302 // just in case!
303 QMessageBox::information ( this, "Hydrogen", tr ( "Please save your song first" ));
304 return;
305 }
306 updatePlayListNode ( filename );
307 }
308
removeFromList()309 void PlaylistDialog::removeFromList()
310 {
311 QTreeWidgetItem* pPlaylistItem = m_pPlaylistTree->currentItem();
312 int index = m_pPlaylistTree->indexOfTopLevelItem ( pPlaylistItem );
313 QTreeWidgetItem * pTmpItem = m_pPlaylistTree->topLevelItem ( 1 );
314
315 if (pPlaylistItem == nullptr){
316 QMessageBox::information ( this, "Hydrogen", tr ( "No Song selected!" ));
317 } else {
318 if (pTmpItem == nullptr){
319 m_pPlaylistTree->clear();
320 Playlist::get_instance()->clear();
321 Playlist::get_instance()->setSelectedSongNr( -1 );
322 Playlist::get_instance()->setActiveSongNumber( -1 );
323 Playlist::get_instance()->setFilename( "" );
324 setWindowTitle ( tr ( "Playlist Browser" ) );
325
326 return;
327 } else {
328 ///avoid segfault if the last item will be removed!!
329 ///
330 delete pPlaylistItem;
331
332 updatePlayListVector();
333 if ( Playlist::get_instance()->getActiveSongNumber() == index ){
334 Playlist::get_instance()->setActiveSongNumber( -1 );
335 } else if ( Playlist::get_instance()->getActiveSongNumber() > index ){
336 Playlist::get_instance()->setActiveSongNumber( Playlist::get_instance()->getActiveSongNumber() -1 );
337 }
338 }
339 }
340 }
341
clearPlaylist()342 void PlaylistDialog::clearPlaylist()
343 {
344 bool DiscardChanges = false;
345 bool IsModified = Playlist::get_instance()->getIsModified();
346
347 if( IsModified )
348 {
349 switch(QMessageBox::information( this, "Hydrogen",
350 tr("\nThe current playlist contains unsaved changes.\n"
351 "Do you want to discard the changes?\n"),
352 tr("&Discard"), tr("&Cancel"),
353 nullptr, // Enter == button 0
354 2 ) ) { // Escape == button 1
355 case 0: // Discard clicked or Alt+D pressed
356 // don't save but exit
357 DiscardChanges = true;
358 break;
359 case 1: // Cancel clicked or Alt+C pressed or Escape pressed
360 // don't exit
361 DiscardChanges = false;
362 break;
363 }
364 }
365
366 if(!IsModified || (IsModified && DiscardChanges))
367 {
368 m_pPlaylistTree->clear();
369 Playlist::get_instance()->clear();
370 Playlist::get_instance()->setSelectedSongNr( -1 );
371 Playlist::get_instance()->setActiveSongNumber( -1 );
372 Playlist::get_instance()->setFilename ( "" );
373 setWindowTitle ( tr ( "Playlist Browser" ) );
374
375 Playlist::get_instance()->setIsModified(false);
376 }
377 return;
378 }
379
updatePlayListNode(QString file)380 void PlaylistDialog::updatePlayListNode ( QString file )
381 {
382 QTreeWidgetItem* m_pPlaylistItem = new QTreeWidgetItem ( m_pPlaylistTree );
383 m_pPlaylistItem->setText ( 0, file );
384 m_pPlaylistItem->setText ( 1, tr("no Script") );
385 m_pPlaylistItem->setCheckState( 2, Qt::Unchecked );
386
387 updatePlayListVector();
388
389 m_pPlaylistTree->setCurrentItem ( m_pPlaylistItem );
390 }
391
loadList()392 void PlaylistDialog::loadList()
393 {
394 QFileDialog fd(this);
395 fd.setWindowTitle( tr( "Load Playlist" ) );
396 fd.setFileMode( QFileDialog::ExistingFile );
397 fd.setDirectory( Filesystem::playlists_dir() );
398 fd.setNameFilter( Filesystem::playlists_filter_name );
399
400 if ( fd.exec() != QDialog::Accepted ) {
401 return;
402 }
403
404 QString filename = fd.selectedFiles().first();
405
406 bool relativePaths = Preferences::get_instance()->isPlaylistUsingRelativeFilenames();
407 Playlist* pPlaylist = Playlist::load( filename, relativePaths);
408 if ( ! pPlaylist ) {
409 _ERRORLOG( "Error loading the playlist" );
410 /* FIXME: get current instance (?) */
411 pPlaylist = Playlist::get_instance();
412 }
413
414 Playlist* playlist = Playlist::get_instance();
415 if( playlist->size() > 0 ) {
416 QTreeWidget* m_pPlaylist = m_pPlaylistTree;
417 m_pPlaylist->clear();
418
419 for ( uint i = 0; i < playlist->size(); ++i ){
420 QTreeWidgetItem* m_pPlaylistItem = new QTreeWidgetItem ( m_pPlaylistTree );
421
422 if( playlist->get( i )->fileExists ){
423 m_pPlaylistItem->setText( 0, playlist->get( i )->filePath );
424 } else {
425 m_pPlaylistItem->setText( 0, tr("File not found: ") + playlist->get( i )->filePath );
426 }
427
428 m_pPlaylistItem->setText ( 1, playlist->get( i )->scriptPath );
429
430 if ( playlist->get( i )->scriptEnabled ) {
431 m_pPlaylistItem->setCheckState( 2, Qt::Checked );
432 } else {
433 m_pPlaylistItem->setCheckState( 2, Qt::Unchecked );
434 }
435 }
436
437 QTreeWidgetItem* m_pPlaylistItem = m_pPlaylist->topLevelItem ( 0 );
438 m_pPlaylist->setCurrentItem ( m_pPlaylistItem );
439 pPlaylist->setSelectedSongNr( 0 );
440 setWindowTitle ( tr ( "Playlist Browser" ) + QString(" - ") + pPlaylist->getFilename() );
441 }
442 }
443
newScript()444 void PlaylistDialog::newScript()
445 {
446
447 Preferences *pPref = Preferences::get_instance();
448
449 QFileDialog fd(this);
450 fd.setFileMode ( QFileDialog::AnyFile );
451 fd.setNameFilter( Filesystem::scripts_filter_name );
452 fd.setAcceptMode ( QFileDialog::AcceptSave );
453 fd.setWindowTitle ( tr ( "New Script" ) );
454 fd.setDirectory( Filesystem::scripts_dir() );
455
456 QString defaultFilename;
457
458 defaultFilename += ".sh";
459
460 fd.selectFile ( defaultFilename );
461
462 QString filename;
463 if ( fd.exec() != QDialog::Accepted ) return;
464
465 filename = fd.selectedFiles().first();
466
467 if( filename.contains(" ", Qt::CaseInsensitive)){
468 QMessageBox::information ( this, "Hydrogen", tr ( "Script name or path to the script contains whitespaces.\nIMPORTANT\nThe path to the script and the scriptname must be without whitespaces.") );
469 return;
470 }
471
472 QFile chngPerm ( filename );
473 if (!chngPerm.open(QIODevice::WriteOnly | QIODevice::Text)) {
474 return;
475 }
476
477 QTextStream out(&chngPerm);
478 out << "#!/bin/sh\n\n#have phun";
479 chngPerm.close();
480
481 if (chngPerm.exists() ) {
482 chngPerm.setPermissions( QFile::ReadOwner|QFile::WriteOwner|QFile::ExeOwner );
483 QMessageBox::information ( this, "Hydrogen", tr ( "WARNING, the new file is executable by the owner of the file!" ) );
484 }
485
486 if( pPref->getDefaultEditor().isEmpty() ){
487 QMessageBox::information ( this, "Hydrogen", tr ( "No Default Editor Set. Please set your Default Editor\nDo not use a console based Editor\nSorry, but this will not work for the moment." ) );
488
489 static QString lastUsedDir = "/usr/bin/";
490
491 QFileDialog fd(this);
492 fd.setFileMode ( QFileDialog::ExistingFile );
493 fd.setDirectory ( lastUsedDir );
494
495 fd.setWindowTitle ( tr ( "Set your Default Editor" ) );
496
497 QString filename;
498 if ( fd.exec() == QDialog::Accepted ){
499 filename = fd.selectedFiles().first();
500
501 pPref->setDefaultEditor( filename );
502 }
503 }
504
505 QString openfile = pPref->getDefaultEditor() + " " + filename + "&";
506
507 char *ofile;
508 ofile = new char[openfile.length() + 1];
509 strcpy(ofile, openfile.toLatin1());
510 std::system( ofile );
511 delete [] ofile;
512 return;
513 }
514
saveListAs()515 void PlaylistDialog::saveListAs()
516 {
517 QFileDialog fd(this);
518 fd.setWindowTitle( tr( "Save Playlist" ) );
519 fd.setFileMode( QFileDialog::AnyFile );
520 fd.setNameFilter( Filesystem::playlists_filter_name );
521 fd.setAcceptMode( QFileDialog::AcceptSave );
522 fd.setDirectory( Filesystem::playlists_dir() );
523 fd.selectFile( Filesystem::untitled_playlist_file_name() );
524 fd.setDefaultSuffix( Filesystem::playlist_ext );
525
526 if ( fd.exec() != QDialog::Accepted ) {
527 return;
528 }
529
530 QString filename = fd.selectedFiles().first();
531
532 Playlist* pPlaylist = Playlist::get_instance();
533 bool relativePaths = Preferences::get_instance()->isPlaylistUsingRelativeFilenames();
534 if ( Files::savePlaylistPath( filename, pPlaylist, relativePaths ) == nullptr ) {
535 return;
536 }
537
538 pPlaylist->setIsModified( false );
539
540 setWindowTitle( tr( "Playlist Browser" ) + QString(" - %1").arg( filename ) );
541 }
542
saveList()543 void PlaylistDialog::saveList()
544 {
545 Playlist* pPlaylist = Playlist::get_instance();
546 if ( pPlaylist->getFilename().isEmpty() ) {
547 return saveListAs();
548 }
549
550 bool relativePaths = Preferences::get_instance()->isPlaylistUsingRelativeFilenames();
551 if ( Files::savePlaylistPath( pPlaylist->getFilename(), pPlaylist, relativePaths ) == nullptr ) {
552 return;
553 }
554
555 pPlaylist->setIsModified( false );
556 }
557
loadScript()558 void PlaylistDialog::loadScript()
559 {
560
561 QTreeWidgetItem* pPlaylistItem = m_pPlaylistTree->currentItem();
562 if ( pPlaylistItem == nullptr ){
563 QMessageBox::information ( this, "Hydrogen", tr ( "No Song in List or no Song selected!" ) );
564 return;
565 }
566
567 static QString lastUsedDir = Filesystem::scripts_dir();
568
569 QFileDialog fd(this);
570 fd.setFileMode ( QFileDialog::ExistingFile );
571 fd.setDirectory ( lastUsedDir );
572 fd.setNameFilter ( tr ( "Hydrogen Playlist (*.sh)" ) );
573 fd.setWindowTitle ( tr ( "Add Script to selected Song" ) );
574
575 QString filename;
576 if ( fd.exec() == QDialog::Accepted ){
577 filename = fd.selectedFiles().first();
578
579 if( filename.contains(" ", Qt::CaseInsensitive)){
580 QMessageBox::information ( this, "Hydrogen", tr ( "Script name or path to the script contains whitespaces.\nIMPORTANT\nThe path to the script and the scriptname must without whitespaces.") );
581 return;
582 }
583
584 pPlaylistItem->setText ( 1, filename );
585 updatePlayListVector();
586
587 }
588 }
589
removeScript()590 void PlaylistDialog::removeScript()
591 {
592 QTreeWidgetItem* m_pPlaylistItem = m_pPlaylistTree->currentItem();
593
594
595 if (m_pPlaylistItem == nullptr){
596 QMessageBox::information ( this, "Hydrogen", tr ( "No Song selected!" ));
597 return;
598 } else {
599 QString selected;
600 selected = m_pPlaylistItem->text ( 1 );
601 if( !QFile( selected ).exists() ){
602 QMessageBox::information ( this, "Hydrogen", tr ( "No Script in use!" ));
603 return;
604 } else {
605 m_pPlaylistItem->setText ( 1, tr("no Script") );
606
607 m_pPlaylistItem->setCheckState( 2, Qt::Unchecked );
608 updatePlayListVector();
609 }
610 }
611
612 }
613
editScript()614 void PlaylistDialog::editScript()
615 {
616 Preferences *pPref = Preferences::get_instance();
617 if( pPref->getDefaultEditor().isEmpty() ){
618 QMessageBox::information ( this, "Hydrogen", tr ( "No Default Editor Set. Please set your Default Editor\nDo not use a console based Editor\nSorry, but this will not work for the moment." ) );
619
620 static QString lastUsedDir = "/usr/bin/";
621
622 QFileDialog fd(this);
623 fd.setFileMode ( QFileDialog::ExistingFile );
624 fd.setDirectory ( lastUsedDir );
625
626 fd.setWindowTitle ( tr ( "Set your Default Editor" ) );
627
628 QString filename;
629 if ( fd.exec() == QDialog::Accepted ){
630 filename = fd.selectedFiles().first();
631
632 pPref->setDefaultEditor( filename );
633 }
634 }
635
636 QTreeWidgetItem* pPlaylistItem = m_pPlaylistTree->currentItem();
637
638 if ( pPlaylistItem == nullptr ){
639 QMessageBox::information ( this, "Hydrogen", tr ( "No Song selected!" ) );
640 return;
641 }
642 QString selected;
643 selected = pPlaylistItem->text ( 1 );
644
645 QString filename = pPref->getDefaultEditor() + " " + selected + "&";
646
647 if( !QFile( selected ).exists() ){
648 QMessageBox::information ( this, "Hydrogen", tr ( "No Script selected!" ));
649 return;
650 }
651
652 char *file;
653 file = new char[ filename.length() + 1 ];
654 strcpy( file , filename.toLatin1() );
655 std::system( file );
656 delete [] file;
657 return;
658
659 }
660
o_upBClicked()661 void PlaylistDialog::o_upBClicked()
662 {
663 timer->stop();
664
665 Playlist* pPlaylist = Playlist::get_instance();
666
667 QTreeWidget* pPlaylistTree = m_pPlaylistTree;
668 QTreeWidgetItem* pPlaylistTreeItem = m_pPlaylistTree->currentItem();
669 int index = pPlaylistTree->indexOfTopLevelItem ( pPlaylistTreeItem );
670
671 if (index == 0 ){
672 timer->start( 1000 );
673 return;
674 }
675
676 QTreeWidgetItem* tmpPlaylistItem = pPlaylistTree->takeTopLevelItem ( index );
677
678 pPlaylistTree->insertTopLevelItem ( index -1, tmpPlaylistItem );
679 pPlaylistTree->setCurrentItem ( tmpPlaylistItem );
680
681 if ( pPlaylist->getSelectedSongNr() >= 0 ){
682 pPlaylist->setSelectedSongNr( pPlaylist->getSelectedSongNr() -1 );
683 }
684
685 if ( pPlaylist->getActiveSongNumber() == index ){
686 pPlaylist->setActiveSongNumber( pPlaylist->getActiveSongNumber() -1 );
687 }else if ( pPlaylist->getActiveSongNumber() == index -1 ){
688 pPlaylist->setActiveSongNumber( pPlaylist->getActiveSongNumber() +1 );
689 }
690
691 updatePlayListVector();
692 }
693
o_downBClicked()694 void PlaylistDialog::o_downBClicked()
695 {
696 timer->stop();
697 Playlist* pPlaylist = Playlist::get_instance();
698
699 QTreeWidget* m_pPlaylist = m_pPlaylistTree;
700 int length = m_pPlaylist->topLevelItemCount();
701 QTreeWidgetItem* m_pPlaylistItem = m_pPlaylistTree->currentItem();
702 int index = m_pPlaylist->indexOfTopLevelItem ( m_pPlaylistItem );
703
704 if ( index == length - 1){
705 timer->start( 1000 );
706 return;
707 }
708
709 QTreeWidgetItem* pTmpPlaylistItem = m_pPlaylist->takeTopLevelItem ( index );
710
711 m_pPlaylist->insertTopLevelItem ( index +1, pTmpPlaylistItem );
712 m_pPlaylist->setCurrentItem ( pTmpPlaylistItem );
713
714 if ( pPlaylist->getSelectedSongNr() >= 0 ) {
715 pPlaylist->setSelectedSongNr( pPlaylist->getSelectedSongNr() +1 );
716 }
717
718 if (pPlaylist ->getActiveSongNumber() == index ){
719 pPlaylist->setActiveSongNumber( pPlaylist->getActiveSongNumber() +1 );
720 }else if ( pPlaylist->getActiveSongNumber() == index +1 ){
721 pPlaylist->setActiveSongNumber( pPlaylist->getActiveSongNumber() -1 );
722 }
723 updatePlayListVector();
724
725 }
726
on_m_pPlaylistTree_itemClicked(QTreeWidgetItem * item,int column)727 void PlaylistDialog::on_m_pPlaylistTree_itemClicked ( QTreeWidgetItem * item, int column )
728 {
729 if ( column == 2 ){
730 QString selected;
731 selected = item->text ( 1 );
732
733 if( !QFile( selected ).exists() ){
734 QMessageBox::information ( this, "Hydrogen", tr ( "No Script!" ));
735 item->setCheckState( 2, Qt::Unchecked );
736 return;
737 }
738 updatePlayListVector();
739 }
740 return;
741 }
742
nodePlayBTN(Button * ref)743 void PlaylistDialog::nodePlayBTN( Button* ref )
744 {
745 Hydrogen * pEngine = Hydrogen::get_instance();
746 HydrogenApp * pH2App = HydrogenApp::get_instance();
747
748 if (ref->isPressed()) {
749 QTreeWidgetItem* m_pPlaylistItem = m_pPlaylistTree->currentItem();
750 if ( m_pPlaylistItem == nullptr ){
751 QMessageBox::information ( this, "Hydrogen", tr ( "No valid song selected!" ) );
752 m_pPlayBtn->setPressed(false);
753 return;
754 }
755 QString selected = "";
756 selected = m_pPlaylistItem->text ( 0 );
757
758 if( selected == pEngine->getSong()->get_filename()){
759 pEngine->sequencer_play();
760 return;
761 }
762
763 if ( pEngine->getState() == STATE_PLAYING ){
764 pEngine->sequencer_stop();
765 }
766
767 Song *pSong = Song::load ( selected );
768 if ( pSong == nullptr ){
769 QMessageBox::information ( this, "Hydrogen", tr ( "Error loading song." ) );
770 m_pPlayBtn->setPressed(false);
771 return;
772 }
773
774 QTreeWidget* m_pPlaylist = m_pPlaylistTree;
775 int index = m_pPlaylist->indexOfTopLevelItem ( m_pPlaylistItem );
776 Playlist::get_instance()->setActiveSongNumber( index );
777
778 pH2App->setSong ( pSong );
779 pEngine->setSelectedPatternNumber ( 0 );
780
781 pEngine->sequencer_play();
782 }else
783 {
784 pEngine->sequencer_stop();
785 pH2App->setStatusBarMessage(tr("Pause."), 5000);
786 }
787 }
788
nodeStopBTN(Button * ref)789 void PlaylistDialog::nodeStopBTN( Button* ref )
790 {
791 UNUSED( ref );
792 m_pPlayBtn->setPressed(false);
793 Hydrogen::get_instance()->sequencer_stop();
794 Hydrogen::get_instance()->setPatternPos ( 0 );
795 }
796
ffWDBtnClicked(Button * ref)797 void PlaylistDialog::ffWDBtnClicked( Button* ref)
798 {
799 UNUSED( ref );
800 Hydrogen *pEngine = Hydrogen::get_instance();
801 pEngine->setPatternPos( pEngine->getPatternPos() + 1 );
802 }
803
rewindBtnClicked(Button * ref)804 void PlaylistDialog::rewindBtnClicked( Button* ref )
805 {
806 UNUSED( ref );
807 Hydrogen *pEngine = Hydrogen::get_instance();
808 pEngine->setPatternPos( pEngine->getPatternPos() - 1 );
809 }
810
on_m_pPlaylistTree_itemDoubleClicked()811 void PlaylistDialog::on_m_pPlaylistTree_itemDoubleClicked ()
812 {
813 QTreeWidgetItem* pPlaylistItem = m_pPlaylistTree->currentItem();
814 if ( pPlaylistItem == nullptr ){
815 QMessageBox::information ( this, "Hydrogen", tr ( "No Song selected!" ) );
816 return;
817 }
818
819 QString selected;
820 selected = pPlaylistItem->text ( 0 );
821
822 int index = m_pPlaylistTree->indexOfTopLevelItem ( pPlaylistItem );
823 Playlist::get_instance()->setSelectedSongNr( index );
824 Playlist::get_instance()->setActiveSongNumber( index );
825
826 HydrogenApp *pH2App = HydrogenApp::get_instance();
827 Hydrogen *pEngine = Hydrogen::get_instance();
828
829 if ( pEngine->getState() == STATE_PLAYING ){
830 pEngine->sequencer_stop();
831 }
832
833 m_pPlayBtn->setPressed(false);
834
835 Timeline* pTimeline = pEngine->getTimeline();
836 pTimeline->m_timelinetagvector.clear();
837
838 Song *pSong = Song::load ( selected );
839 if ( pSong == nullptr ){
840 QMessageBox::information ( this, "Hydrogen", tr ( "Error loading song." ) );
841 return;
842 }
843
844 pH2App->setSong ( pSong );
845 pEngine->setSelectedPatternNumber ( 0 );
846
847 HydrogenApp::get_instance()->getSongEditorPanel()->updatePositionRuler();
848 pH2App->setStatusBarMessage( tr( "Playlist: set song no. %1" ).arg( index +1 ), 5000 );
849
850 HydrogenApp::get_instance()->getInstrumentRack()->getSoundLibraryPanel()->update_background_color();
851
852 EventQueue::get_instance()->push_event( EVENT_METRONOME, 3 );
853
854 ///exec script
855 ///this is very very simple and only an experiment
856 #ifdef WIN32
857 //I know nothing about windows scripts -wolke-
858 return;
859 #else
860 QString execscript;
861 selected = pPlaylistItem->text ( 1 );
862 bool execcheckbox = pPlaylistItem->checkState ( 2 );
863
864 if( execcheckbox == false){
865 //QMessageBox::information ( this, "Hydrogen", tr ( "No Script selected!" ));
866 return;
867 }
868
869 if( execscript == "Script not used"){
870 //QMessageBox::information ( this, "Hydrogen", tr ( "Script not in use!" ));
871 return;
872 }
873
874 char *file;
875 file = new char[ selected.length() + 1 ];
876 strcpy( file , selected.toLatin1() );
877 std::system( file );
878 delete [] file;
879 return;
880 #endif
881
882 }
883
884
updatePlayListVector()885 void PlaylistDialog::updatePlayListVector()
886 {
887 int length = m_pPlaylistTree->topLevelItemCount();
888
889 Playlist::get_instance()->clear();
890
891 for (int i = 0 ;i < length; i++){
892 QTreeWidgetItem * pPlaylistItem = m_pPlaylistTree->topLevelItem ( i );
893
894 Playlist::Entry* entry = new Playlist::Entry();
895 entry->filePath = pPlaylistItem->text( 0 );
896 entry->scriptPath = pPlaylistItem->text( 1 );
897 entry->scriptEnabled = pPlaylistItem->checkState( 2 );
898
899 Playlist::get_instance()->add( entry );
900 Playlist::get_instance()->setIsModified(true);
901 }
902 timer->start( 1000 );
903 }
904
905
updateActiveSongNumber()906 void PlaylistDialog::updateActiveSongNumber()
907 {
908 for ( uint i = 0; i < Playlist::get_instance()->size(); ++i ){
909 if ( !m_pPlaylistTree->topLevelItem( i ) ) {
910 break;
911 }
912 ( m_pPlaylistTree->topLevelItem( i ) )->setBackground( 0, QBrush() );
913 ( m_pPlaylistTree->topLevelItem( i ) )->setBackground( 1, QBrush() );
914 ( m_pPlaylistTree->topLevelItem( i ) )->setBackground( 2, QBrush() );
915
916 }
917
918 int selected = Playlist::get_instance()->getActiveSongNumber();
919 if ( selected == -1 ) {
920 return;
921 }
922
923 QTreeWidgetItem* pPlaylistItem = m_pPlaylistTree->topLevelItem ( selected );
924 if ( pPlaylistItem != nullptr ){
925 pPlaylistItem->setBackground( 0, QColor( 50, 50, 50) );
926 pPlaylistItem->setBackground( 1, QColor( 50, 50, 50) );
927 pPlaylistItem->setBackground( 2, QColor( 50, 50, 50) );
928 }
929 }
930
931
eventFilter(QObject * o,QEvent * e)932 bool PlaylistDialog::eventFilter ( QObject *o, QEvent *e )
933 {
934 UNUSED ( o );
935 if ( e->type() == QEvent::KeyPress ) {
936 QKeyEvent *k = ( QKeyEvent * ) e;
937
938 switch ( k->key() ) {
939 case Qt::Key_F5 :
940 if( Playlist::get_instance()->size() == 0
941 || Playlist::get_instance()->getActiveSongNumber() <=0) {
942 break;
943 }
944
945 Playlist::get_instance()->setNextSongByNumber(Playlist::get_instance()->getActiveSongNumber()-1);
946 return true;
947 break;
948 case Qt::Key_F6 :
949 if( Playlist::get_instance()->size() == 0
950 || Playlist::get_instance()->getActiveSongNumber() >= Playlist::get_instance()->size() -1) {
951 break;
952 }
953
954 Playlist::get_instance()->setNextSongByNumber(Playlist::get_instance()->getActiveSongNumber()+1);
955 return true;
956 break;
957 }
958 } else {
959 return false; // standard event processing
960 }
961
962 return false;
963 }
964
loadListByFileName(QString filename)965 bool PlaylistDialog::loadListByFileName( QString filename )
966 {
967 bool bUseRelativeFilenames = Preferences::get_instance()->isPlaylistUsingRelativeFilenames();
968
969 Playlist* pPlaylist = Playlist::load ( filename, bUseRelativeFilenames );
970 if ( !pPlaylist ) {
971 _ERRORLOG( "Error loading the playlist" );
972 return false;
973 }
974
975 Preferences::get_instance()->setLastPlaylistFilename( filename );
976
977 Playlist* playlist = Playlist::get_instance();
978 if ( playlist->size() > 0 ) {
979 QTreeWidget* m_pPlaylist = m_pPlaylistTree;
980 m_pPlaylist->clear();
981
982 for ( uint i = 0; i < playlist->size(); ++i ){
983 QTreeWidgetItem* m_pPlaylistItem = new QTreeWidgetItem ( m_pPlaylistTree );
984 m_pPlaylistItem->setText( 0, playlist->get( i )->filePath );
985 m_pPlaylistItem->setText( 1, playlist->get( i )->scriptPath );
986
987 if ( playlist->get( i )->scriptEnabled ) {
988 m_pPlaylistItem->setCheckState( 2, Qt::Checked );
989 } else {
990 m_pPlaylistItem->setCheckState( 2, Qt::Unchecked );
991 }
992 }
993
994 QTreeWidgetItem* m_pPlaylistItem = m_pPlaylist->topLevelItem ( 0 );
995 m_pPlaylist->setCurrentItem ( m_pPlaylistItem );
996 pPlaylist->setSelectedSongNr( 0 );
997 setWindowTitle ( tr ( "Playlist Browser" ) + QString(" - ") + pPlaylist->getFilename() );
998 }
999
1000 return true;
1001 }
1002