root/branches/undo/gui/src/MainForm.cpp @ 1568

Revision 1568, 44.6 KB (checked in by wolke, 3 years ago)

merge rev 1565:1567 from trunk

Line 
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#include "version.h"
23
24#include <sys/socket.h>
25
26#include <hydrogen/hydrogen.h>
27#include <hydrogen/playlist.h>
28#include <hydrogen/audio_engine.h>
29#include <hydrogen/smf/SMF.h>
30#include <hydrogen/Preferences.h>
31#include <hydrogen/LocalFileMng.h>
32#include <hydrogen/Pattern.h>
33#include <hydrogen/event_queue.h>
34using namespace H2Core;
35
36
37#include "AboutDialog.h"
38#include "AudioEngineInfoForm.h"
39#include "ExportSongDialog.h"
40#include "HydrogenApp.h"
41#include "InstrumentRack.h"
42#include "Skin.h"
43#include "MainForm.h"
44#include "PlayerControl.h"
45#include "HelpBrowser.h"
46#include "LadspaFXProperties.h"
47#include "SongPropertiesDialog.h"
48#include "UndoActions.h"
49
50#include "MetroBlinker.h"
51#include "Mixer/Mixer.h"
52#include "InstrumentEditor/InstrumentEditorPanel.h"
53#include "PatternEditor/PatternEditorPanel.h"
54#include "SongEditor/SongEditor.h"
55#include "SongEditor/SongEditorPanel.h"
56#include "SoundLibrary/SoundLibraryPanel.h"
57#include "SoundLibrary/SoundLibraryImportDialog.h"
58#include "SoundLibrary/SoundLibrarySaveDialog.h"
59#include "SoundLibrary/SoundLibraryExportDialog.h"
60
61#include <QtGui>
62
63#ifndef WIN32
64        #include <sys/time.h>
65#endif
66
67#ifdef LASH_SUPPORT
68#include <lash-1.0/lash/lash.h>
69#include <hydrogen/LashClient.h>
70#endif
71
72#include <memory>
73#include <cassert>
74
75using namespace std;
76using namespace H2Core;
77
78int MainForm::sigusr1Fd[2];
79
80MainForm::MainForm( QApplication *app, const QString& songFilename )
81 : QMainWindow( 0, 0 )
82 , Object( "MainForm" )
83{
84        setMinimumSize( QSize( 1000, 600 ) );
85        setWindowIcon( QPixmap( Skin::getImagePath() + "/icon16.png" ) );
86
87        if (::socketpair(AF_UNIX, SOCK_STREAM, 0, sigusr1Fd))
88           qFatal("Couldn't create HUP socketpair");
89        snUsr1 = new QSocketNotifier(sigusr1Fd[1], QSocketNotifier::Read, this);
90        connect(snUsr1, SIGNAL(activated(int)), this, SLOT( handleSigUsr1() ));
91
92
93
94        m_pQApp = app;
95
96        m_pQApp->processEvents();
97
98        // Load default song
99        Song *song = NULL;
100        if ( !songFilename.isEmpty() ) {
101                song = Song::load( songFilename );
102                if (song == NULL) {
103                        //QMessageBox::warning( this, "Hydrogen", trUtf8("Error loading song.") );
104                        song = Song::get_empty_song();
105                        song->set_filename( "" );
106                }
107        }
108        else {
109                Preferences *pref = Preferences::get_instance();
110                bool restoreLastSong = pref->isRestoreLastSongEnabled();
111                QString filename = pref->getLastSongFilename();
112                if ( restoreLastSong && ( !filename.isEmpty() )) {
113                        song = Song::load( filename );
114                        if (song == NULL) {
115                                //QMessageBox::warning( this, "Hydrogen", trUtf8("Error restoring last song.") );
116                                song = Song::get_empty_song();
117                                song->set_filename( "" );
118                        }
119                }
120                else {
121                        song = Song::get_empty_song();
122                        song->set_filename( "" );
123                }
124        }
125
126        h2app = new HydrogenApp( this, song );
127        h2app->addEventListener( this );
128
129        createMenuBar();
130
131        h2app->setStatusBarMessage( trUtf8("Hydrogen Ready."), 10000 );
132
133        initKeyInstMap();
134
135        // we need to do all this to support the keyboard playing
136        // for all the window modes
137        h2app->getMixer()->installEventFilter (this);
138        h2app->getPatternEditorPanel()->installEventFilter (this);
139        h2app->getPatternEditorPanel()->getPianoRollEditor()->installEventFilter (this);
140        h2app->getSongEditorPanel()->installEventFilter (this);
141        h2app->getPlayerControl()->installEventFilter(this);
142        InstrumentEditorPanel::get_instance()->installEventFilter(this);
143        h2app->getAudioEngineInfoForm()->installEventFilter(this);
144        h2app->getMetroBlinker()->installEventFilter(this);
145//      h2app->getPlayListDialog()->installEventFilter(this);
146        installEventFilter( this );
147
148        showDevelWarning();
149
150        connect( &m_autosaveTimer, SIGNAL(timeout()), this, SLOT(onAutoSaveTimer()));
151        m_autosaveTimer.start( 60 * 1000 );
152
153
154#ifdef LASH_SUPPORT
155
156        if ( Preferences::get_instance()->useLash() ){
157                LashClient* lashClient = LashClient::get_instance();
158                if (lashClient->isConnected())
159                {
160                        // send alsa client id now since it can only be sent
161                        // after the audio engine has been started.
162                        Preferences *pref = Preferences::get_instance();
163                        if ( pref->m_sMidiDriver == "ALSA" ) {
164        //                      infoLog("[LASH] Sending alsa seq id to LASH server");
165                                lashClient->sendAlsaClientId();
166                        }
167                        // start timer for polling lash events
168                        lashPollTimer = new QTimer(this);
169                        connect( lashPollTimer, SIGNAL( timeout() ), this, SLOT( onLashPollTimer() ) );
170                        lashPollTimer->start(500);
171                }
172        }
173#endif
174
175       
176//playlist display timer
177        QTimer *playlistDisplayTimer = new QTimer(this);
178        connect( playlistDisplayTimer, SIGNAL( timeout() ), this, SLOT( onPlaylistDisplayTimer() ) );
179        playlistDisplayTimer->start(30000);     // update player control at
180// ~ playlist display timer
181       
182//beatcouter
183        Hydrogen::get_instance()->setBcOffsetAdjust();
184// director
185        EventQueue::get_instance()->push_event( EVENT_METRONOME, 1 );
186
187        undoView = new QUndoView(h2app->m_undoStack);
188        undoView->setWindowTitle(tr("Command history"));
189        undoView->setWindowIcon( QPixmap( Skin::getImagePath() + "/icon16.png" ) );
190}
191
192
193MainForm::~MainForm()
194{
195        // remove the autosave file
196        QFile file( getAutoSaveFilename() );
197        file.remove();
198
199        if ( (Hydrogen::get_instance()->getState() == STATE_PLAYING) ) {
200                Hydrogen::get_instance()->sequencer_stop();
201        }
202
203        // remove the autosave file
204        m_autosaveTimer.stop();
205        QFile autosaveFile( "hydrogen_autosave.h2song" );
206        autosaveFile.remove();
207
208
209        hide();
210
211        if (h2app != NULL) {
212                delete Playlist::get_instance();
213                delete h2app;
214                h2app = NULL;
215        }
216
217}
218
219///
220/// Create the menubar
221///
222void MainForm::createMenuBar()
223{
224        // menubar
225        QMenuBar *m_pMenubar = new QMenuBar( this );
226        setMenuBar( m_pMenubar );
227
228        // FILE menu
229        QMenu *m_pFileMenu = m_pMenubar->addMenu( trUtf8( "&Project" ) );
230
231        m_pFileMenu->addAction( trUtf8( "&New" ), this, SLOT( action_file_new() ), QKeySequence( "Ctrl+N" ) );
232        m_pFileMenu->addAction( trUtf8( "Show &info" ), this, SLOT( action_file_songProperties() ), QKeySequence( "" ) );
233
234        m_pFileMenu->addSeparator();                            // -----
235
236        m_pFileMenu->addAction( trUtf8( "&Open" ), this, SLOT( action_file_open() ), QKeySequence( "Ctrl+O" ) );
237        m_pFileMenu->addAction( trUtf8( "Open &Demo" ), this, SLOT( action_file_openDemo() ), QKeySequence( "Ctrl+D" ) );
238
239        m_pRecentFilesMenu = m_pFileMenu->addMenu( trUtf8( "Open &recent" ) );
240
241        m_pFileMenu->addSeparator();                            // -----
242
243        m_pFileMenu->addAction( trUtf8( "&Save" ), this, SLOT( action_file_save() ), QKeySequence( "Ctrl+S" ) );
244        m_pFileMenu->addAction( trUtf8( "Save &as..." ), this, SLOT( action_file_save_as() ), QKeySequence( "Ctrl+Shift+S" ) );
245
246        m_pFileMenu->addSeparator();                            // -----
247
248        m_pFileMenu->addAction ( trUtf8 ( "Open &Pattern" ), this, SLOT ( action_file_openPattern() ), QKeySequence ( "" ) );
249        m_pFileMenu->addAction( trUtf8( "Expor&t pattern as..." ), this, SLOT( action_file_export_pattern_as() ), QKeySequence( "Ctrl+P" ) );
250
251        m_pFileMenu->addSeparator();                            // -----
252
253        m_pFileMenu->addAction( trUtf8( "Export &MIDI file" ), this, SLOT( action_file_export_midi() ), QKeySequence( "Ctrl+M" ) );
254        m_pFileMenu->addAction( trUtf8( "&Export song" ), this, SLOT( action_file_export() ), QKeySequence( "Ctrl+E" ) );
255
256
257#ifndef Q_OS_MACX
258        m_pFileMenu->addSeparator();                            // -----
259
260        m_pFileMenu->addAction( trUtf8("&Quit"), this, SLOT( action_file_exit() ), QKeySequence( "Ctrl+Q" ) );
261#endif
262
263        updateRecentUsedSongList();
264        connect( m_pRecentFilesMenu, SIGNAL( triggered(QAction*) ), this, SLOT( action_file_open_recent(QAction*) ) );
265        //~ FILE menu
266
267        // Undo menu
268        QMenu *m_pUndoMenu = m_pMenubar->addMenu( trUtf8( "U&ndo" ) );
269        m_pUndoMenu->addAction( trUtf8( "Undo" ), this, SLOT( action_undo() ), QKeySequence( "Ctrl+Z" ) );
270        m_pUndoMenu->addAction( trUtf8( "Redo" ), this, SLOT( action_redo() ), QKeySequence( "Shift+Ctrl+Z" ) );
271        m_pUndoMenu->addAction( trUtf8( "Open Undo Stack " ), this, SLOT( openUndoStack() ), QKeySequence( "" ) );
272
273        // INSTRUMENTS MENU
274        QMenu *m_pInstrumentsMenu = m_pMenubar->addMenu( trUtf8( "I&nstruments" ) );
275        m_pInstrumentsMenu->addAction( trUtf8( "&Add instrument" ), this, SLOT( action_instruments_addInstrument() ), QKeySequence( "" ) );
276        m_pInstrumentsMenu->addAction( trUtf8( "&Clear all" ), this, SLOT( action_instruments_clearAll() ), QKeySequence( "" ) );
277        m_pInstrumentsMenu->addAction( trUtf8( "&Save library" ), this, SLOT( action_instruments_saveLibrary() ), QKeySequence( "" ) );
278        m_pInstrumentsMenu->addAction( trUtf8( "&Export library" ), this, SLOT( action_instruments_exportLibrary() ), QKeySequence( "" ) );
279        m_pInstrumentsMenu->addAction( trUtf8( "&Import library" ), this, SLOT( action_instruments_importLibrary() ), QKeySequence( "" ) );
280
281
282
283
284        // Tools menu
285        QMenu *m_pToolsMenu = m_pMenubar->addMenu( trUtf8( "&Tools" ));
286
287//      if ( Preferences::get_instance()->getInterfaceMode() == Preferences::SINGLE_PANED ) {
288//              m_pWindowMenu->addAction( trUtf8("Show song editor"), this, SLOT( action_window_showSongEditor() ), QKeySequence( "" ) );
289//      }
290        m_pToolsMenu->addAction( trUtf8("Playlist &editor"), this, SLOT( action_window_showPlaylistDialog() ), QKeySequence( "" ) );
291        m_pToolsMenu->addAction( trUtf8("Director"), this, SLOT( action_window_show_MetronWidget() ), QKeySequence( "Alt+B" ) );
292
293        m_pToolsMenu->addAction( trUtf8("&Mixer"), this, SLOT( action_window_showMixer() ), QKeySequence( "Alt+M" ) );
294
295        m_pToolsMenu->addAction( trUtf8("&Instrument Rack"), this, SLOT( action_window_showDrumkitManagerPanel() ), QKeySequence( "Alt+I" ) );
296        m_pToolsMenu->addAction( trUtf8("&Preferences"), this, SLOT( showPreferencesDialog() ), QKeySequence( "Alt+P" ) );
297
298        //~ Tools menu
299
300        Logger *l = Logger::get_instance();
301        if ( l->get_log_level() == 15 ) {
302                // DEBUG menu
303                QMenu *m_pDebugMenu = m_pMenubar->addMenu( trUtf8("De&bug") );
304                m_pDebugMenu->addAction( trUtf8( "Show &audio engine info" ), this, SLOT( action_debug_showAudioEngineInfo() ) );
305                m_pDebugMenu->addAction( trUtf8( "Print Objects" ), this, SLOT( action_debug_printObjects() ) );
306                //~ DEBUG menu
307        }
308
309        // INFO menu
310        QMenu *m_pInfoMenu = m_pMenubar->addMenu( trUtf8( "&Info" ) );
311        m_pInfoMenu->addAction( trUtf8("&User manual"), this, SLOT( showUserManual() ), QKeySequence( "Ctrl+?" ) );
312        m_pInfoMenu->addSeparator();
313        m_pInfoMenu->addAction( trUtf8("&About"), this, SLOT( action_help_about() ), QKeySequence( trUtf8("", "Info|About") ) );
314        //~ INFO menu
315}
316
317
318
319
320void MainForm::onLashPollTimer()
321{
322#ifdef LASH_SUPPORT     
323if ( Preferences::get_instance()->useLash() ){
324        LashClient* client = LashClient::get_instance();
325       
326        if (!client->isConnected())
327        {
328                WARNINGLOG("[LASH] Not connected to server!");
329                return;
330        }
331       
332        bool keep_running = true;
333
334        lash_event_t* event;
335
336        string songFilename;
337        QString filenameSong;
338        Song *song = Hydrogen::get_instance()->getSong();
339        // Extra parentheses for -Wparentheses
340        while ( (event = client->getNextEvent()) ) {
341               
342                switch (lash_event_get_type(event)) {
343                       
344                        case LASH_Save_File:
345               
346                                INFOLOG("[LASH] Save file");
347                       
348                                songFilename.append(lash_event_get_string(event));
349                                songFilename.append("/hydrogen.h2song");
350                               
351                                filenameSong = QString::fromLocal8Bit( songFilename.c_str() );
352                                song->set_filename( filenameSong );
353                                action_file_save();
354                         
355                                client->sendEvent(LASH_Save_File);
356                         
357                                break;
358               
359                        case LASH_Restore_File:
360               
361                                songFilename.append(lash_event_get_string(event));
362                                songFilename.append("/hydrogen.h2song");
363                               
364                                INFOLOG( QString("[LASH] Restore file: %1")
365                                         .arg( songFilename.c_str() ) );
366
367                                filenameSong = QString::fromLocal8Bit( songFilename.c_str() );
368                                                         
369                                openSongFile( filenameSong );
370                         
371                                client->sendEvent(LASH_Restore_File);
372                         
373                                break;
374
375                        case LASH_Quit:
376               
377//                              infoLog("[LASH] Quit!");
378                                keep_running = false;
379                               
380                                break;
381               
382                        default:
383                                ;
384//                              infoLog("[LASH] Got unknown event!");
385
386                }
387
388                lash_event_destroy(event);
389
390        }
391
392   if (!keep_running)
393   {
394           lashPollTimer->stop();
395           action_file_exit();
396   }
397}
398#endif
399}
400
401
402/// return true if the app needs to be closed.
403bool MainForm::action_file_exit()
404{
405        bool proceed = handleUnsavedChanges();
406        if(!proceed) {
407                return false;
408        }
409        closeAll();
410        return true;
411}
412
413
414
415void MainForm::action_file_new()
416{
417        if ( (Hydrogen::get_instance()->getState() == STATE_PLAYING) ) {
418                Hydrogen::get_instance()->sequencer_stop();
419        }
420
421        bool proceed = handleUnsavedChanges();
422        if(!proceed) {
423                return;
424        }
425
426        h2app->m_undoStack->clear();
427        Hydrogen::get_instance()->m_timelinevector.clear();
428        Song * song = Song::get_empty_song();
429        song->set_filename( "" );
430        h2app->setSong(song);
431        Hydrogen::get_instance()->setSelectedPatternNumber( 0 );
432        HydrogenApp::get_instance()->getInstrumentRack()->getSoundLibraryPanel()->update_background_color();
433        HydrogenApp::get_instance()->getSongEditorPanel()->updatePositionRuler();
434        Hydrogen::get_instance()->m_timelinetagvector.clear();
435        EventQueue::get_instance()->push_event( EVENT_METRONOME, 2 );
436}
437
438
439
440void MainForm::action_file_save_as()
441{
442        if ( (Hydrogen::get_instance()->getState() == STATE_PLAYING) ) {
443                Hydrogen::get_instance()->sequencer_stop();
444        }
445
446        std::auto_ptr<QFileDialog> fd( new QFileDialog );
447        fd->setFileMode( QFileDialog::AnyFile );
448        fd->setFilter( trUtf8("Hydrogen Song (*.h2song)") );
449        fd->setAcceptMode( QFileDialog::AcceptSave );
450        fd->setWindowTitle( trUtf8( "Save song" ) );
451
452        Song *song = Hydrogen::get_instance()->getSong();
453        QString defaultFilename;
454        QString lastFilename = song->get_filename();
455
456        if ( lastFilename.isEmpty() ) {
457                defaultFilename = Hydrogen::get_instance()->getSong()->__name;
458                defaultFilename += ".h2song";
459        }
460        else {
461                defaultFilename = lastFilename;
462        }
463
464        fd->selectFile( defaultFilename );
465
466        QString filename;
467        if (fd->exec() == QDialog::Accepted) {
468                filename = fd->selectedFiles().first();
469        }
470
471        if ( !filename.isEmpty() ) {
472                QString sNewFilename = filename;
473                if ( sNewFilename.endsWith(".h2song") == false ) {
474                        filename += ".h2song";
475                }
476
477                song->set_filename(filename);
478                action_file_save();
479        }
480        h2app->setScrollStatusBarMessage( trUtf8("Song saved as.") + QString(" Into: ") + defaultFilename, 2000 );
481        h2app->setWindowTitle( filename );
482}
483
484
485
486void MainForm::action_file_save()
487{
488//      if ( ((Hydrogen::get_instance())->getState() == STATE_PLAYING) ) {
489//              (Hydrogen::get_instance())->stop();
490//      }
491
492        Song *song = Hydrogen::get_instance()->getSong();
493        QString filename = song->get_filename();
494
495        if ( filename.isEmpty() ) {
496                // just in case!
497                return action_file_save_as();
498        }
499
500        LocalFileMng mng;
501        bool saved = false;
502        saved = song->save( filename );
503       
504
505        if(! saved) {
506                QMessageBox::warning( this, "Hydrogen", trUtf8("Could not save song.") );
507        } else {
508                Preferences::get_instance()->setLastSongFilename( song->get_filename() );
509
510                // add the new loaded song in the "last used song" vector
511                Preferences *pPref = Preferences::get_instance();
512                vector<QString> recentFiles = pPref->getRecentFiles();
513                recentFiles.insert( recentFiles.begin(), filename );
514                pPref->setRecentFiles( recentFiles );
515
516                updateRecentUsedSongList();
517
518                h2app->setScrollStatusBarMessage( trUtf8("Song saved.") + QString(" Into: ") + filename, 2000 );
519        }
520}
521
522
523
524
525void MainForm::action_help_about() {
526        //QWidget *parent = this;
527//      if (workspace) {
528//              parent = workspace;
529//      }
530
531        // show modal dialog
532        AboutDialog *dialog = new AboutDialog( NULL );
533        dialog->exec();
534}
535
536
537
538
539void MainForm::showUserManual()
540{
541        h2app->getHelpBrowser()->hide();
542        h2app->getHelpBrowser()->show();
543}
544
545
546void MainForm::action_file_export_pattern_as()
547{
548        if ( ( Hydrogen::get_instance()->getState() == STATE_PLAYING ) )
549        {
550                Hydrogen::get_instance()->sequencer_stop();
551        }
552
553        Hydrogen *engine = Hydrogen::get_instance();
554        int selectedpattern = engine->getSelectedPatternNumber();
555        Song *song = engine->getSong();
556        Pattern *pat = song->get_pattern_list()->get ( selectedpattern );
557
558        Instrument *instr = song->get_instrument_list()->get ( 0 );
559        assert ( instr );
560
561        QDir dir  = Preferences::get_instance()->__lastspatternDirectory;
562
563
564        std::auto_ptr<QFileDialog> fd( new QFileDialog );
565        fd->setFileMode ( QFileDialog::AnyFile );
566        fd->setFilter ( trUtf8 ( "Hydrogen Pattern (*.h2pattern)" ) );
567        fd->setAcceptMode ( QFileDialog::AcceptSave );
568        fd->setWindowTitle ( trUtf8 ( "Save Pattern as ..." ) );
569        fd->setDirectory ( dir );
570
571
572
573        QString defaultPatternname = QString ( pat->get_name() );
574
575        fd->selectFile ( defaultPatternname );
576
577        LocalFileMng fileMng;
578        QString filename;
579        if ( fd->exec() == QDialog::Accepted )
580        {
581                filename = fd->selectedFiles().first();
582                QString tmpfilename = filename;
583                QString toremove = tmpfilename.section( '/', -1 );
584                QString newdatapath =  tmpfilename.replace( toremove, "" );
585                Preferences::get_instance()->__lastspatternDirectory = newdatapath;
586        }
587
588        if ( !filename.isEmpty() )
589        {
590                QString sNewFilename = filename;
591                if(sNewFilename.endsWith( ".h2pattern" ) ){
592                        sNewFilename += "";
593                }
594                else{
595                        sNewFilename += ".h2pattern";
596                }
597                QString patternname = sNewFilename;
598                QString realpatternname = filename;
599                QString realname = realpatternname.mid( realpatternname.lastIndexOf( "/" ) + 1 );
600                if ( realname.endsWith( ".h2pattern" ) )
601                        realname.replace( ".h2pattern", "" );
602                pat->set_name(realname);
603                HydrogenApp::get_instance()->getSongEditorPanel()->updateAll();
604                int err = fileMng.savePattern ( song , selectedpattern, patternname, realname, 2 );
605                if ( err != 0 )
606                {
607                        QMessageBox::warning( this, "Hydrogen", trUtf8("Could not export pattern.") );
608                        _ERRORLOG ( "Error saving the pattern" );
609                        QMessageBox::warning( this, "Hydrogen", trUtf8("Could not export pattern.") );
610                }
611        }
612        h2app->setStatusBarMessage ( trUtf8 ( "Pattern saved." ), 10000 );
613       
614        //update SoundlibraryPanel
615        HydrogenApp::get_instance()->getInstrumentRack()->getSoundLibraryPanel()->test_expandedItems();
616        HydrogenApp::get_instance()->getInstrumentRack()->getSoundLibraryPanel()->updateDrumkitList();
617}
618
619
620
621void MainForm::action_file_open() {
622        if ( ((Hydrogen::get_instance())->getState() == STATE_PLAYING) ) {
623                Hydrogen::get_instance()->sequencer_stop();
624        }
625
626        bool proceed = handleUnsavedChanges();
627        if(!proceed) {
628                return;
629        }
630
631        static QString lastUsedDir = Preferences::get_instance()->getDataDirectory() + "/songs";
632       
633        std::auto_ptr<QFileDialog> fd( new QFileDialog );
634        fd->setFileMode(QFileDialog::ExistingFile);
635        fd->setFilter( trUtf8("Hydrogen Song (*.h2song)") );
636        fd->setDirectory( lastUsedDir );
637
638        fd->setWindowTitle( trUtf8( "Open song" ) );
639
640        /// \todo impostare il preview
641        /*
642        fd->setContentsPreviewEnabled( TRUE );
643        fd->setContentsPreview( "uno", "due" );
644        fd->setPreviewMode( QFileDialog::Contents );
645        */
646
647        QString filename;
648        if (fd->exec() == QDialog::Accepted) {
649                filename = fd->selectedFiles().first();
650                lastUsedDir = fd->directory().absolutePath();
651        }
652
653
654        if ( !filename.isEmpty() ) {
655                openSongFile( filename );
656        }
657
658        HydrogenApp::get_instance()->getInstrumentRack()->getSoundLibraryPanel()->update_background_color();
659}
660
661
662void MainForm::action_file_openPattern()
663{
664
665        Hydrogen *engine = Hydrogen::get_instance();
666        Song *song = engine->getSong();
667        PatternList *pPatternList = song->get_pattern_list();
668
669        Instrument *instr = song->get_instrument_list()->get ( 0 );
670        assert ( instr );
671
672        QDir dirPattern( Preferences::get_instance()->getDataDirectory() + "/patterns" );
673        std::auto_ptr<QFileDialog> fd( new QFileDialog );
674        fd->setFileMode ( QFileDialog::ExistingFile );
675        fd->setFilter ( trUtf8 ( "Hydrogen Pattern (*.h2pattern)" ) );
676        fd->setDirectory ( dirPattern );
677
678        fd->setWindowTitle ( trUtf8 ( "Open Pattern" ) );
679
680
681        QString filename;
682        if ( fd->exec() == QDialog::Accepted )
683        {
684                filename = fd->selectedFiles().first();
685        }
686        QString patternname = filename;
687
688
689        LocalFileMng mng;
690        LocalFileMng fileMng;
691        Pattern* err = fileMng.loadPattern ( patternname );
692        if ( err == 0 )
693        {
694                _ERRORLOG( "Error loading the pattern" );
695                _ERRORLOG( patternname );
696        }
697        else
698        {
699                H2Core::Pattern *pNewPattern = err;
700                pPatternList->add ( pNewPattern );
701                song->__is_modified = true;
702        }
703
704        HydrogenApp::get_instance()->getSongEditorPanel()->updateAll();
705}
706
707/// \todo parametrizzare il metodo action_file_open ed eliminare il seguente...
708void MainForm::action_file_openDemo()
709{
710        if ( (Hydrogen::get_instance()->getState() == STATE_PLAYING) ) {
711                Hydrogen::get_instance()->sequencer_stop();
712        }
713
714        bool proceed = handleUnsavedChanges();
715        if(!proceed) {
716                return;
717        }
718       
719        h2app->m_undoStack->clear();
720        std::auto_ptr<QFileDialog> fd( new QFileDialog );
721        fd->setFileMode(QFileDialog::ExistingFile);
722        fd->setFilter( trUtf8("Hydrogen Song (*.h2song)") );
723
724        fd->setWindowTitle( trUtf8( "Open song" ) );
725//      fd->setIcon( QPixmap( Skin::getImagePath() + "/icon16.png" ) );
726
727        /// \todo impostare il preview
728        /*
729        fd->setContentsPreviewEnabled( TRUE );
730        fd->setContentsPreview( "uno", "due" );
731        fd->setPreviewMode( QFileDialog::Contents );
732        */
733        fd->setDirectory( QString( Preferences::get_instance()->getDemoPath() ) );
734
735
736        QString filename;
737        if (fd->exec() == QDialog::Accepted) {
738                filename = fd->selectedFiles().first();
739        }
740
741
742        if ( !filename.isEmpty() ) {
743                openSongFile( filename );
744                Hydrogen::get_instance()->getSong()->set_filename( "" );
745        }
746}
747
748
749
750void MainForm::showPreferencesDialog()
751{
752        if ( (Hydrogen::get_instance()->getState() == STATE_PLAYING) ) {
753                Hydrogen::get_instance()->sequencer_stop();
754        }
755
756        h2app->showPreferencesDialog();
757}
758
759
760
761void MainForm::action_window_showPlaylistDialog()
762{
763        h2app->showPlaylistDialog();   
764}
765
766void MainForm::action_window_show_MetronWidget()
767{
768
769        h2app->showMetroBlinker();
770}
771
772void MainForm::action_window_showMixer()
773{
774        bool isVisible = HydrogenApp::get_instance()->getMixer()->isVisible();
775        h2app->showMixer( !isVisible );
776}
777
778
779
780void MainForm::action_debug_showAudioEngineInfo()
781{
782        h2app->showAudioEngineInfoForm();
783}
784
785
786
787///
788/// Shows the song editor
789///
790void MainForm::action_window_showSongEditor()
791{
792        bool isVisible = h2app->getSongEditorPanel()->isVisible();
793        h2app->getSongEditorPanel()->setHidden( isVisible );
794}
795
796
797
798void MainForm::action_instruments_addInstrument()
799{
800        SE_mainMenuAddInstrumentAction *action = new SE_mainMenuAddInstrumentAction();
801        HydrogenApp::get_instance()->m_undoStack->push( action );
802}
803
804
805
806void MainForm::action_instruments_clearAll()
807{
808        switch(
809               QMessageBox::information( this,
810                                         "Hydrogen",
811                                         trUtf8("Clear all instruments?"),
812                                         trUtf8("Ok"),
813                                         trUtf8("Cancel"),
814                                         0,      // Enter == button 0
815                                         1 )) { // Escape == button 2
816        case 0:
817          // ok btn pressed
818          break;
819        case 1:
820          // cancel btn pressed
821          return;
822        }
823
824        // Remove all layers
825        AudioEngine::get_instance()->lock( RIGHT_HERE );
826        Song *pSong = Hydrogen::get_instance()->getSong();
827        InstrumentList* pList = pSong->get_instrument_list();
828        for (uint i = 0; i < pList->get_size(); i++) {
829                Instrument* pInstr = pList->get( i );
830                pInstr->set_name( (QString( trUtf8( "Instrument %1" ) ).arg( i + 1 )) );
831                // remove all layers
832                for ( int nLayer = 0; nLayer < MAX_LAYERS; nLayer++ ) {
833                        InstrumentLayer* pLayer = pInstr->get_layer( nLayer );
834                        delete pLayer;
835                        pInstr->set_layer( NULL, nLayer );
836                }
837        }
838        AudioEngine::get_instance()->unlock();
839        EventQueue::get_instance()->push_event( EVENT_SELECTED_INSTRUMENT_CHANGED, -1 );
840}
841
842
843
844void MainForm::action_instruments_exportLibrary()
845{
846        SoundLibraryExportDialog exportDialog( this );
847        exportDialog.exec();
848}
849
850
851
852
853void MainForm::action_instruments_importLibrary()
854{
855        SoundLibraryImportDialog dialog( this );
856        dialog.exec();
857}
858
859
860
861void MainForm::action_instruments_saveLibrary()
862{
863        SoundLibrarySaveDialog dialog( this );
864        dialog.exec();
865        HydrogenApp::get_instance()->getInstrumentRack()->getSoundLibraryPanel()->test_expandedItems();
866        HydrogenApp::get_instance()->getInstrumentRack()->getSoundLibraryPanel()->updateDrumkitList();
867}
868
869
870
871
872
873
874
875///
876/// Window close event
877///
878void MainForm::closeEvent( QCloseEvent* ev )
879{
880        if ( action_file_exit() == false ) {
881                // don't close!!!
882                ev->ignore();
883                return;
884        }
885
886        ev->accept();
887}
888
889
890
891void MainForm::action_file_export() {
892        if ( (Hydrogen::get_instance()->getState() == STATE_PLAYING) ) {
893                Hydrogen::get_instance()->sequencer_stop();
894        }
895
896        ExportSongDialog *dialog = new ExportSongDialog(this);
897        dialog->exec();
898        delete dialog;
899}
900
901
902
903void MainForm::action_window_showDrumkitManagerPanel()
904{
905        InstrumentRack *pPanel = HydrogenApp::get_instance()->getInstrumentRack();
906        pPanel->setHidden( pPanel->isVisible() );
907}
908
909
910
911
912void MainForm::closeAll() {
913        // save window properties in the preferences files
914        Preferences *pref = Preferences::get_instance();
915
916        // mainform
917        WindowProperties mainFormProp;
918        mainFormProp.x = x();
919        mainFormProp.y = y();
920        mainFormProp.height = height();
921        mainFormProp.width = width();
922        pref->setMainFormProperties( mainFormProp );
923
924        // Save mixer properties
925        WindowProperties mixerProp;
926        mixerProp.x = h2app->getMixer()->x();
927        mixerProp.y = h2app->getMixer()->y();
928        mixerProp.width = h2app->getMixer()->width();
929        mixerProp.height = h2app->getMixer()->height();
930        mixerProp.visible = h2app->getMixer()->isVisible();
931        pref->setMixerProperties( mixerProp );
932
933        // save pattern editor properties
934        WindowProperties patternEditorProp;
935        patternEditorProp.x = h2app->getPatternEditorPanel()->x();
936        patternEditorProp.y = h2app->getPatternEditorPanel()->y();
937        patternEditorProp.width = h2app->getPatternEditorPanel()->width();
938        patternEditorProp.height = h2app->getPatternEditorPanel()->height();
939        patternEditorProp.visible = h2app->getPatternEditorPanel()->isVisible();
940        pref->setPatternEditorProperties( patternEditorProp );
941
942        // save song editor properties
943        WindowProperties songEditorProp;
944        songEditorProp.x = h2app->getSongEditorPanel()->x();
945        songEditorProp.y = h2app->getSongEditorPanel()->y();
946        songEditorProp.width = h2app->getSongEditorPanel()->width();
947        songEditorProp.height = h2app->getSongEditorPanel()->height();
948
949        QSize size = h2app->getSongEditorPanel()->frameSize();
950        songEditorProp.visible = h2app->getSongEditorPanel()->isVisible();
951        pref->setSongEditorProperties( songEditorProp );
952
953
954        // save audio engine info properties
955        WindowProperties audioEngineInfoProp;
956        audioEngineInfoProp.x = h2app->getAudioEngineInfoForm()->x();
957        audioEngineInfoProp.y = h2app->getAudioEngineInfoForm()->y();
958        audioEngineInfoProp.visible = h2app->getAudioEngineInfoForm()->isVisible();
959        pref->setAudioEngineInfoProperties( audioEngineInfoProp );
960
961
962#ifdef LADSPA_SUPPORT
963        // save LADSPA FX window properties
964        for (uint nFX = 0; nFX < MAX_FX; nFX++) {
965                WindowProperties prop;
966                prop.x = h2app->getLadspaFXProperties(nFX)->x();
967                prop.y = h2app->getLadspaFXProperties(nFX)->y();
968                prop.visible= h2app->getLadspaFXProperties(nFX)->isVisible();
969                pref->setLadspaProperties(nFX, prop);
970        }
971#endif
972
973        m_pQApp->quit();
974}
975
976
977
978// keybindings..
979
980void MainForm::onPlayStopAccelEvent()
981{
982        int nState = Hydrogen::get_instance()->getState();
983        switch (nState) {
984                case STATE_READY:
985                        Hydrogen::get_instance()->sequencer_play();
986                        break;
987
988                case STATE_PLAYING:
989                        Hydrogen::get_instance()->sequencer_stop();
990                        break;
991
992                default:
993                        ERRORLOG( "[MainForm::onPlayStopAccelEvent()] Unhandled case." );
994        }
995}
996
997
998
999void MainForm::onRestartAccelEvent()
1000{
1001        Hydrogen* pEngine = Hydrogen::get_instance();
1002        pEngine->setPatternPos( 0 );
1003}
1004
1005
1006
1007void MainForm::onBPMPlusAccelEvent()
1008{
1009        Hydrogen* pEngine = Hydrogen::get_instance();
1010        AudioEngine::get_instance()->lock( RIGHT_HERE );
1011
1012        Song* pSong = pEngine->getSong();
1013        if (pSong->__bpm  < 300) {
1014                pEngine->setBPM( pSong->__bpm + 0.1 );
1015        }
1016        AudioEngine::get_instance()->unlock();
1017}
1018
1019
1020
1021void MainForm::onBPMMinusAccelEvent()
1022{
1023        Hydrogen* pEngine = Hydrogen::get_instance();
1024        AudioEngine::get_instance()->lock( RIGHT_HERE );
1025
1026        Song* pSong = pEngine->getSong();
1027        if (pSong->__bpm > 40 ) {
1028                pEngine->setBPM( pSong->__bpm - 0.1 );
1029        }
1030        AudioEngine::get_instance()->unlock();
1031}
1032
1033
1034
1035void MainForm::onSaveAsAccelEvent()
1036{
1037        action_file_save_as();
1038}
1039
1040
1041
1042void MainForm::onSaveAccelEvent()
1043{
1044        action_file_save();
1045}
1046
1047
1048
1049void MainForm::onOpenAccelEvent()
1050{
1051        action_file_open();
1052}
1053
1054
1055
1056void MainForm::updateRecentUsedSongList()
1057{
1058        m_pRecentFilesMenu->clear();
1059
1060        Preferences *pPref = Preferences::get_instance();
1061        vector<QString> recentUsedSongs = pPref->getRecentFiles();
1062
1063        QString sFilename;
1064
1065        for ( uint i = 0; i < recentUsedSongs.size(); ++i ) {
1066                sFilename = recentUsedSongs[ i ];
1067
1068                if ( !sFilename.isEmpty() ) {
1069                        QAction *pAction = new QAction( this  );
1070                        pAction->setText( sFilename );
1071                        m_pRecentFilesMenu->addAction( pAction );
1072                }
1073        }
1074}
1075
1076
1077
1078void MainForm::action_file_open_recent(QAction *pAction)
1079{
1080//      INFOLOG( pAction->text() );
1081        openSongFile( pAction->text() );
1082}
1083
1084
1085
1086void MainForm::openSongFile( const QString& sFilename )
1087{
1088        Hydrogen *engine = Hydrogen::get_instance();
1089        if ( engine->getState() == STATE_PLAYING ) {
1090                engine->sequencer_stop();
1091        }
1092
1093        engine->m_timelinetagvector.clear();
1094
1095        h2app->closeFXProperties();
1096        LocalFileMng mng;
1097        Song *pSong = Song::load( sFilename );
1098        if ( pSong == NULL ) {
1099                QMessageBox::information( this, "Hydrogen", trUtf8("Error loading song.") );
1100                return;
1101        }
1102        h2app->m_undoStack->clear();
1103
1104        // add the new loaded song in the "last used song" vector
1105        Preferences *pPref = Preferences::get_instance();
1106        vector<QString> recentFiles = pPref->getRecentFiles();
1107        recentFiles.insert( recentFiles.begin(), sFilename );
1108        pPref->setRecentFiles( recentFiles );
1109
1110        h2app->setSong( pSong );
1111
1112        updateRecentUsedSongList();
1113        engine->setSelectedPatternNumber( 0 );
1114        HydrogenApp::get_instance()->getSongEditorPanel()->updatePositionRuler();
1115        EventQueue::get_instance()->push_event( EVENT_METRONOME, 1 );
1116}
1117
1118
1119
1120void MainForm::initKeyInstMap()
1121{
1122
1123        QString loc = QLocale::system().name();
1124        int instr = 0;
1125
1126///POSIX Locale
1127//locale for keyboardlayout QWERTZ
1128// de_DE, de_AT, de_LU, de_CH, de
1129
1130//locale for keyboardlayout AZERTY
1131// fr_BE, fr_CA, fr_FR, fr_LU, fr_CH
1132
1133//locale for keyboardlayout QWERTY
1134// en_GB, en_US, en_ZA, usw.
1135
1136        if ( loc.contains( "de" ) || loc.contains( "DE" )){ ///QWERTZ
1137                keycodeInstrumentMap[Qt::Key_Y] = instr++;
1138                keycodeInstrumentMap[Qt::Key_S] = instr++;
1139                keycodeInstrumentMap[Qt::Key_X] = instr++;
1140                keycodeInstrumentMap[Qt::Key_D] = instr++;
1141                keycodeInstrumentMap[Qt::Key_C] = instr++;
1142                keycodeInstrumentMap[Qt::Key_V] = instr++;
1143                keycodeInstrumentMap[Qt::Key_G] = instr++;
1144                keycodeInstrumentMap[Qt::Key_B] = instr++;
1145                keycodeInstrumentMap[Qt::Key_H] = instr++;
1146                keycodeInstrumentMap[Qt::Key_N] = instr++;
1147                keycodeInstrumentMap[Qt::Key_J] = instr++;
1148                keycodeInstrumentMap[Qt::Key_M] = instr++;
1149       
1150                keycodeInstrumentMap[Qt::Key_Q] = instr++;
1151                keycodeInstrumentMap[Qt::Key_2] = instr++;
1152                keycodeInstrumentMap[Qt::Key_W] = instr++;
1153                keycodeInstrumentMap[Qt::Key_3] = instr++;
1154                keycodeInstrumentMap[Qt::Key_E] = instr++;
1155                keycodeInstrumentMap[Qt::Key_R] = instr++;
1156                keycodeInstrumentMap[Qt::Key_5] = instr++;
1157                keycodeInstrumentMap[Qt::Key_T] = instr++;
1158                keycodeInstrumentMap[Qt::Key_6] = instr++;
1159                keycodeInstrumentMap[Qt::Key_Z] = instr++;
1160                keycodeInstrumentMap[Qt::Key_7] = instr++;
1161                keycodeInstrumentMap[Qt::Key_U] = instr++;
1162        }
1163        else if ( loc.contains( "fr" ) || loc.contains( "FR" )){ ///AZERTY
1164                keycodeInstrumentMap[Qt::Key_W] = instr++;
1165                keycodeInstrumentMap[Qt::Key_S] = instr++;
1166                keycodeInstrumentMap[Qt::Key_X] = instr++;
1167                keycodeInstrumentMap[Qt::Key_D] = instr++;
1168                keycodeInstrumentMap[Qt::Key_C] = instr++;
1169                keycodeInstrumentMap[Qt::Key_V] = instr++;
1170                keycodeInstrumentMap[Qt::Key_G] = instr++;
1171                keycodeInstrumentMap[Qt::Key_B] = instr++;
1172                keycodeInstrumentMap[Qt::Key_H] = instr++;
1173                keycodeInstrumentMap[Qt::Key_N] = instr++;
1174                keycodeInstrumentMap[Qt::Key_J] = instr++;
1175                keycodeInstrumentMap[Qt::Key_Question] = instr++;
1176       
1177                keycodeInstrumentMap[Qt::Key_A] = instr++;
1178                keycodeInstrumentMap[Qt::Key_2] = instr++;
1179                keycodeInstrumentMap[Qt::Key_Z] = instr++;
1180                keycodeInstrumentMap[Qt::Key_3] = instr++;
1181                keycodeInstrumentMap[Qt::Key_E] = instr++;
1182                keycodeInstrumentMap[Qt::Key_R] = instr++;
1183                keycodeInstrumentMap[Qt::Key_5] = instr++;
1184                keycodeInstrumentMap[Qt::Key_T] = instr++;
1185                keycodeInstrumentMap[Qt::Key_6] = instr++;
1186                keycodeInstrumentMap[Qt::Key_Y] = instr++;
1187                keycodeInstrumentMap[Qt::Key_7] = instr++;
1188                keycodeInstrumentMap[Qt::Key_U] = instr++;
1189        }else
1190        { /// default QWERTY
1191                keycodeInstrumentMap[Qt::Key_Z] = instr++;
1192                keycodeInstrumentMap[Qt::Key_S] = instr++;
1193                keycodeInstrumentMap[Qt::Key_X] = instr++;
1194                keycodeInstrumentMap[Qt::Key_D] = instr++;
1195                keycodeInstrumentMap[Qt::Key_C] = instr++;
1196                keycodeInstrumentMap[Qt::Key_V] = instr++;
1197                keycodeInstrumentMap[Qt::Key_G] = instr++;
1198                keycodeInstrumentMap[Qt::Key_B] = instr++;
1199                keycodeInstrumentMap[Qt::Key_H] = instr++;
1200                keycodeInstrumentMap[Qt::Key_N] = instr++;
1201                keycodeInstrumentMap[Qt::Key_J] = instr++;
1202                keycodeInstrumentMap[Qt::Key_M] = instr++;
1203       
1204                keycodeInstrumentMap[Qt::Key_Q] = instr++;
1205                keycodeInstrumentMap[Qt::Key_2] = instr++;
1206                keycodeInstrumentMap[Qt::Key_W] = instr++;
1207                keycodeInstrumentMap[Qt::Key_3] = instr++;
1208                keycodeInstrumentMap[Qt::Key_E] = instr++;
1209                keycodeInstrumentMap[Qt::Key_R] = instr++;
1210                keycodeInstrumentMap[Qt::Key_5] = instr++;
1211                keycodeInstrumentMap[Qt::Key_T] = instr++;
1212                keycodeInstrumentMap[Qt::Key_6] = instr++;
1213                keycodeInstrumentMap[Qt::Key_Y] = instr++;
1214                keycodeInstrumentMap[Qt::Key_7] = instr++;
1215                keycodeInstrumentMap[Qt::Key_U] = instr++;
1216        }
1217
1218        /*
1219        // QWERTY etc.... rows of the keyboard
1220        keycodeInstrumentMap[Qt::Key_Q] = instr++;
1221        keycodeInstrumentMap[Qt::Key_W] = instr++;
1222        keycodeInstrumentMap[Qt::Key_E] = instr++;
1223        keycodeInstrumentMap[Qt::Key_R] = instr++;
1224        keycodeInstrumentMap[Qt::Key_T] = instr++;
1225        keycodeInstrumentMap[Qt::Key_Y] = instr++;
1226        keycodeInstrumentMap[Qt::Key_U] = instr++;
1227        keycodeInstrumentMap[Qt::Key_I] = instr++;
1228        keycodeInstrumentMap[Qt::Key_O] = instr++;
1229        keycodeInstrumentMap[Qt::Key_P] = instr++;
1230        keycodeInstrumentMap[Qt::Key_BracketLeft] = instr++;
1231        keycodeInstrumentMap[Qt::Key_BracketRight] = instr++;
1232        keycodeInstrumentMap[Qt::Key_A] = instr++;
1233        keycodeInstrumentMap[Qt::Key_S] = instr++;
1234        keycodeInstrumentMap[Qt::Key_D] = instr++;
1235        keycodeInstrumentMap[Qt::Key_F] = instr++;
1236        keycodeInstrumentMap[Qt::Key_G] = instr++;
1237        keycodeInstrumentMap[Qt::Key_H] = instr++;
1238        keycodeInstrumentMap[Qt::Key_J] = instr++;
1239        keycodeInstrumentMap[Qt::Key_K] = instr++;
1240        keycodeInstrumentMap[Qt::Key_L] = instr++;
1241        keycodeInstrumentMap[Qt::Key_Semicolon] = instr++;
1242        keycodeInstrumentMap[Qt::Key_Apostrophe] = instr++;
1243        keycodeInstrumentMap[Qt::Key_Z] = instr++;
1244        keycodeInstrumentMap[Qt::Key_X] = instr++;
1245        keycodeInstrumentMap[Qt::Key_C] = instr++;
1246        keycodeInstrumentMap[Qt::Key_V] = instr++;
1247        keycodeInstrumentMap[Qt::Key_B] = instr++;
1248        keycodeInstrumentMap[Qt::Key_N] = instr++;
1249        keycodeInstrumentMap[Qt::Key_M] = instr++;
1250        keycodeInstrumentMap[Qt::Key_Comma] = instr++;
1251        keycodeInstrumentMap[Qt::Key_Period] = instr++;
1252*/
1253}
1254
1255
1256
1257bool MainForm::eventFilter( QObject *o, QEvent *e )
1258{
1259        UNUSED( o );
1260
1261        if ( e->type() == QEvent::KeyPress) {
1262                // special processing for key press
1263                QKeyEvent *k = (QKeyEvent *)e;
1264
1265                // qDebug( "Got key press for instrument '%c'", k->ascii() );
1266                int songnumber = 0;
1267
1268                switch (k->key()) {
1269                        case Qt::Key_Space:
1270                                onPlayStopAccelEvent();
1271                                return TRUE; // eat event
1272
1273
1274                        case Qt::Key_Comma:
1275                                Hydrogen::get_instance()->handleBeatCounter();
1276                                return TRUE; // eat even
1277                                break;
1278
1279                        case Qt::Key_Backspace:
1280                                onRestartAccelEvent();
1281                                return TRUE; // eat event
1282                                break;
1283
1284                        case Qt::Key_Plus:
1285                                onBPMPlusAccelEvent();
1286                                return TRUE; // eat event
1287                                break;
1288
1289                        case Qt::Key_Minus:
1290                                onBPMMinusAccelEvent();
1291                                return TRUE; // eat event
1292                                break;
1293
1294                        case Qt::Key_Backslash:
1295                                Hydrogen::get_instance()->onTapTempoAccelEvent();
1296                                return TRUE; // eat event
1297                                break;
1298
1299                        case  Qt::Key_S | Qt::CTRL:
1300                                onSaveAccelEvent();
1301                                return TRUE;
1302                                break;
1303                       
1304                        case  Qt::Key_F5 :
1305                                if( Hydrogen::get_instance()->m_PlayList.size() == 0)
1306                                        break;
1307                                Playlist::get_instance()->setPrevSongPlaylist();
1308                                songnumber = Playlist::get_instance()->getActiveSongNumber();
1309                                HydrogenApp::get_instance()->setScrollStatusBarMessage( trUtf8( "Playlist: Set song No. %1" ).arg( songnumber +1 ), 5000 );
1310                                return TRUE;
1311                                break;
1312
1313                        case  Qt::Key_F6 :
1314                                if( Hydrogen::get_instance()->m_PlayList.size() == 0)
1315                                        break;
1316                                Playlist::get_instance()->setNextSongPlaylist();
1317                                songnumber = Playlist::get_instance()->getActiveSongNumber();
1318                                HydrogenApp::get_instance()->setScrollStatusBarMessage( trUtf8( "Playlist: Set song No. %1" ).arg( songnumber +1 ), 5000 );
1319                                return TRUE;
1320                                break;
1321
1322                        case  Qt::Key_F12 : //panic button stop all playing notes
1323                                Hydrogen::get_instance()->__panic();
1324//                              QMessageBox::information( this, "Hydrogen", trUtf8( "Panic" ) );
1325                                return TRUE;
1326                                break;
1327
1328                        case  Qt::Key_F9 : // Qt::Key_Left do not work. Some ideas ?
1329                                Hydrogen::get_instance()->setPatternPos( Hydrogen::get_instance()->getPatternPos() - 1 );
1330                                return TRUE;
1331                                break;
1332
1333                        case  Qt::Key_F10 : // Qt::Key_Right do not work. Some ideas ?
1334                                Hydrogen::get_instance()->setPatternPos( Hydrogen::get_instance()->getPatternPos() + 1 );
1335                                return TRUE;
1336                                break;
1337                       
1338                        case Qt::Key_L :
1339                                Hydrogen::get_instance()->togglePlaysSelected();
1340                                QString msg = Preferences::get_instance()->patternModePlaysSelected() ? "Single pattern mode" : "Stacked pattern mode";
1341                                HydrogenApp::get_instance()->setStatusBarMessage( msg, 5000 );
1342                                HydrogenApp::get_instance()->getSongEditorPanel()->setModeActionBtn( Preferences::get_instance()->patternModePlaysSelected() );
1343                                HydrogenApp::get_instance()->getSongEditorPanel()->updateAll();
1344                               
1345                                return TRUE;
1346                       
1347                //      QAccel *a = new QAccel( this );
1348//      a->connectItem( a->insertItem(Key_S + CTRL), this, SLOT( onSaveAccelEvent() ) );
1349//      a->connectItem( a->insertItem(Key_O + CTRL), this, SLOT( onOpenAccelEvent() ) );
1350
1351                }
1352
1353                // virtual keyboard handling
1354                map<int,int>::iterator found = keycodeInstrumentMap.find ( k->key() );
1355                if (found != keycodeInstrumentMap.end()) {
1356//                      INFOLOG( "[eventFilter] virtual keyboard event" );
1357                        // insert note at the current column in time
1358                        // if event recording enabled
1359                        int row = (*found).second;
1360                        Hydrogen* engine = Hydrogen::get_instance();
1361
1362                        float velocity = 0.8;
1363                        float pan_L = 1.0;
1364                        float pan_R = 1.0;
1365
1366                        engine->addRealtimeNote (row, velocity, pan_L, pan_R, NULL, NULL, NULL , row + 36);
1367
1368                        return TRUE; // eat event
1369                }
1370                else {
1371                        return FALSE; // let it go
1372                }
1373        }
1374        else {
1375                return FALSE; // standard event processing
1376        }
1377}
1378
1379
1380
1381
1382
1383/// print the object map
1384void MainForm::action_debug_printObjects()
1385{
1386        INFOLOG( "[action_debug_printObjects]" );
1387        Object::print_object_map();
1388}
1389
1390
1391
1392
1393
1394
1395void MainForm::action_file_export_midi()
1396{
1397        if ( ((Hydrogen::get_instance())->getState() == STATE_PLAYING) ) {
1398                Hydrogen::get_instance()->sequencer_stop();
1399        }
1400
1401        std::auto_ptr<QFileDialog> fd( new QFileDialog );
1402        fd->setFileMode(QFileDialog::AnyFile);
1403        fd->setFilter( trUtf8("Midi file (*.mid)") );
1404        fd->setDirectory( QDir::homePath() );
1405        fd->setWindowTitle( trUtf8( "Export MIDI file" ) );
1406        fd->setAcceptMode( QFileDialog::AcceptSave );
1407//      fd->setIcon( QPixmap( Skin::getImagePath() + "/icon16.png" ) );
1408
1409        QString sFilename;
1410        if ( fd->exec() == QDialog::Accepted ) {
1411                sFilename = fd->selectedFiles().first();
1412        }
1413
1414        if ( !sFilename.isEmpty() ) {
1415                if ( sFilename.endsWith(".mid") == false ) {
1416                        sFilename += ".mid";
1417                }
1418
1419                Song *pSong = Hydrogen::get_instance()->getSong();
1420
1421                // create the Standard Midi File object
1422                SMFWriter *pSmfWriter = new SMFWriter();
1423                pSmfWriter->save( sFilename, pSong );
1424
1425                delete pSmfWriter;
1426        }
1427}
1428
1429
1430
1431void MainForm::errorEvent( int nErrorCode )
1432{
1433        //ERRORLOG( "[errorEvent]" );
1434
1435        QString msg;
1436        switch (nErrorCode) {
1437                case Hydrogen::UNKNOWN_DRIVER:
1438                        msg = trUtf8( "Unknown audio driver" );
1439                        break;
1440
1441                case Hydrogen::ERROR_STARTING_DRIVER:
1442                        msg = trUtf8( "Error starting audio driver" );
1443                        break;
1444
1445                case Hydrogen::JACK_SERVER_SHUTDOWN:
1446                        msg = trUtf8( "Jack driver: server shutdown" );
1447                        break;
1448
1449                case Hydrogen::JACK_CANNOT_ACTIVATE_CLIENT:
1450                        msg = trUtf8( "Jack driver: cannot activate client" );
1451                        break;
1452
1453                case Hydrogen::JACK_CANNOT_CONNECT_OUTPUT_PORT:
1454                        msg = trUtf8( "Jack driver: cannot connect output port" );
1455                        break;
1456
1457                case Hydrogen::JACK_ERROR_IN_PORT_REGISTER:
1458                        msg = trUtf8( "Jack driver: error in port register" );
1459                        break;
1460
1461                default:
1462                        msg = QString( trUtf8( "Unknown error %1" ) ).arg( nErrorCode );
1463        }
1464        QMessageBox::information( this, "Hydrogen", msg );
1465}
1466
1467
1468void MainForm::action_file_songProperties()
1469{
1470        SongPropertiesDialog *pDialog = new SongPropertiesDialog( this );
1471        if ( pDialog->exec() == QDialog::Accepted ) {
1472                Hydrogen::get_instance()->getSong()->__is_modified = true;
1473        }
1474        delete pDialog;
1475}
1476
1477
1478void MainForm::action_window_showPatternEditor()
1479{
1480        bool isVisible = HydrogenApp::get_instance()->getPatternEditorPanel()->isVisible();
1481        HydrogenApp::get_instance()->getPatternEditorPanel()->setHidden( isVisible );
1482}
1483
1484
1485void MainForm::showDevelWarning()
1486{
1487
1488        //set this to 'false' for the case that you want to make a release..
1489        if ( true ) {
1490                Preferences *pref = Preferences::get_instance();
1491                bool isDevelWarningEnabled = pref->getShowDevelWarning();
1492                if(isDevelWarningEnabled) {
1493
1494                        QString msg = trUtf8( "You're using a development version of Hydrogen, please help us reporting bugs or suggestions in the hydrogen-devel mailing list.<br><br>Thank you!" );
1495                        QMessageBox develMessageBox( this );
1496                        develMessageBox.setText( msg );
1497                        develMessageBox.addButton( QMessageBox::Ok );
1498                        develMessageBox.addButton( trUtf8( "Don't show this message anymore" ) , QMessageBox::AcceptRole );
1499
1500                        if( develMessageBox.exec() == 0 ){
1501                                //don't show warning again
1502                                pref->setShowDevelWarning( false );
1503                        }
1504          }
1505
1506
1507        }
1508}
1509
1510
1511
1512QString MainForm::getAutoSaveFilename()
1513{
1514        Song *pSong = Hydrogen::get_instance()->getSong();
1515        assert( pSong );
1516        QString sOldFilename = pSong->get_filename();
1517        QString newName = "autosave.h2song";
1518
1519        if ( !sOldFilename.isEmpty() ) {
1520                newName = sOldFilename.left( sOldFilename.length() - 7 ) + ".autosave.h2song";
1521        }
1522
1523        return newName;
1524}
1525
1526
1527
1528void MainForm::onAutoSaveTimer()
1529{
1530        //INFOLOG( "[onAutoSaveTimer]" );
1531        Song *pSong = Hydrogen::get_instance()->getSong();
1532        assert( pSong );
1533        QString sOldFilename = pSong->get_filename();
1534
1535        pSong->save( getAutoSaveFilename() );
1536
1537        pSong->set_filename(sOldFilename);
1538
1539/*
1540        Song *pSong = h2app->getSong();
1541        if (pSong->getFilename() == "") {
1542                pSong->save( "autosave.h2song" );
1543                return;
1544        }
1545
1546        action_file_save();
1547*/
1548}
1549
1550
1551void MainForm::onPlaylistDisplayTimer()
1552{
1553        if( Hydrogen::get_instance()->m_PlayList.size() == 0)
1554                return;
1555        int songnumber = Playlist::get_instance()->getActiveSongNumber();
1556        QString songname;
1557        if ( songnumber == -1 )
1558                        return;
1559
1560        if ( Hydrogen::get_instance()->getSong()->__name == "Untitled Song" ){
1561                songname = Hydrogen::get_instance()->getSong()->get_filename();
1562        }else
1563        {
1564                songname = Hydrogen::get_instance()->getSong()->__name;
1565        }
1566        QString message = (trUtf8("Playlist: Song No. %1").arg( songnumber + 1)) + QString("  ---  Songname: ") + songname + QString("  ---  Author: ") + Hydrogen::get_instance()->getSong()->__author;
1567        HydrogenApp::get_instance()->setScrollStatusBarMessage( message, 2000 );
1568}
1569
1570// Returns true if unsaved changes are successfully handled (saved, discarded, etc.)
1571// Returns false if not (i.e. Cancel)
1572bool MainForm::handleUnsavedChanges()
1573{
1574        bool done = false;
1575        bool rv = true;
1576        while ( !done && Hydrogen::get_instance()->getSong()->__is_modified ) {
1577                switch(
1578                                QMessageBox::information( this, "Hydrogen",
1579                                                trUtf8("\nThe document contains unsaved changes.\n"
1580                                                "Do you want to save the changes?\n"),
1581                                                trUtf8("&Save"), trUtf8("&Discard"), trUtf8("&Cancel"),
1582                                                0,      // Enter == button 0
1583                                                2 ) ) { // Escape == button 2
1584                        case 0: // Save clicked or Alt+S pressed or Enter pressed.
1585                                // If the save fails, the __is_modified flag will still be true
1586                            if ( ! Hydrogen::get_instance()->getSong()->get_filename().isEmpty() ) {
1587                                        action_file_save();
1588                                } else {
1589                                        // never been saved
1590                                        action_file_save_as();
1591                                }
1592                                // save
1593                                break;
1594                        case 1: // Discard clicked or Alt+D pressed
1595                                // don't save but exit
1596                                done = true;
1597                                break;
1598                        case 2: // Cancel clicked or Alt+C pressed or Escape pressed
1599                                // don't exit
1600                                done = true;
1601                                rv = false;
1602                                break;
1603                }
1604        }
1605        return rv;
1606}
1607
1608
1609void MainForm::usr1SignalHandler(int)
1610 {
1611     char a = 1;
1612     ::write(sigusr1Fd[0], &a, sizeof(a));
1613 }
1614
1615void MainForm::handleSigUsr1()
1616{
1617    snUsr1->setEnabled(false);
1618    char tmp;
1619    ::read(sigusr1Fd[1], &tmp, sizeof(tmp));
1620
1621    action_file_save();
1622    snUsr1->setEnabled(true);
1623}
1624
1625void MainForm::openUndoStack()
1626{
1627        undoView->show();
1628        undoView->setAttribute(Qt::WA_QuitOnClose, false);
1629};
1630
1631void MainForm::action_undo(){
1632    h2app->m_undoStack->undo();
1633};
1634
1635void MainForm::action_redo(){
1636    h2app->m_undoStack->redo();
1637};
1638
1639
1640
Note: See TracBrowser for help on using the browser.