Skip to content

Developers_manual

Paweł Salawa edited this page Mar 11, 2018 · 6 revisions

Table of Contents

This page describes aspects of SQLiteStudio core application development. Learning this will also help you with developing plugins.

Code conventions

switch-case with all cases explicit

Almost every switch-case for enums will list all cases (all enum values) explicitly. This is not a waste of time - it helps maintaining the code, because when you add new enum, the compiler will warn you that you didn't handle that enum value yet in such places.

For "switch-casing" enums, list all cases explicitly, don't use default keyword.

Application core (shared library)

Core application is enclosed in the coreSQLiteStudio shared library (*.dll/*.so/*.dylib). It's used by all clients (console, GUI), while it's independent from the actual interface implementation. It does not depend on QtGui or any other GUI library. It's linked with QtCore, QtXml and QtNetwork.

SQLiteStudio singleton

The SQLiteStudio singleton is a entry point for all services in the application (well, those enclosed in the core, not the ones from GUI or CLI). It can be accessed with a singleton method:

qDebug() << SQLiteStudio::getInstance()->getVersionString();

or easier, with a macro:

qDebug() << SQLITESTUDIO->getVersionString();

Database manager

Configuration manager

You will rarely use configuration manager explicitly. Instead you should use configuration containers created with model-view binding, namely CFG_CORE, CFG_UI and CFG_CLI. Nevertheless, sometimes you will want to manage SQL queries history, or add new functionality to the configuration manager, so here's how it works.

Plugin manager

Querying plugins

Registering new plugin type

Registering built-in plugin

Model-view binding

SQLiteStudio provides a very handy binding automation which connects data model with UI forms. It's used widely in the ConfigDialog, but also in several plugin-related dialogs. It allows plugins to be developed without GUI dependency, but yet having the UI forms when used from GUI.

The main configuration objects (CFG_CORE, CFG_UI and CFG_CLI) are defined using this framework.

This subject is quite extensive and was moved to a separate page: Model-view binding.

GUI application

Database list/tree

Binding UI form (widgets) to the configuration container

See the Model-view binding section above.

Shortcuts binding

Using SQLiteStudio's shortcuts binding solution makes any defined action shortcuts automatically available in the configuration dialog, including saving modified values into configuration file.

See Shortcuts binding for more details.

Icons

Dynamically loadable UI forms

Adding action to menu and toolbars

Plugins can create their own QAction and may need it to be added to SQLiteStudio's main menu, or to some toolbars.

Adding to main menu

This is easy. Just use one of:

MAINWINDOW->getDatabaseMenu()
MAINWINDOW->getStructureMenu()
MAINWINDOW->getViewMenu()
MAINWINDOW->getToolsMenu()

...to access particular menus. To access the menu bar (for example to add new menu) use:

MAINWINDOW->menuBar()

Adding to toolbars

In case of the main window there is always only one instance of it, so you can handle it in a similar way as for menus:

MAINWINDOW->getToolBar(MainWindow::TOOLBAR_MAIN)

The TOOLBAR_MAIN is the value of ToolBar enum defined in the MainWindow. This way you can query all toolbars placed in the main window.

MDI window toolbars

This is a little more complicated in case of MDI windows, such as EditorWindow, TableWindow, etc. You need to "register" and "deregister" actions for particular class and toolbar. This is possible thanks to the ExtActionContainer class, which is inherited by all SQLiteStudio widgets that have toolbar inside.

For example we will add and then remove action from the EditorWindow:

ExtActionPrototype* action = new ExtActionPrototype(QIcon(":/icons/icon.png"), tr("Action title"), this);
ExtActionContainer::insertActionBefore<EditorWindow>(action, EditorWindow::EXEC_QUERY, EditorWindow::TOOLBAR_MAIN);

// Now remove:
ExtActionContainer::removeAction<EditorWindow>(action, EditorWindow::TOOLBAR_MAIN);

The ExtActionPrototype is a special prototype for QAction that can be copied as QAction and inserted to different action containers (and this actually what's being done by the ExtActionContainer), while each action calls back the ExtActionPrototype when triggered. This ways the ExtActionPrototype knows which action (from which container) called it and so it emits signal with information which container exactly requested the action. See list of signals emitted by ExtActionPrototype below to learn more.

Adding action this way causes action to be added to all currently existing EditorWindow instances and also to every EditorWindow that will be open by the user in future.

This is important that when adding/removing action with ExtActionContainer methods you use toolbar enums from the same class that you specify as a template parameter to insertAction/removeAction, otherwise action might be added to wrong toolbar, or even worse - application can crash.

Some classes (and the EditorWindow is an example of it) have those static methods overloaded, so they don't require template parameter, Action and ToolBar enums are explicitly declared, instead of implict cast to integer. This makes above calls more human friendly and protects you from making a mistake with wrong toolbar type or wrong action type used (as in the warning above), because compiler will check those types:

ExtActionPrototype* action = new ExtActionPrototype(QIcon(":/icons/icon.png"), tr("Action title"), this);
EditorWindow::insertActionBefore(action, EditorWindow::EXEC_QUERY, EditorWindow::TOOLBAR_MAIN);

// Now remove:
EditorWindow::removeAction(action, EditorWindow::TOOLBAR_MAIN);

Other classes that have such overloaded methods are:

  • DataView
  • TableWindow
  • ViewWindow

For other ExtActionContainer classes you will have to use generic template methods from the ExtActionPrototype itself.

The ExtActionPrototype emits several useful signals. The most important is triggered(ExtActionContainer*,int), which tells you, that the action was triggered from given action container and given toolbar (toolbar integer represents enum value of the toolbar that the action was added to - use ExtActionContainer::getToolBar(int) to get QToolBar*.)

Other ExtActionPrototype signals will tell you when the action prototype is copied and inserted into ExtActionContainer, or when it's removed from the container. Arguments of those signals include the individual copy of QAction being added/removed from the container. You can use those signals to - for example - dynamically update action status (enabled or not), according to some changed in the action container.

Console application (CLI)

New release routine

  1. Check unit tests.
  2. Update translations (lupdate, translate, lrelease)
  3. Compile on all 3 platforms.
  4. Upload new app packages.
  5. Upload update repositories.
  6. Update Changelog on homepage.
  7. Post release news at homepage
  8. Post release news at social media
Clone this wiki locally