-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Coupling between core and GUI #1862
Comments
@M374LX, Any concrete sore spots you can point at? I see Models everywhere, and they should fit the description "data being stored out of the GUI" pretty well, right? |
@softrabbit Here's what a grep for "gui" in the core folder gives: [lmms-dev]$ cd lmms/src/core/
[core]$ grep -r "gui"
midi/MidiOss.cpp:#include "gui_templates.h"
midi/MidiAlsaSeq.cpp:#include "gui_templates.h"
midi/MidiWinMM.cpp:#include "gui_templates.h"
midi/MidiAlsaRaw.cpp:#include "gui_templates.h"
Engine.cpp: return gui != nullptr;
audio/AudioJack.cpp:#include "gui_templates.h"
audio/AudioJack.cpp: QMessageBox::information( gui->mainWindow(),
audio/AudioJack.cpp: QMessageBox::information( gui->mainWindow(),
audio/AudioAlsa.cpp:#include "gui_templates.h"
audio/AudioPulseAudio.cpp:#include "gui_templates.h"
audio/AudioPortAudio.cpp:#include "gui_templates.h"
audio/AudioSdl.cpp:#include "gui_templates.h"
audio/AudioOss.cpp:#include "gui_templates.h"
TrackContainer.cpp: gui->mainWindow() );
Track.cpp:#include "gui_templates.h"
Track.cpp: if( m_trackView->trackContainerView() == gui->getBBEditor()->trackContainerView() )
Track.cpp: if( m_trackView->trackContainerView() != gui->getBBEditor()->trackContainerView() )
Song.cpp: if( gui && gui->getBBEditor() )
Song.cpp: gui->getBBEditor()->trackContainerView()->clearAllTracks();
Song.cpp: if( gui && gui->songEditor() )
Song.cpp: gui->songEditor()->m_editor->clearAllTracks();
Song.cpp: if( gui && gui->fxMixerView() )
Song.cpp: gui->fxMixerView()->clear();
Song.cpp: if( gui && gui->automationEditor() )
Song.cpp: gui->automationEditor()->setCurrentPattern( NULL );
Song.cpp: if( gui && gui->pianoRoll() )
Song.cpp: gui->pianoRoll()->reset();
Song.cpp: if( gui && gui->getProjectNotes() )
Song.cpp: gui->getProjectNotes()->clear();
Song.cpp: if( gui->mainWindow() )
Song.cpp: gui->mainWindow()->resetWindowTitle();
Song.cpp: if( gui->mainWindow() )
Song.cpp: gui->mainWindow()->resetWindowTitle();
Song.cpp: gui->fxMixerView()->refreshDisplay();
Song.cpp: if( node.nodeName() == gui->getControllerRackView()->nodeName() )
Song.cpp: gui->getControllerRackView()->restoreState( node.toElement() );
Song.cpp: else if( node.nodeName() == gui->pianoRoll()->nodeName() )
Song.cpp: gui->pianoRoll()->restoreState( node.toElement() );
Song.cpp: else if( node.nodeName() == gui->automationEditor()->m_editor->nodeName() )
Song.cpp: gui->automationEditor()->m_editor->restoreState( node.toElement() );
Song.cpp: else if( node.nodeName() == gui->getProjectNotes()->nodeName() )
Song.cpp: gui->getProjectNotes()->SerializingObject::restoreState( node.toElement() );
Song.cpp: if( gui && gui->mainWindow() )
Song.cpp: gui->mainWindow()->resetWindowTitle();
Song.cpp: gui->getControllerRackView()->saveState( dataFile, dataFile.content() );
Song.cpp: gui->pianoRoll()->saveState( dataFile, dataFile.content() );
Song.cpp: gui->automationEditor()->m_editor->saveState( dataFile, dataFile.content() );
Song.cpp: gui->getProjectNotes()->SerializingObject::saveState( dataFile, dataFile.content() );
Song.cpp:// save current song and update the gui
Song.cpp:bool Song::guiSaveProject()
Song.cpp: gui->mainWindow()->resetWindowTitle();
Song.cpp:bool Song::guiSaveProjectAs( const QString & _file_name )
Song.cpp: if( guiSaveProject() == false )
Song.cpp: QMessageBox::information( gui->mainWindow(),
Song.cpp: FileDialog efd( gui->mainWindow() );
Song.cpp: ExportProjectDialog epd( exportFileName, gui->mainWindow(), multiExport );
Song.cpp: QMessageBox::information( gui->mainWindow(),
Song.cpp: FileDialog efd( gui->mainWindow() );
Song.cpp: if( Engine::hasGUI() && gui->mainWindow() &&
Song.cpp: QThread::currentThread() == gui->mainWindow()->thread() )
Song.cpp: gui->mainWindow()->resetWindowTitle();
main.cpp: QMessageBox::question( gui->mainWindow(), MainWindow::tr( "Project recovery" ),
main.cpp: gui->mainWindow()->show();
main.cpp: gui->mainWindow()->showMaximized();
main.cpp: gui->mainWindow()->show();
main.cpp: gui->mainWindow()->showMaximized();
main.cpp: gui->mainWindow()->show();
main.cpp: gui->mainWindow()->showMaximized();
Mixer.cpp: gui->pianoRoll()->isRecording() == true &&
It just a few lines but these contain audio drivers showing dialogs and the Song class accessing GUI classes left and right. :) Possible solutions might be:
In my opinion decoupling the core from the GUI should also imply being able to compile the core independently of the GUI and that the core should not have to link QtGui but only QtCore and similar libraries. |
@softrabbit
Many other core classes show message boxes. Being able to compile the core without the GUI, as suggested by @michaelgregorius, would improve the program's testability. |
Let's see... the audio and MIDI drivers provide setup widgets, good to know. But I'll save my thoughts on that for another issue.
Looks like it's only to collect errors when loading a Song. Forget I asked :)
In Song at least, signals should be fine as file operations are RT unsafe anyway, right? And that class looks like a pretty big offender so far.
Sure, if the GUI code gets in the way. ISTR some discussion on the subject, but was there ever a decision on which testing framework to use? |
File operation do not necessarily have to be RT unsafe. I think the coarse recipe for these cases is as follows. Let's say you want to switch a sample that's played in a sampler.
The GUI code will likely get in the way quite fast. Imagine you wanted to write unit tests for the Song class. You'd either have to have all the dialogs available during the test execution or you'd have to write code as currently seen in the Song class which checks a global variable that indicates whether the GUI is available which is quite clunky. |
Closing this because it's a design principle and not a clearly defined, achievable goal and therefore doesn't serve any real purpose on this tracker. |
Another issue related to code maintainability.
One way to make the code more maintainable is to make the core independent from the GUI, that is, keep low coupling.
The GUI should be allowed to use methods from the core (to both read and change its state), but the opposite should be avoided. In other words, instead of storing data in the GUI and allowing the core to read and change it (by means of methods, of course), data should be stored in the core and the GUI should read and change it. Data needed only by the GUI would be kept in the GUI, naturally.
However, the core is somewhat highly dependent from the GUI currently.
The text was updated successfully, but these errors were encountered: