mirror of https://github.com/KLayout/klayout.git
WIP: introducing MacroController
The MacroController is the central facility for managing macros and their views. The plugin framework has been extended to support such a design. In addition, some small bugs have been fixed related to macro interpreters (specifically the DRC).
This commit is contained in:
parent
90693f9f67
commit
abb5424ece
|
|
@ -90,8 +90,17 @@ module DRC
|
|||
|
||||
# Constructor
|
||||
def initialize
|
||||
|
||||
# Make the DSL use ruby syntax highlighting
|
||||
self.syntax_scheme = "ruby"
|
||||
self.suffix = "drc"
|
||||
self.debugger_scheme = RBA::MacroInterpreter::RubyDebugger
|
||||
self.storage_scheme = RBA::MacroInterpreter::PlainTextWithHashAnnotationsFormat
|
||||
self.description = "DRC (Text)"
|
||||
|
||||
# Registers the new interpreter
|
||||
register("drc-dsl")
|
||||
|
||||
end
|
||||
|
||||
# Implements the execute method
|
||||
|
|
@ -99,27 +108,6 @@ module DRC
|
|||
DRC::execute_drc(macro)
|
||||
end
|
||||
|
||||
# Make the DSL use ruby syntax highlighting
|
||||
def syntax_scheme
|
||||
"ruby"
|
||||
end
|
||||
|
||||
def suffix
|
||||
"drc"
|
||||
end
|
||||
|
||||
def debugger_scheme
|
||||
return RBA::MacroInterpreter::RubyDebugger
|
||||
end
|
||||
|
||||
def storage_scheme
|
||||
return RBA::MacroInterpreter::PlainTextWithHashAnnotationsFormat
|
||||
end
|
||||
|
||||
def description
|
||||
return "DRC (Text)"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
# Register the new interpreters
|
||||
|
|
|
|||
246
src/lay/lay.pro
246
src/lay/lay.pro
|
|
@ -9,138 +9,140 @@ DEFINES += MAKE_LAY_LIBRARY
|
|||
TEMPLATE = lib
|
||||
|
||||
HEADERS = \
|
||||
layApplication.h \
|
||||
layClipDialog.h \
|
||||
layCrashMessage.h \
|
||||
layFillDialog.h \
|
||||
layGenericSyntaxHighlighter.h \
|
||||
layGSIHelpProvider.h \
|
||||
layHelpDialog.h \
|
||||
layHelpProvider.h \
|
||||
layHelpSource.h \
|
||||
layLayoutStatisticsForm.h \
|
||||
layLogViewerDialog.h \
|
||||
layMacro.h \
|
||||
layMacroEditorDialog.h \
|
||||
layMacroEditorPage.h \
|
||||
layMacroEditorSetupDialog.h \
|
||||
layMacroEditorTree.h \
|
||||
layMacroInterpreter.h \
|
||||
layMacroPropertiesDialog.h \
|
||||
layMacroVariableView.h \
|
||||
layMainConfigPages.h \
|
||||
layMainWindow.h \
|
||||
layNavigator.h \
|
||||
layProgress.h \
|
||||
layProgressWidget.h \
|
||||
layResourceHelpProvider.h \
|
||||
layRuntimeErrorForm.h \
|
||||
laySearchReplaceConfigPage.h \
|
||||
laySearchReplaceDialog.h \
|
||||
laySearchReplacePropertiesWidgets.h \
|
||||
laySelectCellViewForm.h \
|
||||
laySession.h \
|
||||
laySettingsForm.h \
|
||||
layTechnologySelector.h \
|
||||
layTechSetupDialog.h \
|
||||
layTextProgress.h \
|
||||
layVersion.h \
|
||||
layApplication.h \
|
||||
layClipDialog.h \
|
||||
layCrashMessage.h \
|
||||
layFillDialog.h \
|
||||
layGenericSyntaxHighlighter.h \
|
||||
layGSIHelpProvider.h \
|
||||
layHelpDialog.h \
|
||||
layHelpProvider.h \
|
||||
layHelpSource.h \
|
||||
layLayoutStatisticsForm.h \
|
||||
layLogViewerDialog.h \
|
||||
layMacro.h \
|
||||
layMacroEditorDialog.h \
|
||||
layMacroEditorPage.h \
|
||||
layMacroEditorSetupDialog.h \
|
||||
layMacroEditorTree.h \
|
||||
layMacroInterpreter.h \
|
||||
layMacroPropertiesDialog.h \
|
||||
layMacroVariableView.h \
|
||||
layMainConfigPages.h \
|
||||
layMainWindow.h \
|
||||
layNavigator.h \
|
||||
layProgress.h \
|
||||
layProgressWidget.h \
|
||||
layResourceHelpProvider.h \
|
||||
layRuntimeErrorForm.h \
|
||||
laySearchReplaceConfigPage.h \
|
||||
laySearchReplaceDialog.h \
|
||||
laySearchReplacePropertiesWidgets.h \
|
||||
laySelectCellViewForm.h \
|
||||
laySession.h \
|
||||
laySettingsForm.h \
|
||||
layTechnologySelector.h \
|
||||
layTechSetupDialog.h \
|
||||
layTextProgress.h \
|
||||
layVersion.h \
|
||||
layCommon.h \
|
||||
layConfig.h
|
||||
layConfig.h \
|
||||
layMacroController.h
|
||||
|
||||
FORMS = \
|
||||
ClipDialog.ui \
|
||||
CrashMessage.ui \
|
||||
Console.ui \
|
||||
DeleteModeDialog.ui \
|
||||
FillDialog.ui \
|
||||
HelpAboutDialog.ui \
|
||||
KeyBindingsConfigPage.ui \
|
||||
LayoutStatistics.ui \
|
||||
LogViewerDialog.ui \
|
||||
MacroEditorDialog.ui \
|
||||
MacroEditorSetupDialog.ui \
|
||||
MacroPropertiesDialog.ui \
|
||||
MacroTemplateSelectionDialog.ui \
|
||||
MainConfigPage.ui \
|
||||
MainConfigPage2.ui \
|
||||
MainConfigPage3.ui \
|
||||
MainConfigPage4.ui \
|
||||
MainConfigPage5.ui \
|
||||
MainConfigPage6.ui \
|
||||
ReplacePropertiesBox.ui \
|
||||
ReplacePropertiesInstance.ui \
|
||||
ReplacePropertiesPath.ui \
|
||||
ReplacePropertiesShape.ui \
|
||||
ReplacePropertiesText.ui \
|
||||
RuntimeErrorForm.ui \
|
||||
SearchPropertiesBox.ui \
|
||||
SearchPropertiesInstance.ui \
|
||||
SearchPropertiesPath.ui \
|
||||
SearchPropertiesShape.ui \
|
||||
SearchPropertiesText.ui \
|
||||
SearchReplaceConfigPage.ui \
|
||||
SearchReplaceDialog.ui \
|
||||
SelectCellViewForm.ui \
|
||||
SettingsForm.ui \
|
||||
TechBaseEditorPage.ui \
|
||||
TechComponentSetupDialog.ui \
|
||||
TechLayerMappingEditorPage.ui \
|
||||
TechMacrosPage.ui \
|
||||
TechSetupDialog.ui \
|
||||
XORToolDialog.ui \
|
||||
ClipDialog.ui \
|
||||
CrashMessage.ui \
|
||||
Console.ui \
|
||||
DeleteModeDialog.ui \
|
||||
FillDialog.ui \
|
||||
HelpAboutDialog.ui \
|
||||
KeyBindingsConfigPage.ui \
|
||||
LayoutStatistics.ui \
|
||||
LogViewerDialog.ui \
|
||||
MacroEditorDialog.ui \
|
||||
MacroEditorSetupDialog.ui \
|
||||
MacroPropertiesDialog.ui \
|
||||
MacroTemplateSelectionDialog.ui \
|
||||
MainConfigPage.ui \
|
||||
MainConfigPage2.ui \
|
||||
MainConfigPage3.ui \
|
||||
MainConfigPage4.ui \
|
||||
MainConfigPage5.ui \
|
||||
MainConfigPage6.ui \
|
||||
ReplacePropertiesBox.ui \
|
||||
ReplacePropertiesInstance.ui \
|
||||
ReplacePropertiesPath.ui \
|
||||
ReplacePropertiesShape.ui \
|
||||
ReplacePropertiesText.ui \
|
||||
RuntimeErrorForm.ui \
|
||||
SearchPropertiesBox.ui \
|
||||
SearchPropertiesInstance.ui \
|
||||
SearchPropertiesPath.ui \
|
||||
SearchPropertiesShape.ui \
|
||||
SearchPropertiesText.ui \
|
||||
SearchReplaceConfigPage.ui \
|
||||
SearchReplaceDialog.ui \
|
||||
SelectCellViewForm.ui \
|
||||
SettingsForm.ui \
|
||||
TechBaseEditorPage.ui \
|
||||
TechComponentSetupDialog.ui \
|
||||
TechLayerMappingEditorPage.ui \
|
||||
TechMacrosPage.ui \
|
||||
TechSetupDialog.ui \
|
||||
XORToolDialog.ui \
|
||||
TechLoadOptionsEditorPage.ui \
|
||||
TechSaveOptionsEditorPage.ui \
|
||||
MainConfigPage7.ui
|
||||
|
||||
SOURCES = \
|
||||
gsiDeclLayApplication.cc \
|
||||
gsiDeclLayHelpDialog.cc \
|
||||
gsiDeclLayMacro.cc \
|
||||
gsiDeclLayMainWindow.cc \
|
||||
layApplication.cc \
|
||||
layClipDialog.cc \
|
||||
layCrashMessage.cc \
|
||||
layFillDialog.cc \
|
||||
layGenericSyntaxHighlighter.cc \
|
||||
layGSIHelpProvider.cc \
|
||||
layHelpDialog.cc \
|
||||
layHelpProvider.cc \
|
||||
layHelpSource.cc \
|
||||
layLayoutStatisticsForm.cc \
|
||||
layLogViewerDialog.cc \
|
||||
layMacro.cc \
|
||||
layMacroEditorDialog.cc \
|
||||
layMacroEditorPage.cc \
|
||||
layMacroEditorSetupDialog.cc \
|
||||
layMacroEditorTree.cc \
|
||||
layMacroInterpreter.cc \
|
||||
layMacroPropertiesDialog.cc \
|
||||
layMacroVariableView.cc \
|
||||
layMainConfigPages.cc \
|
||||
layMainWindow.cc \
|
||||
layNavigator.cc \
|
||||
layProgress.cc \
|
||||
layProgressWidget.cc \
|
||||
layResourceHelpProvider.cc \
|
||||
layRuntimeErrorForm.cc \
|
||||
laySearchReplaceConfigPage.cc \
|
||||
laySearchReplaceDialog.cc \
|
||||
laySearchReplacePlugin.cc \
|
||||
laySearchReplacePropertiesWidgets.cc \
|
||||
laySelectCellViewForm.cc \
|
||||
laySession.cc \
|
||||
laySettingsForm.cc \
|
||||
layTechnologySelector.cc \
|
||||
layTechSetupDialog.cc \
|
||||
layTextProgress.cc \
|
||||
layVersion.cc \
|
||||
gsiDeclLayApplication.cc \
|
||||
gsiDeclLayHelpDialog.cc \
|
||||
gsiDeclLayMacro.cc \
|
||||
gsiDeclLayMainWindow.cc \
|
||||
layApplication.cc \
|
||||
layClipDialog.cc \
|
||||
layCrashMessage.cc \
|
||||
layFillDialog.cc \
|
||||
layGenericSyntaxHighlighter.cc \
|
||||
layGSIHelpProvider.cc \
|
||||
layHelpDialog.cc \
|
||||
layHelpProvider.cc \
|
||||
layHelpSource.cc \
|
||||
layLayoutStatisticsForm.cc \
|
||||
layLogViewerDialog.cc \
|
||||
layMacro.cc \
|
||||
layMacroEditorDialog.cc \
|
||||
layMacroEditorPage.cc \
|
||||
layMacroEditorSetupDialog.cc \
|
||||
layMacroEditorTree.cc \
|
||||
layMacroInterpreter.cc \
|
||||
layMacroPropertiesDialog.cc \
|
||||
layMacroVariableView.cc \
|
||||
layMainConfigPages.cc \
|
||||
layMainWindow.cc \
|
||||
layNavigator.cc \
|
||||
layProgress.cc \
|
||||
layProgressWidget.cc \
|
||||
layResourceHelpProvider.cc \
|
||||
layRuntimeErrorForm.cc \
|
||||
laySearchReplaceConfigPage.cc \
|
||||
laySearchReplaceDialog.cc \
|
||||
laySearchReplacePlugin.cc \
|
||||
laySearchReplacePropertiesWidgets.cc \
|
||||
laySelectCellViewForm.cc \
|
||||
laySession.cc \
|
||||
laySettingsForm.cc \
|
||||
layTechnologySelector.cc \
|
||||
layTechSetupDialog.cc \
|
||||
layTextProgress.cc \
|
||||
layVersion.cc \
|
||||
layMacroController.cc
|
||||
|
||||
RESOURCES = layBuildInMacros.qrc \
|
||||
layHelpResources.qrc \
|
||||
layLayoutStatistics.qrc \
|
||||
layMacroTemplates.qrc \
|
||||
layResources.qrc \
|
||||
layHelpResources.qrc \
|
||||
layLayoutStatistics.qrc \
|
||||
layMacroTemplates.qrc \
|
||||
layResources.qrc \
|
||||
|
||||
INCLUDEPATH += ../tl ../gsi ../db ../rdb ../laybasic ../ant ../img ../edt
|
||||
DEPENDPATH += ../tl ../gsi ../db ../rdb ../laybasic ../ant ../img ../edt
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
#include "layProgress.h"
|
||||
#include "layTextProgress.h"
|
||||
#include "layBackgroundAwareTreeStyle.h"
|
||||
#include "layMacroController.h"
|
||||
#include "gtf.h"
|
||||
#include "gsiDecl.h"
|
||||
#include "gsiInterpreter.h"
|
||||
|
|
@ -500,6 +501,8 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
|
|||
mp_qapp = this;
|
||||
mp_qapp_gui = (non_ui_mode ? 0 : this);
|
||||
|
||||
mp_dm_scheduler.reset (new tl::DeferredMethodScheduler ());
|
||||
|
||||
// install a special style proxy to overcome the issue of black-on-black tree expanders
|
||||
if (mp_qapp_gui) {
|
||||
mp_qapp_gui->setStyle (new lay::BackgroundAwareTreeStyle (0));
|
||||
|
|
@ -1099,11 +1102,10 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
|
|||
mp_plugin_root = new lay::PluginRoot ();
|
||||
}
|
||||
|
||||
// initialize the plugins (this should be the last action in the constructor since the
|
||||
// main window should be functional now.
|
||||
// initialize the plugins for the first time
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
|
||||
pd->initialize (mp_mw);
|
||||
pd->initialize (mp_plugin_root);
|
||||
}
|
||||
|
||||
// establish the configuration
|
||||
|
|
@ -1199,6 +1201,12 @@ Application::finish ()
|
|||
void
|
||||
Application::shutdown ()
|
||||
{
|
||||
// uninitialize the plugins
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
|
||||
pd->uninitialize (mp_plugin_root);
|
||||
}
|
||||
|
||||
if (mp_mw) {
|
||||
delete mp_mw;
|
||||
mp_mw = 0;
|
||||
|
|
@ -1357,9 +1365,10 @@ Application::run ()
|
|||
macro->set_file_path (*m);
|
||||
if (macro->show_in_menu ()) {
|
||||
// menu-based macros are just registered so they are shown in the menu
|
||||
if (mp_mw) {
|
||||
tl::log << "Register macro '" << *m << "'";
|
||||
mp_mw->add_temp_macro (macro.release ());
|
||||
lay::MacroController *mc = lay::MacroController::instance ();
|
||||
if (mc) {
|
||||
tl::log << "Registering macro '" << *m << "'";
|
||||
mc->add_temp_macro (macro.release ());
|
||||
}
|
||||
} else {
|
||||
// other macros given with -rm are run
|
||||
|
|
@ -1479,15 +1488,25 @@ Application::run ()
|
|||
player.replay (m_gtf_replay_rate, m_gtf_replay_stop);
|
||||
}
|
||||
|
||||
// update the menus with the macro menu bindings as late as possible (now we
|
||||
// can be sure that the menus are created propertly)
|
||||
mp_mw->update_menu_with_macros ();
|
||||
// Give the plugins a change to do some last-minute initialisation and checks
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
|
||||
pd->initialized (mp_mw);
|
||||
}
|
||||
|
||||
if (! m_no_gui && m_gtf_replay.empty () && ! mp_recorder) {
|
||||
// Show initial tip window if required
|
||||
mp_mw->about_to_exec ();
|
||||
}
|
||||
|
||||
} else if (mp_plugin_root) {
|
||||
|
||||
// Give the plugins a change to do some last-minute initialisation and checks
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
|
||||
pd->initialized (mp_plugin_root);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (! m_run_macro.empty ()) {
|
||||
|
|
@ -1586,7 +1605,7 @@ Application::process_events (QEventLoop::ProcessEventsFlags flags, bool silent)
|
|||
if (mp_mw) {
|
||||
|
||||
if (silent) {
|
||||
tl::DeferredMethodScheduler::instance ()->enable (false);
|
||||
mp_dm_scheduler->enable (false);
|
||||
}
|
||||
|
||||
#if QT_VERSION < 0x050000
|
||||
|
|
@ -1598,7 +1617,7 @@ Application::process_events (QEventLoop::ProcessEventsFlags flags, bool silent)
|
|||
mp_mw->enter_busy_mode (false);
|
||||
|
||||
if (silent) {
|
||||
tl::DeferredMethodScheduler::instance ()->enable (true);
|
||||
mp_dm_scheduler->enable (true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@
|
|||
|
||||
#include <set>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
namespace gsi
|
||||
{
|
||||
|
|
@ -44,6 +45,11 @@ namespace gtf
|
|||
class Recorder;
|
||||
}
|
||||
|
||||
namespace tl
|
||||
{
|
||||
class DeferredMethodScheduler;
|
||||
}
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
|
|
@ -339,6 +345,7 @@ private:
|
|||
bool m_enable_undo;
|
||||
QCoreApplication *mp_qapp;
|
||||
QApplication *mp_qapp_gui;
|
||||
std::auto_ptr<tl::DeferredMethodScheduler> mp_dm_scheduler;
|
||||
// HINT: the ruby interpreter must be destroyed before MainWindow
|
||||
// in order to maintain a valid MainWindow reference for ruby scripts and Ruby's GC all the time.
|
||||
gsi::Interpreter *mp_ruby_interpreter;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,395 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2017 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
#include "layMacroController.h"
|
||||
#include "layMacroEditorDialog.h"
|
||||
#include "layMacroInterpreter.h"
|
||||
#include "layMainWindow.h"
|
||||
#include "layMainConfigPages.h"
|
||||
#include "layConfig.h"
|
||||
#include "layApplication.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QUrl>
|
||||
#include <QMessageBox>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
MacroController::MacroController ()
|
||||
: mp_macro_editor (0), mp_mw (0),
|
||||
dm_do_update_menu_with_macros (this, &MacroController::do_update_menu_with_macros)
|
||||
{
|
||||
connect (&m_temp_macros, SIGNAL (menu_needs_update ()), this, SLOT (update_menu_with_macros ()));
|
||||
connect (&m_temp_macros, SIGNAL (macro_collection_changed (MacroCollection *)), this, SLOT (update_menu_with_macros ()));
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::initialized (lay::PluginRoot *root)
|
||||
{
|
||||
mp_mw = dynamic_cast <lay::MainWindow *> (root);
|
||||
if (mp_mw) {
|
||||
mp_macro_editor = new lay::MacroEditorDialog (mp_mw, &lay::MacroCollection::root ());
|
||||
mp_macro_editor->setModal (false);
|
||||
}
|
||||
|
||||
connect (&lay::MacroCollection::root (), SIGNAL (menu_needs_update ()), this, SLOT (update_menu_with_macros ()));
|
||||
connect (&lay::MacroCollection::root (), SIGNAL (macro_collection_changed (MacroCollection *)), this, SLOT (update_menu_with_macros ()));
|
||||
|
||||
// update the menus with the macro menu bindings as late as possible (now we
|
||||
// can be sure that the menus are created propertly)
|
||||
do_update_menu_with_macros ();
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::uninitialize (lay::PluginRoot * /*root*/)
|
||||
{
|
||||
disconnect (&lay::MacroCollection::root (), SIGNAL (menu_needs_update ()), this, SLOT (update_menu_with_macros ()));
|
||||
disconnect (&lay::MacroCollection::root (), SIGNAL (macro_collection_changed (MacroCollection *)), this, SLOT (update_menu_with_macros ()));
|
||||
|
||||
delete mp_macro_editor;
|
||||
mp_macro_editor = 0;
|
||||
mp_mw = 0;
|
||||
}
|
||||
|
||||
bool
|
||||
MacroController::configure (const std::string &key, const std::string &value)
|
||||
{
|
||||
if (key == cfg_key_bindings && mp_mw) {
|
||||
|
||||
// Update the shortcuts of the menu item if they have been edited in the configuration editor
|
||||
std::vector<std::pair<std::string, std::string> > key_bindings = unpack_key_binding (value);
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator kb = key_bindings.begin (); kb != key_bindings.end (); ++kb) {
|
||||
if (mp_mw->menu ()->is_valid (kb->first)) {
|
||||
lay::Action a = mp_mw->menu ()->action (kb->first);
|
||||
if (m_action_to_macro.find (a.qaction ()) != m_action_to_macro.end ()) {
|
||||
m_action_to_macro [a.qaction ()]->set_shortcut (kb->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::config_finalize()
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
bool
|
||||
MacroController::can_exit (lay::PluginRoot * /*root*/) const
|
||||
{
|
||||
if (mp_macro_editor) {
|
||||
return mp_macro_editor->can_exit ();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MacroController::accepts_drop (const std::string &path_or_url) const
|
||||
{
|
||||
QUrl url (tl::to_qstring (path_or_url));
|
||||
QFileInfo file_info (url.path ());
|
||||
QString suffix = file_info.suffix ().toLower ();
|
||||
|
||||
if (suffix == QString::fromUtf8 ("rb") ||
|
||||
suffix == QString::fromUtf8 ("py") ||
|
||||
suffix == QString::fromUtf8 ("lym")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// check the suffixes in the DSL interpreter declarations
|
||||
for (tl::Registrar<lay::MacroInterpreter>::iterator cls = tl::Registrar<lay::MacroInterpreter>::begin (); cls != tl::Registrar<lay::MacroInterpreter>::end (); ++cls) {
|
||||
if (suffix == tl::to_qstring (cls->suffix ())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::drop_url (const std::string &path_or_url)
|
||||
{
|
||||
// Normalize the URL to become either a normal path or a URL
|
||||
std::string path = path_or_url;
|
||||
|
||||
QUrl url (tl::to_qstring (path_or_url));
|
||||
QString file_name = QFileInfo (url.path ()).fileName ();
|
||||
|
||||
if (url.scheme () == QString::fromUtf8 ("file")) {
|
||||
path = tl::to_string (url.toLocalFile ());
|
||||
}
|
||||
|
||||
// load and run macro
|
||||
std::auto_ptr<lay::Macro> macro (new lay::Macro ());
|
||||
macro->load_from (path);
|
||||
macro->set_file_path (path);
|
||||
|
||||
if (macro->is_autorun () || macro->show_in_menu ()) {
|
||||
|
||||
// install macro permanently
|
||||
if (QMessageBox::question (mp_mw,
|
||||
QObject::tr ("Install Macro"),
|
||||
QObject::tr ("Install macro '%1' permanently?\n\nPress 'Yes' to install the macro in the application settings folder permanently.").arg (file_name),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No) == QMessageBox::Yes) {
|
||||
|
||||
// Use the application data folder
|
||||
QDir folder (tl::to_qstring (lay::Application::instance ()->appdata_path ()));
|
||||
|
||||
std::string cat = "macros";
|
||||
if (! macro->category ().empty ()) {
|
||||
cat = macro->category ();
|
||||
}
|
||||
|
||||
if (! folder.cd (tl::to_qstring (cat))) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Folder '%s' does not exists in installation path '%s' - cannot install")).c_str (), cat, lay::Application::instance ()->appdata_path ());
|
||||
}
|
||||
|
||||
QFileInfo target (folder, file_name);
|
||||
|
||||
if (! target.exists () || QMessageBox::question (mp_mw,
|
||||
QObject::tr ("Overwrite Macro"),
|
||||
QObject::tr ("Overwrite existing macro?"),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No) == QMessageBox::Yes) {
|
||||
|
||||
QFile target_file (target.filePath ());
|
||||
if (target.exists () && ! target_file.remove ()) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Unable to remove file '%1'").arg (target.filePath ())));
|
||||
}
|
||||
|
||||
macro->set_file_path (tl::to_string (target.filePath ()));
|
||||
|
||||
// run the macro now - if it fails, it is not installed, but the file path is already set to
|
||||
// the target path.
|
||||
if (macro->is_autorun ()) {
|
||||
macro->run ();
|
||||
}
|
||||
|
||||
macro->save ();
|
||||
|
||||
// refresh macro editor to show new macro plus to install the menus
|
||||
refresh ();
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (macro->is_autorun ()) {
|
||||
// If it is not installed, run it now ..
|
||||
macro->run ();
|
||||
} else if (macro->show_in_menu ()) {
|
||||
// .. or add as temporary macro so it is shown in the menu.
|
||||
add_temp_macro (macro.release ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
macro->run ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::show_editor (const std::string &cat, bool force_add)
|
||||
{
|
||||
if (mp_macro_editor) {
|
||||
mp_macro_editor->show (cat, force_add);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::refresh ()
|
||||
{
|
||||
if (mp_macro_editor) {
|
||||
mp_macro_editor->refresh ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::add_temp_macro (lay::Macro *m)
|
||||
{
|
||||
m_temp_macros.add_unspecific (m);
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::add_macro_items_to_menu (lay::MacroCollection &collection, int &n, std::set<std::string> &groups, const lay::Technology *tech, std::vector<std::pair<std::string, std::string> > *key_bindings)
|
||||
{
|
||||
for (lay::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) {
|
||||
|
||||
// check whether the macro collection is associated with the selected technology (if there is one)
|
||||
bool consider = false;
|
||||
if (! tech || c->second->virtual_mode () != lay::MacroCollection::TechFolder) {
|
||||
consider = true;
|
||||
} else {
|
||||
const std::vector<std::pair<std::string, std::string> > &mc = lay::Application::instance ()->macro_categories ();
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator cc = mc.begin (); cc != mc.end () && !consider; ++cc) {
|
||||
consider = (c->second->path () == tl::to_string (QDir (tl::to_qstring (tech->base_path ())).filePath (tl::to_qstring (cc->first))));
|
||||
}
|
||||
}
|
||||
|
||||
if (consider) {
|
||||
add_macro_items_to_menu (*c->second, n, groups, 0 /*don't check 2nd level and below*/, key_bindings);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (lay::MacroCollection::iterator c = collection.begin (); c != collection.end (); ++c) {
|
||||
|
||||
std::string sc = tl::trim (c->second->shortcut ());
|
||||
|
||||
if (c->second->show_in_menu ()) {
|
||||
|
||||
std::string mp = tl::trim (c->second->menu_path ());
|
||||
if (mp.empty ()) {
|
||||
mp = "macros_menu.end";
|
||||
}
|
||||
|
||||
std::string gn = tl::trim (c->second->group_name ());
|
||||
if (! gn.empty () && groups.find (gn) == groups.end ()) {
|
||||
groups.insert (gn);
|
||||
lay::Action as;
|
||||
as.set_separator (true);
|
||||
m_macro_actions.push_back (as);
|
||||
mp_mw->menu ()->insert_item (mp, "macro_in_menu_" + tl::to_string (n++), as);
|
||||
}
|
||||
|
||||
lay::Action a;
|
||||
if (c->second->description ().empty ()) {
|
||||
a.set_title (c->second->path ());
|
||||
} else {
|
||||
a.set_title (c->second->description ());
|
||||
}
|
||||
a.set_shortcut (sc);
|
||||
m_macro_actions.push_back (a);
|
||||
mp_mw->menu ()->insert_item (mp, "macro_in_menu_" + tl::to_string (n++), a);
|
||||
|
||||
m_action_to_macro.insert (std::make_pair (a.qaction (), c->second));
|
||||
|
||||
MacroSignalAdaptor *adaptor = new MacroSignalAdaptor (a.qaction (), c->second);
|
||||
QObject::connect (a.qaction (), SIGNAL (triggered ()), adaptor, SLOT (run ()));
|
||||
|
||||
// store the key bindings in the array
|
||||
if (!sc.empty () && key_bindings) {
|
||||
key_bindings->push_back (std::make_pair (mp, sc));
|
||||
}
|
||||
|
||||
} else if (! sc.empty ()) {
|
||||
|
||||
// Create actions for shortcut-only actions too and add them to the main window
|
||||
// to register their shortcut.
|
||||
|
||||
lay::Action a;
|
||||
if (c->second->description ().empty ()) {
|
||||
a.set_title (c->second->path ());
|
||||
} else {
|
||||
a.set_title (c->second->description ());
|
||||
}
|
||||
a.set_shortcut (sc);
|
||||
m_macro_actions.push_back (a);
|
||||
|
||||
mp_mw->addAction (a.qaction ());
|
||||
MacroSignalAdaptor *adaptor = new MacroSignalAdaptor (a.qaction (), c->second);
|
||||
QObject::connect (a.qaction (), SIGNAL (triggered ()), adaptor, SLOT (run ()));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::update_menu_with_macros ()
|
||||
{
|
||||
// empty action to macro table now we know it's invalid
|
||||
m_action_to_macro.clear ();
|
||||
dm_do_update_menu_with_macros ();
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::do_update_menu_with_macros ()
|
||||
{
|
||||
if (!mp_mw) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: implement this by asking the technology manager for the active technology
|
||||
const lay::Technology *tech = 0;
|
||||
if (mp_mw->current_view () && mp_mw->current_view ()->active_cellview_index () >= 0 && mp_mw->current_view ()->active_cellview_index () <= int (mp_mw->current_view ()->cellviews ())) {
|
||||
std::string active_tech = mp_mw->current_view ()->active_cellview ()->tech_name ();
|
||||
tech = lay::Technologies::instance ()->technology_by_name (active_tech);
|
||||
}
|
||||
|
||||
std::vector<std::pair<std::string, std::string> > key_bindings = unpack_key_binding (mp_mw->config_get (cfg_key_bindings));
|
||||
std::sort (key_bindings.begin (), key_bindings.end ());
|
||||
|
||||
std::vector<std::pair<std::string, std::string> > new_key_bindings;
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator kb = key_bindings.begin (); kb != key_bindings.end (); ++kb) {
|
||||
if (mp_mw->menu ()->is_valid (kb->first)) {
|
||||
lay::Action a = mp_mw->menu ()->action (kb->first);
|
||||
if (m_action_to_macro.find (a.qaction ()) == m_action_to_macro.end ()) {
|
||||
new_key_bindings.push_back (*kb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete all existing items
|
||||
for (std::vector<lay::Action>::iterator a = m_macro_actions.begin (); a != m_macro_actions.end (); ++a) {
|
||||
mp_mw->menu ()->delete_items (*a);
|
||||
}
|
||||
m_macro_actions.clear ();
|
||||
m_action_to_macro.clear ();
|
||||
|
||||
int n = 1;
|
||||
std::set<std::string> groups;
|
||||
add_macro_items_to_menu (m_temp_macros, n, groups, tech, 0);
|
||||
add_macro_items_to_menu (lay::MacroCollection::root (), n, groups, tech, &new_key_bindings);
|
||||
|
||||
// update the key bindings if required
|
||||
std::sort (new_key_bindings.begin (), new_key_bindings.end ());
|
||||
if (new_key_bindings != key_bindings) {
|
||||
mp_mw->config_set (cfg_key_bindings, pack_key_binding (new_key_bindings));
|
||||
}
|
||||
}
|
||||
|
||||
MacroController *
|
||||
MacroController::instance ()
|
||||
{
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
MacroController *mc = dynamic_cast <MacroController *> (cls.operator-> ());
|
||||
if (mc) {
|
||||
return mc;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// The singleton instance of the macro controller
|
||||
static tl::RegisteredClass<lay::PluginDeclaration> macro_controller_decl (new lay::MacroController (), 120, "MacroController");
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,157 @@
|
|||
|
||||
/*
|
||||
|
||||
KLayout Layout Viewer
|
||||
Copyright (C) 2006-2017 Matthias Koefferlein
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef HDR_layMacroController
|
||||
#define HDR_layMacroController
|
||||
|
||||
#include "layCommon.h"
|
||||
#include "layPlugin.h"
|
||||
#include "layMacro.h"
|
||||
#include "tlObject.h"
|
||||
#include "tlDeferredExecution.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <set>
|
||||
|
||||
#include <QObject>
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
class MacroEditorDialog;
|
||||
class MainWindow;
|
||||
class Technology;
|
||||
|
||||
/**
|
||||
* @brief A controller for the macro environment
|
||||
*
|
||||
* This object is a singleton that acts as a controller
|
||||
* for the macro environment. The controller is responsible
|
||||
* to managing the macro folders, autorunning of macros
|
||||
* and other things.
|
||||
*
|
||||
* It interacts with the MacroEditorDialog which basically
|
||||
* is the view for the macros.
|
||||
*
|
||||
* By making the controller a PluginDeclaration it will receive
|
||||
* initialization and configuration calls.
|
||||
*/
|
||||
class MacroController
|
||||
: public lay::PluginDeclaration, public tl::Object
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
MacroController ();
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
virtual void initialized (lay::PluginRoot *root);
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
virtual void uninitialize (lay::PluginRoot *root);
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
virtual bool configure (const std::string &key, const std::string &value);
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
virtual void config_finalize();
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the PluginDeclaration interface
|
||||
*/
|
||||
virtual bool can_exit (lay::PluginRoot *root) const;
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the plugin will accept a dropped file with the given URL or path
|
||||
*/
|
||||
virtual bool accepts_drop (const std::string &path_or_url) const;
|
||||
|
||||
/**
|
||||
* @brief Gets called when a file or URL is dropped on the plugin
|
||||
*/
|
||||
virtual void drop_url (const std::string &path_or_url);
|
||||
|
||||
/**
|
||||
* @brief Shows the macro editor
|
||||
*
|
||||
* Depending on the category, a different tip dialog will be shown.
|
||||
* If "force_add" is true, a new macro will be created, otherwise only
|
||||
* if none exists yet.
|
||||
*/
|
||||
void show_editor (const std::string &cat = std::string (), bool force_add = false);
|
||||
|
||||
/**
|
||||
* @brief Reloads all macros from the paths registered
|
||||
*/
|
||||
void refresh ();
|
||||
|
||||
/**
|
||||
* @brief Adds a temporary macro
|
||||
*
|
||||
* Temporary macros are such present on the command line or
|
||||
* dragged into the main window without installing.
|
||||
* They need to be present so they participate in the
|
||||
* menu building. Hence they are stored temporarily.
|
||||
* The MainWindow object will become owner of the macro object.
|
||||
*/
|
||||
void add_temp_macro (lay::Macro *m);
|
||||
|
||||
/**
|
||||
* @brief Gets the singleton instance for this object
|
||||
*/
|
||||
static MacroController *instance ();
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Update the menu with macros bound to a menu
|
||||
*/
|
||||
void update_menu_with_macros ();
|
||||
|
||||
private:
|
||||
lay::MacroEditorDialog *mp_macro_editor;
|
||||
lay::MainWindow *mp_mw;
|
||||
tl::DeferredMethod<MacroController> dm_do_update_menu_with_macros;
|
||||
std::vector<lay::Action> m_macro_actions;
|
||||
std::map<QAction *, lay::Macro *> m_action_to_macro;
|
||||
lay::MacroCollection m_temp_macros;
|
||||
|
||||
void add_macro_items_to_menu (lay::MacroCollection &collection, int &n, std::set<std::string> &groups, const lay::Technology *tech, std::vector<std::pair<std::string, std::string> > *key_bindings);
|
||||
void do_update_menu_with_macros ();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
@ -37,6 +37,7 @@
|
|||
#include "layQtTools.h"
|
||||
#include "layConfig.h"
|
||||
#include "layWidgets.h"
|
||||
#include "layProgress.h"
|
||||
#include "tlString.h"
|
||||
#include "tlClassRegistry.h"
|
||||
#include "tlExceptions.h"
|
||||
|
|
@ -253,6 +254,10 @@ MacroEditorDialog::MacroEditorDialog (QWidget * /*parent*/, lay::MacroCollection
|
|||
m_add_edit_trace_enabled (true),
|
||||
dm_refresh_file_watcher (this, &MacroEditorDialog::do_refresh_file_watcher)
|
||||
{
|
||||
// Makes this dialog receive events while progress bars are on - this way we can set breakpoints
|
||||
// during execution of a macro even if anything lengthy is running.
|
||||
lay::mark_widget_alive (this, true);
|
||||
|
||||
Ui::MacroEditorDialog::setupUi (this);
|
||||
|
||||
connect (mp_root, SIGNAL (macro_changed (Macro *)), this, SLOT (macro_changed (Macro *)));
|
||||
|
|
|
|||
|
|
@ -148,6 +148,12 @@ public:
|
|||
void select_category (const std::string &cat);
|
||||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Reloads all macros from the paths registered
|
||||
*/
|
||||
void refresh ();
|
||||
|
||||
private slots:
|
||||
void help_button_clicked ();
|
||||
void add_button_clicked ();
|
||||
void close_button_clicked ();
|
||||
|
|
@ -166,7 +172,6 @@ public slots:
|
|||
void properties_button_clicked ();
|
||||
void setup_button_clicked ();
|
||||
void breakpoint_button_clicked ();
|
||||
void refresh ();
|
||||
void add_location ();
|
||||
void remove_location ();
|
||||
void clear_breakpoints_button_clicked ();
|
||||
|
|
|
|||
|
|
@ -474,6 +474,9 @@ KeyBindingsConfigPage::apply (const std::vector<std::pair<std::string, std::stri
|
|||
|
||||
}
|
||||
|
||||
mp_ui->binding_le->setText (QString ());
|
||||
mp_ui->binding_le->setEnabled (false);
|
||||
|
||||
m_enable_event = true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,6 +50,7 @@
|
|||
#include "tlAssert.h"
|
||||
#include "tlDeferredExecution.h"
|
||||
#include "tlStream.h"
|
||||
#include "tlExceptions.h"
|
||||
#include "dbMemStatistics.h"
|
||||
#include "dbManager.h"
|
||||
#include "dbStream.h"
|
||||
|
|
@ -81,7 +82,6 @@
|
|||
#include "layMainConfigPages.h"
|
||||
#include "layAbstractMenu.h"
|
||||
#include "layQtTools.h"
|
||||
#include "tlExceptions.h"
|
||||
#include "laySaveLayoutOptionsDialog.h"
|
||||
#include "layLoadLayoutOptionsDialog.h"
|
||||
#include "layLogViewerDialog.h"
|
||||
|
|
@ -93,6 +93,7 @@
|
|||
#include "laySelectCellViewForm.h"
|
||||
#include "layLayoutPropertiesForm.h"
|
||||
#include "layLayoutStatisticsForm.h"
|
||||
#include "layMacroController.h"
|
||||
#include "ui_HelpAboutDialog.h"
|
||||
#include "gsi.h"
|
||||
#include "gtf.h"
|
||||
|
|
@ -410,7 +411,6 @@ MainWindow::MainWindow (QApplication *app, const char *name)
|
|||
m_open_mode (0),
|
||||
m_disable_tab_selected (false),
|
||||
m_exited (false),
|
||||
dm_do_update_menu_with_macros (this, &MainWindow::do_update_menu_with_macros),
|
||||
dm_do_update_menu (this, &MainWindow::do_update_menu),
|
||||
m_grid_micron (0.001),
|
||||
m_default_grids_updated (true),
|
||||
|
|
@ -419,7 +419,6 @@ MainWindow::MainWindow (QApplication *app, const char *name)
|
|||
m_synchronized_views (false),
|
||||
m_synchronous (false),
|
||||
m_busy (false),
|
||||
m_work_in_progress (false),
|
||||
mp_app (app)
|
||||
{
|
||||
setObjectName (QString::fromUtf8 (name));
|
||||
|
|
@ -437,16 +436,6 @@ MainWindow::MainWindow (QApplication *app, const char *name)
|
|||
|
||||
lay::register_help_handler (this, SLOT (show_help (const QString &)));
|
||||
|
||||
connect (&lay::MacroCollection::root (), SIGNAL (menu_needs_update ()), this, SLOT (update_menu_with_macros ()));
|
||||
connect (&lay::MacroCollection::root (), SIGNAL (macro_collection_changed (MacroCollection *)), this, SLOT (update_menu_with_macros ()));
|
||||
|
||||
if (lay::Application::instance ()) {
|
||||
mp_macro_editor = new lay::MacroEditorDialog (this, &lay::MacroCollection::root ());
|
||||
mp_macro_editor->setModal (false);
|
||||
} else {
|
||||
mp_macro_editor = 0;
|
||||
}
|
||||
|
||||
mp_assistant = new lay::HelpDialog (this);
|
||||
|
||||
mp_pr = new lay::ProgressReporter ();
|
||||
|
|
@ -679,13 +668,6 @@ MainWindow::~MainWindow ()
|
|||
{
|
||||
lay::register_help_handler (0, 0);
|
||||
|
||||
// uninitialize the plugins (this should be the first action in the constructor since the
|
||||
// main window should be functional still.
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
|
||||
pd->uninitialize (this);
|
||||
}
|
||||
|
||||
// since the configuration actions unregister themselves, we need to do this before the main
|
||||
// window is gone:
|
||||
m_ca_collection.clear ();
|
||||
|
|
@ -712,9 +694,6 @@ MainWindow::~MainWindow ()
|
|||
delete mp_log_viewer_dialog;
|
||||
mp_log_viewer_dialog = 0;
|
||||
|
||||
delete mp_macro_editor;
|
||||
mp_macro_editor = 0;
|
||||
|
||||
delete mp_assistant;
|
||||
mp_assistant = 0;
|
||||
}
|
||||
|
|
@ -1183,12 +1162,6 @@ MainWindow::close_all ()
|
|||
void
|
||||
MainWindow::about_to_exec ()
|
||||
{
|
||||
// Give the plugins a change to do some last-minute initialisation and checks
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
|
||||
pd->initialized (this);
|
||||
}
|
||||
|
||||
bool f;
|
||||
|
||||
// TODO: later, each view may get it's own editable flag
|
||||
|
|
@ -1654,18 +1627,10 @@ void
|
|||
MainWindow::apply_key_bindings ()
|
||||
{
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator kb = m_key_bindings.begin (); kb != m_key_bindings.end (); ++kb) {
|
||||
|
||||
if (menu ()->is_valid (kb->first)) {
|
||||
|
||||
lay::Action a = menu ()->action (kb->first);
|
||||
a.set_shortcut (kb->second);
|
||||
|
||||
if (m_action_to_macro.find (a.qaction ()) != m_action_to_macro.end ()) {
|
||||
m_action_to_macro [a.qaction ()]->set_shortcut (kb->second);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1793,8 +1758,11 @@ MainWindow::can_close ()
|
|||
|
||||
}
|
||||
|
||||
if (mp_macro_editor && ! mp_macro_editor->can_exit ()) {
|
||||
return false;
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
|
||||
if (! pd->can_exit (this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::string df_list;
|
||||
|
|
@ -1901,6 +1869,8 @@ MainWindow::cm_view_log ()
|
|||
void
|
||||
MainWindow::cm_print ()
|
||||
{
|
||||
// TODO: move to lay::LayoutView
|
||||
|
||||
BEGIN_PROTECTED
|
||||
|
||||
// Late-initialize the printer to save time on startup
|
||||
|
|
@ -2295,116 +2265,6 @@ MainWindow::cm_redo ()
|
|||
END_PROTECTED
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::add_macro_items_to_menu (lay::MacroCollection &collection, int &n, std::set<std::string> &groups, const lay::Technology *tech)
|
||||
{
|
||||
for (lay::MacroCollection::child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) {
|
||||
|
||||
// check whether the macro collection is associated with the selected technology (if there is one)
|
||||
bool consider = false;
|
||||
if (! tech || c->second->virtual_mode () != lay::MacroCollection::TechFolder) {
|
||||
consider = true;
|
||||
} else {
|
||||
const std::vector<std::pair<std::string, std::string> > &mc = lay::Application::instance ()->macro_categories ();
|
||||
for (std::vector<std::pair<std::string, std::string> >::const_iterator cc = mc.begin (); cc != mc.end () && !consider; ++cc) {
|
||||
consider = (c->second->path () == tl::to_string (QDir (tl::to_qstring (tech->base_path ())).filePath (tl::to_qstring (cc->first))));
|
||||
}
|
||||
}
|
||||
|
||||
if (consider) {
|
||||
add_macro_items_to_menu (*c->second, n, groups, 0 /*don't check 2nd level and below*/);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for (lay::MacroCollection::iterator c = collection.begin (); c != collection.end (); ++c) {
|
||||
|
||||
std::string sc = tl::trim (c->second->shortcut ());
|
||||
|
||||
if (c->second->show_in_menu ()) {
|
||||
|
||||
std::string mp = tl::trim (c->second->menu_path ());
|
||||
if (mp.empty ()) {
|
||||
mp = "macros_menu.end";
|
||||
}
|
||||
|
||||
std::string gn = tl::trim (c->second->group_name ());
|
||||
if (! gn.empty () && groups.find (gn) == groups.end ()) {
|
||||
groups.insert (gn);
|
||||
lay::Action as;
|
||||
as.set_separator (true);
|
||||
m_macro_actions.push_back (as);
|
||||
menu ()->insert_item (mp, "macro_in_menu_" + tl::to_string (n++), as);
|
||||
}
|
||||
|
||||
lay::Action a;
|
||||
if (c->second->description ().empty ()) {
|
||||
a.set_title (c->second->path ());
|
||||
} else {
|
||||
a.set_title (c->second->description ());
|
||||
}
|
||||
a.set_shortcut (sc);
|
||||
m_macro_actions.push_back (a);
|
||||
menu ()->insert_item (mp, "macro_in_menu_" + tl::to_string (n++), a);
|
||||
|
||||
m_action_to_macro.insert (std::make_pair (a.qaction (), c->second));
|
||||
|
||||
MacroSignalAdaptor *adaptor = new MacroSignalAdaptor (a.qaction (), c->second);
|
||||
QObject::connect (a.qaction (), SIGNAL (triggered ()), adaptor, SLOT (run ()));
|
||||
|
||||
} else if (! sc.empty ()) {
|
||||
|
||||
// Create actions for shortcut-only actions too and add them to the main window
|
||||
// to register their shortcut.
|
||||
|
||||
lay::Action a;
|
||||
if (c->second->description ().empty ()) {
|
||||
a.set_title (c->second->path ());
|
||||
} else {
|
||||
a.set_title (c->second->description ());
|
||||
}
|
||||
a.set_shortcut (sc);
|
||||
m_macro_actions.push_back (a);
|
||||
|
||||
addAction (a.qaction ());
|
||||
MacroSignalAdaptor *adaptor = new MacroSignalAdaptor (a.qaction (), c->second);
|
||||
QObject::connect (a.qaction (), SIGNAL (triggered ()), adaptor, SLOT (run ()));
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::update_menu_with_macros ()
|
||||
{
|
||||
// empty action to macro table now we know it's invalid
|
||||
m_action_to_macro.clear ();
|
||||
dm_do_update_menu_with_macros ();
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::do_update_menu_with_macros ()
|
||||
{
|
||||
const lay::Technology *tech = 0;
|
||||
if (current_view () && current_view ()->active_cellview_index () >= 0 && current_view ()->active_cellview_index () <= int (current_view ()->cellviews ())) {
|
||||
std::string active_tech = current_view ()->active_cellview ()->tech_name ();
|
||||
tech = lay::Technologies::instance ()->technology_by_name (active_tech);
|
||||
}
|
||||
|
||||
// delete all existing items
|
||||
for (std::vector<lay::Action>::iterator a = m_macro_actions.begin (); a != m_macro_actions.end (); ++a) {
|
||||
menu ()->delete_items (*a);
|
||||
}
|
||||
m_macro_actions.clear ();
|
||||
m_action_to_macro.clear ();
|
||||
|
||||
int n = 1;
|
||||
std::set<std::string> groups;
|
||||
add_macro_items_to_menu (m_temp_macros, n, groups, tech);
|
||||
add_macro_items_to_menu (lay::MacroCollection::root (), n, groups, tech);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::bookmark_menu_show ()
|
||||
{
|
||||
|
|
@ -3475,6 +3335,8 @@ MainWindow::cm_adjust_origin ()
|
|||
void
|
||||
MainWindow::cm_new_cell ()
|
||||
{
|
||||
// TODO: move this function to lay::LayoutView
|
||||
|
||||
BEGIN_PROTECTED
|
||||
|
||||
lay::LayoutView *curr = current_view ();
|
||||
|
|
@ -4634,68 +4496,15 @@ MainWindow::show_progress_bar (bool show)
|
|||
|
||||
} else {
|
||||
|
||||
if (m_work_in_progress != show) {
|
||||
|
||||
m_work_in_progress = show;
|
||||
if (show) {
|
||||
// to avoid recursions of any kind, disallow any user interaction except
|
||||
// cancelling the operation
|
||||
mp_app->installEventFilter (this);
|
||||
QApplication::setOverrideCursor (QCursor (Qt::WaitCursor));
|
||||
} else {
|
||||
mp_app->removeEventFilter (this);
|
||||
QApplication::restoreOverrideCursor ();
|
||||
}
|
||||
|
||||
// HINT: enabling the scheduler is accumulative - make sure that this method is only called when necessary
|
||||
tl::DeferredMethodScheduler::instance ()->enable (! show);
|
||||
|
||||
mp_main_stack_widget->setCurrentIndex (show ? 1 : 0);
|
||||
|
||||
if (show) {
|
||||
clear_current_pos ();
|
||||
}
|
||||
|
||||
mp_main_stack_widget->setCurrentIndex (show ? 1 : 0);
|
||||
if (show) {
|
||||
clear_current_pos ();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
MainWindow::eventFilter (QObject *obj, QEvent *event)
|
||||
{
|
||||
// do not handle events that are not targeted towards widgets
|
||||
if (! dynamic_cast <QWidget *> (obj)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// do not handle events if a modal widget is active (i.e. a message box)
|
||||
if (QApplication::activeModalWidget () && QApplication::activeModalWidget () != this) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dynamic_cast <QInputEvent *> (event)) {
|
||||
|
||||
QObject *o = obj;
|
||||
while (o) {
|
||||
// If the watched object is a child of the progress widget or the macro editor, pass the event on to this.
|
||||
// Including the macro editor keeps it alive while progress events are processed.
|
||||
if (o == mp_progress_widget || o == mp_macro_editor) {
|
||||
return false;
|
||||
}
|
||||
o = o->parent ();
|
||||
}
|
||||
|
||||
// eat the event
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::cm_technologies ()
|
||||
{
|
||||
|
|
@ -4716,41 +4525,42 @@ MainWindow::cm_technologies ()
|
|||
}
|
||||
|
||||
// because the macro-tech association might have changed, do this:
|
||||
update_menu_with_macros ();
|
||||
// TODO: let the macro controller monitor the technologies.
|
||||
lay::MacroController *mc = lay::MacroController::instance ();
|
||||
if (mc) {
|
||||
mc->update_menu_with_macros ();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::add_temp_macro (lay::Macro *m)
|
||||
{
|
||||
m_temp_macros.add_unspecific (m);
|
||||
update_menu_with_macros ();
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::show_macro_editor (const std::string &cat, bool add)
|
||||
{
|
||||
if (mp_macro_editor) {
|
||||
mp_macro_editor->show (cat, add);
|
||||
lay::MacroController *mc = lay::MacroController::instance ();
|
||||
if (mc) {
|
||||
mc->show_editor (cat, add);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::cm_edit_drc_scripts ()
|
||||
{
|
||||
// TODO: implement this as generic menu provided by the Interpreter
|
||||
show_macro_editor ("drc", false);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::cm_new_drc_script ()
|
||||
{
|
||||
// TODO: implement this as generic menu provided by the Interpreter
|
||||
show_macro_editor ("drc", true);
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::cm_macro_editor ()
|
||||
{
|
||||
// TODO: implement this as generic menu provided by the plugin declaration
|
||||
show_macro_editor ();
|
||||
}
|
||||
|
||||
|
|
@ -5394,8 +5204,10 @@ MainWindow::dropEvent(QDropEvent *event)
|
|||
QList<QUrl> urls = event->mimeData ()->urls ();
|
||||
for (QList<QUrl>::const_iterator url = urls.begin (); url != urls.end (); ++url) {
|
||||
|
||||
QUrl eff_url (*url);
|
||||
|
||||
QString path;
|
||||
if (url->scheme () == QString::fromUtf8 ("file")) {
|
||||
if (eff_url.scheme () == QString::fromUtf8 ("file")) {
|
||||
path = url->toLocalFile ();
|
||||
|
||||
#if defined(__APPLE__)
|
||||
|
|
@ -5452,101 +5264,38 @@ MainWindow::dropEvent(QDropEvent *event)
|
|||
CFRelease( relCFURL );
|
||||
CFRelease( relCFStringRef );
|
||||
}
|
||||
|
||||
eff_url = QUrl::fromLocalFile (path);
|
||||
#endif
|
||||
|
||||
} else if (url->scheme () == QString::fromUtf8 ("http") || url->scheme () == QString::fromUtf8 ("https")) {
|
||||
path = url->toString ();
|
||||
} else if (eff_url.scheme () == QString::fromUtf8 ("http") || eff_url.scheme () == QString::fromUtf8 ("https")) {
|
||||
path = eff_url.toString ();
|
||||
} else {
|
||||
// other schemes are not supported currently.
|
||||
continue;
|
||||
}
|
||||
|
||||
#if defined(__APPLE__)
|
||||
QFileInfo file_info (path); // Use the one resolved above
|
||||
QString suffix = file_info.suffix ().toLower ();
|
||||
#else
|
||||
QFileInfo file_info (url->path ()); // Original
|
||||
QString suffix = file_info.suffix ().toLower ();
|
||||
#endif
|
||||
if (suffix == QString::fromUtf8 ("rb") ||
|
||||
suffix == QString::fromUtf8 ("rbm") ||
|
||||
suffix == QString::fromUtf8 ("lym") ||
|
||||
suffix == QString::fromUtf8 ("lydrc") ||
|
||||
suffix == QString::fromUtf8 ("drc")) {
|
||||
// Let the plugins decide if they accept the drop
|
||||
|
||||
// load and run macro
|
||||
std::auto_ptr<lay::Macro> macro (new lay::Macro ());
|
||||
macro->load_from (tl::to_string (path));
|
||||
macro->set_file_path (tl::to_string (path));
|
||||
|
||||
if (macro->is_autorun () || macro->show_in_menu ()) {
|
||||
|
||||
// install ruby module permanently
|
||||
if (QMessageBox::question (this,
|
||||
QObject::tr ("Install Macro"),
|
||||
tl::to_qstring (tl::sprintf (tl::to_string (QObject::tr ("Install macro '%s' permanently?\n\nPress 'Yes' to install the macro in the application settings folder permanently.")).c_str (), tl::to_string (file_info.fileName ()).c_str ())),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No) == QMessageBox::Yes) {
|
||||
|
||||
// Use the application data folder
|
||||
QDir folder (tl::to_qstring (lay::Application::instance ()->appdata_path ()));
|
||||
|
||||
std::string cat = "macros";
|
||||
if (! macro->category ().empty ()) {
|
||||
cat = macro->category ();
|
||||
}
|
||||
|
||||
if (! folder.cd (tl::to_qstring (cat))) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Folder '%s' does not exists in installation path '%s' - cannot install")).c_str (), cat, lay::Application::instance ()->appdata_path ());
|
||||
}
|
||||
|
||||
QFileInfo target (folder, file_info.fileName ());
|
||||
|
||||
if (! target.exists () || QMessageBox::question (this,
|
||||
QObject::tr ("Overwrite Macro"),
|
||||
QObject::tr ("Overwrite existing macro?"),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No) == QMessageBox::Yes) {
|
||||
|
||||
QFile target_file (target.filePath ());
|
||||
if (target.exists () && ! target_file.remove ()) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Unable to remove file '%s'")).c_str (), tl::to_string (target.filePath ()).c_str ());
|
||||
}
|
||||
|
||||
macro->set_file_path (tl::to_string (target.filePath ()));
|
||||
|
||||
// run the macro now - if it fails, it is not installed, but the file path is already set to
|
||||
// the target path.
|
||||
if (macro->is_autorun ()) {
|
||||
macro->run ();
|
||||
}
|
||||
|
||||
macro->save ();
|
||||
|
||||
// refresh macro editor to show new macro plus to install the menus
|
||||
if (mp_macro_editor) {
|
||||
mp_macro_editor->refresh ();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
if (macro->is_autorun ()) {
|
||||
// If it is not installed, run it now ..
|
||||
macro->run ();
|
||||
} else if (macro->show_in_menu ()) {
|
||||
// .. or add as temporary macro so it is shown in the menu.
|
||||
add_temp_macro (macro.release ());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
macro->run ();
|
||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
|
||||
if (pd->accepts_drop (tl::to_string (eff_url.toString ()))) {
|
||||
pd->drop_url (tl::to_string (eff_url.toString ()));
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (suffix == QString::fromUtf8 ("lyp")) {
|
||||
if (current_view () && current_view ()->accepts_drop (tl::to_string (eff_url.toString ()))) {
|
||||
current_view ()->drop_url (tl::to_string (eff_url.toString ()));
|
||||
return;
|
||||
}
|
||||
|
||||
// Now try the built-in ones
|
||||
|
||||
QFileInfo file_info (eff_url.path ());
|
||||
QString suffix = file_info.suffix ().toLower ();
|
||||
|
||||
if (suffix == QString::fromUtf8 ("lyp")) {
|
||||
|
||||
load_layer_properties (tl::to_string (path), false /*current view only*/, false /*don't add a default*/);
|
||||
|
||||
|
|
|
|||
|
|
@ -520,17 +520,6 @@ public:
|
|||
*/
|
||||
void show_macro_editor (const std::string &cat = std::string (), bool add = false);
|
||||
|
||||
/**
|
||||
* @brief Adds a temporary macro
|
||||
*
|
||||
* Temporary macros are such present on the command line or
|
||||
* dragged into the main window without installing.
|
||||
* They need to be present so they participate in the
|
||||
* menu building. Hence they are stored temporarily.
|
||||
* The MainWindow object will become owner of the macro object.
|
||||
*/
|
||||
void add_temp_macro (lay::Macro *m);
|
||||
|
||||
/**
|
||||
* @brief Reimplementation of the plugin interface: handle a generic menu request
|
||||
*/
|
||||
|
|
@ -828,11 +817,6 @@ public slots:
|
|||
* Intended as a connection target for QLabel linkVisisted signals.
|
||||
*/
|
||||
void show_help (const QString &url);
|
||||
|
||||
/**
|
||||
* @brief Update the menu with macros bound to a menu
|
||||
*/
|
||||
void update_menu_with_macros ();
|
||||
|
||||
/**
|
||||
* @brief visibility of one of the dock widgets changed
|
||||
|
|
@ -852,7 +836,6 @@ protected slots:
|
|||
protected:
|
||||
void update_content ();
|
||||
void do_update_menu ();
|
||||
void do_update_menu_with_macros ();
|
||||
|
||||
private:
|
||||
TextProgressDelegate m_text_progress;
|
||||
|
|
@ -895,7 +878,6 @@ private:
|
|||
QLabel *mp_tech_status_label;
|
||||
bool m_disable_tab_selected;
|
||||
bool m_exited;
|
||||
tl::DeferredMethod<MainWindow> dm_do_update_menu_with_macros;
|
||||
tl::DeferredMethod<MainWindow> dm_do_update_menu;
|
||||
QTimer m_message_timer;
|
||||
QTimer m_file_changed_timer;
|
||||
|
|
@ -914,16 +896,11 @@ private:
|
|||
bool m_synchronized_views;
|
||||
bool m_synchronous;
|
||||
bool m_busy;
|
||||
bool m_work_in_progress;
|
||||
QApplication *mp_app;
|
||||
lay::MacroEditorDialog *mp_macro_editor;
|
||||
lay::HelpDialog *mp_assistant;
|
||||
std::string m_current_session;
|
||||
std::string m_message;
|
||||
std::auto_ptr<QPrinter> mp_printer;
|
||||
std::vector<lay::Action> m_macro_actions;
|
||||
std::map<QAction *, lay::Macro *> m_action_to_macro;
|
||||
lay::MacroCollection m_temp_macros;
|
||||
std::vector<QString> m_changed_files;
|
||||
|
||||
std::map<std::string, lay::Action> m_actions_for_slot;
|
||||
|
|
@ -937,7 +914,6 @@ private:
|
|||
|
||||
void init_menu ();
|
||||
|
||||
bool eventFilter (QObject *watched, QEvent *event);
|
||||
void closeEvent (QCloseEvent *event);
|
||||
void resizeEvent (QResizeEvent *event);
|
||||
|
||||
|
|
@ -963,8 +939,6 @@ private:
|
|||
virtual void plugin_removed (lay::PluginDeclaration *cls);
|
||||
|
||||
void libraries_changed ();
|
||||
|
||||
void add_macro_items_to_menu (lay::MacroCollection &collection, int &n, std::set<std::string> &groups, const lay::Technology *tech);
|
||||
void apply_key_bindings ();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -23,20 +23,40 @@
|
|||
|
||||
#include <QMutex>
|
||||
#include <QApplication>
|
||||
#include <QInputEvent>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
|
||||
#include "layProgress.h"
|
||||
#include "layMainWindow.h"
|
||||
#include "layApplication.h"
|
||||
#include "layProgressWidget.h"
|
||||
#include "tlProgress.h"
|
||||
#include "tlDeferredExecution.h"
|
||||
|
||||
namespace lay
|
||||
{
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
static const char *s_alive_prop_name = "klayout_progressAlive";
|
||||
|
||||
void mark_widget_alive (QWidget *w, bool alive)
|
||||
{
|
||||
if (alive) {
|
||||
w->setProperty (s_alive_prop_name, QVariant (true));
|
||||
} else {
|
||||
w->setProperty (s_alive_prop_name, QVariant ());
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_marked_alive (QObject *obj)
|
||||
{
|
||||
return obj->property (s_alive_prop_name).isValid ();
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
ProgressReporter::ProgressReporter ()
|
||||
: m_start_time (), mp_pb (0), m_pw_visible (false)
|
||||
{
|
||||
|
|
@ -55,11 +75,11 @@ ProgressReporter::set_progress_bar (lay::ProgressBar *pb)
|
|||
return;
|
||||
}
|
||||
if (mp_pb) {
|
||||
mp_pb->show_progress_bar (m_pw_visible);
|
||||
set_visible (m_pw_visible);
|
||||
}
|
||||
mp_pb = pb;
|
||||
if (mp_pb) {
|
||||
mp_pb->show_progress_bar (m_pw_visible);
|
||||
set_visible (m_pw_visible);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -75,10 +95,7 @@ ProgressReporter::register_object (tl::Progress *progress)
|
|||
|
||||
// make dialog visible after some time has passed
|
||||
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
|
||||
if (mp_pb) {
|
||||
mp_pb->show_progress_bar (true);
|
||||
}
|
||||
m_pw_visible = true;
|
||||
set_visible (true);
|
||||
}
|
||||
|
||||
update_and_yield ();
|
||||
|
|
@ -95,10 +112,9 @@ ProgressReporter::unregister_object (tl::Progress *progress)
|
|||
|
||||
// close or refresh window
|
||||
if (mp_objects.empty ()) {
|
||||
if (mp_pb) {
|
||||
mp_pb->show_progress_bar (false);
|
||||
if (m_pw_visible) {
|
||||
set_visible (false);
|
||||
}
|
||||
m_pw_visible = false;
|
||||
m_start_time = tl::Clock ();
|
||||
}
|
||||
|
||||
|
|
@ -116,10 +132,7 @@ ProgressReporter::trigger (tl::Progress *progress)
|
|||
if (! mp_objects.empty () && mp_objects.front () == progress) {
|
||||
// make dialog visible after some time has passed
|
||||
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
|
||||
if (mp_pb) {
|
||||
mp_pb->show_progress_bar (true);
|
||||
}
|
||||
m_pw_visible = true;
|
||||
set_visible (true);
|
||||
}
|
||||
update_and_yield ();
|
||||
}
|
||||
|
|
@ -130,10 +143,7 @@ ProgressReporter::yield (tl::Progress * /*progress*/)
|
|||
{
|
||||
// make dialog visible after some time has passed
|
||||
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
|
||||
if (mp_pb) {
|
||||
mp_pb->show_progress_bar (true);
|
||||
}
|
||||
m_pw_visible = true;
|
||||
set_visible (true);
|
||||
update_and_yield ();
|
||||
} else if (m_pw_visible) {
|
||||
// process events if necessary
|
||||
|
|
@ -166,8 +176,67 @@ ProgressReporter::update_and_yield ()
|
|||
void
|
||||
ProgressReporter::process_events ()
|
||||
{
|
||||
if (m_pw_visible && lay::MainWindow::instance () && lay::Application::instance ()) {
|
||||
lay::Application::instance ()->process_events ();
|
||||
if (m_pw_visible && lay::MainWindow::instance () && QApplication::instance ()) {
|
||||
QApplication::instance ()->processEvents (QEventLoop::AllEvents);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
ProgressReporter::set_visible (bool vis)
|
||||
{
|
||||
if (mp_pb) {
|
||||
mp_pb->show_progress_bar (vis);
|
||||
}
|
||||
|
||||
if (vis != m_pw_visible) {
|
||||
// prevent deferred method execution inside progress events - this might interfere with the
|
||||
// actual operation
|
||||
tl::DeferredMethodScheduler::enable (!vis);
|
||||
}
|
||||
|
||||
m_pw_visible = vis;
|
||||
|
||||
if (QApplication::instance()) {
|
||||
if (vis) {
|
||||
// to avoid recursions of any kind, disallow any user interaction except
|
||||
// cancelling the operation
|
||||
QApplication::instance ()->installEventFilter (this);
|
||||
} else {
|
||||
QApplication::instance ()->removeEventFilter (this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
ProgressReporter::eventFilter (QObject *obj, QEvent *event)
|
||||
{
|
||||
// do not handle events that are not targeted towards widgets
|
||||
if (! dynamic_cast <QWidget *> (obj)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// do not handle events if a modal widget is active (i.e. a message box)
|
||||
if (QApplication::activeModalWidget () && ! dynamic_cast<lay::MainWindow *> (QApplication::activeModalWidget ())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dynamic_cast <QInputEvent *> (event)) {
|
||||
|
||||
QObject *o = obj;
|
||||
while (o) {
|
||||
// If the watched object is a child of the progress widget or the macro editor, pass the event on to this.
|
||||
// Including the macro editor keeps it alive while progress events are processed.
|
||||
if (dynamic_cast<lay::ProgressWidget *> (o) || is_marked_alive (o)) {
|
||||
return false;
|
||||
}
|
||||
o = o->parent ();
|
||||
}
|
||||
|
||||
// eat the event
|
||||
return true;
|
||||
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ public:
|
|||
};
|
||||
|
||||
class LAY_PUBLIC ProgressReporter
|
||||
: public tl::ProgressAdaptor
|
||||
: public QObject, public tl::ProgressAdaptor
|
||||
{
|
||||
public:
|
||||
ProgressReporter ();
|
||||
|
|
@ -64,6 +64,7 @@ public:
|
|||
virtual void unregister_object (tl::Progress *progress);
|
||||
virtual void trigger (tl::Progress *progress);
|
||||
virtual void yield (tl::Progress *progress);
|
||||
virtual bool eventFilter (QObject *dest, QEvent *event);
|
||||
|
||||
void signal_break ();
|
||||
void set_progress_bar (lay::ProgressBar *pb);
|
||||
|
|
@ -76,8 +77,15 @@ private:
|
|||
|
||||
void process_events ();
|
||||
void update_and_yield ();
|
||||
void set_visible (bool vis);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Marks a widget as alive
|
||||
* "alive" widgets receive input events also while a progress reporter is shown
|
||||
*/
|
||||
LAY_PUBLIC void mark_widget_alive (QWidget *w, bool alive);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include "layPlugin.h"
|
||||
#include "laybasicConfig.h"
|
||||
#include "layMainWindow.h"
|
||||
#include "layMacroController.h"
|
||||
#include "layTechnology.h"
|
||||
#include "laybasicConfig.h"
|
||||
#include "tlDeferredExecution.h"
|
||||
|
|
@ -112,8 +113,12 @@ private:
|
|||
lay::MainWindow *mw = lay::MainWindow::instance ();
|
||||
if (mw) {
|
||||
mw->tech_message (tech_string_from_name (active_tech));
|
||||
}
|
||||
lay::MacroController *mc = lay::MacroController::instance ();
|
||||
if (mc) {
|
||||
// TODO: let the macro controller monitor the active technology
|
||||
// need to do this since macros may be bound to the new technology
|
||||
mw->update_menu_with_macros ();
|
||||
mc->update_menu_with_macros ();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -664,6 +664,26 @@ void LayoutView::viewport_changed ()
|
|||
viewport_changed_event ();
|
||||
}
|
||||
|
||||
bool LayoutView::accepts_drop (const std::string &path_or_url) const
|
||||
{
|
||||
for (std::vector<lay::Plugin *>::const_iterator p = mp_plugins.begin (); p != mp_plugins.end (); ++p) {
|
||||
if ((*p)->accepts_drop (path_or_url)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void LayoutView::drop_url (const std::string &path_or_url)
|
||||
{
|
||||
for (std::vector<lay::Plugin *>::const_iterator p = mp_plugins.begin (); p != mp_plugins.end (); ++p) {
|
||||
if ((*p)->accepts_drop (path_or_url)) {
|
||||
(*p)->drop_url (path_or_url);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lay::Plugin *LayoutView::create_plugin (lay::PluginRoot *root, const lay::PluginDeclaration *cls)
|
||||
{
|
||||
lay::Plugin *p = cls->create_plugin (manager (), root, this);
|
||||
|
|
@ -2584,7 +2604,7 @@ LayoutView::get_screenshot ()
|
|||
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Save screenshot")));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::instance ()->execute ();
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
|
||||
return mp_canvas->screenshot ();
|
||||
}
|
||||
|
|
@ -2614,7 +2634,7 @@ LayoutView::save_screenshot (const std::string &fn)
|
|||
writer.setText (QString::fromUtf8 ("Rect"), tl::to_qstring (desc));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::instance ()->execute ();
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
|
||||
if (! writer.write (mp_canvas->screenshot ())) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Unable to write screenshot to file: %s (%s)")), fn, tl::to_string (writer.errorString ()));
|
||||
|
|
@ -2629,7 +2649,7 @@ LayoutView::get_image (unsigned int width, unsigned int height)
|
|||
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Save image")));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::instance ()->execute ();
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
|
||||
return mp_canvas->image (width, height);
|
||||
}
|
||||
|
|
@ -2641,7 +2661,7 @@ LayoutView::get_image_with_options (unsigned int width, unsigned int height, int
|
|||
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Save image")));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::instance ()->execute ();
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
|
||||
return mp_canvas->image_with_options (width, height, linewidth, oversampling, resolution, background, foreground, active, target_box, monochrome);
|
||||
}
|
||||
|
|
@ -2667,7 +2687,7 @@ LayoutView::save_image (const std::string &fn, unsigned int width, unsigned int
|
|||
writer.setText (QString::fromUtf8 ("Rect"), tl::to_qstring (vp.box ().to_string ()));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::instance ()->execute ();
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
|
||||
if (! writer.write (mp_canvas->image (width, height))) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Unable to write screenshot to file: %s (%s)")), fn, tl::to_string (writer.errorString ()));
|
||||
|
|
@ -2699,7 +2719,7 @@ LayoutView::save_image_with_options (const std::string &fn,
|
|||
writer.setText (QString::fromUtf8 ("Rect"), tl::to_qstring (vp.box ().to_string ()));
|
||||
|
||||
// Execute all deferred methods - ensure there are no pending tasks
|
||||
tl::DeferredMethodScheduler::instance ()->execute ();
|
||||
tl::DeferredMethodScheduler::execute ();
|
||||
|
||||
if (! writer.write (mp_canvas->image_with_options (width, height, linewidth, oversampling, resolution, background, foreground, active, target_box, monochrome))) {
|
||||
throw tl::Exception (tl::to_string (QObject::tr ("Unable to write screenshot to file: %s (%s)")), fn, tl::to_string (writer.errorString ()));
|
||||
|
|
|
|||
|
|
@ -1878,7 +1878,17 @@ public:
|
|||
return m_drawing_workers;
|
||||
}
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Gets a value indicating whether the view will accept a dropped file with the given URL or path
|
||||
*/
|
||||
virtual bool accepts_drop (const std::string &path_or_url) const;
|
||||
|
||||
/**
|
||||
* @brief Gets called when a file or URL is dropped on the view
|
||||
*/
|
||||
virtual void drop_url (const std::string &path_or_url);
|
||||
|
||||
/**
|
||||
* @brief Localize a plugin by name
|
||||
*
|
||||
* This method will return 0, if no such plugin is registered
|
||||
|
|
|
|||
|
|
@ -264,6 +264,17 @@ public:
|
|||
// .. the default implementation does nothing ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the plugin can exit
|
||||
*
|
||||
* If the plugin wants to prevent the application from closing, it may return false
|
||||
* in this method.
|
||||
*/
|
||||
virtual bool can_exit (lay::PluginRoot * /*root*/) const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Fetch the menu objects for this plugin
|
||||
*
|
||||
|
|
@ -369,6 +380,22 @@ public:
|
|||
return m_editable_enabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the plugin will accept a dropped file with the given URL or path
|
||||
*/
|
||||
virtual bool accepts_drop (const std::string & /*path_or_url*/) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets called when a file or URL is dropped on the plugin
|
||||
*/
|
||||
virtual void drop_url (const std::string & /*path_or_url*/)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Notifies that plugin root that a new plugin was registered
|
||||
*
|
||||
|
|
@ -661,6 +688,22 @@ public:
|
|||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets a value indicating whether the plugin will accept a dropped file with the given URL or path
|
||||
*/
|
||||
virtual bool accepts_drop (const std::string & /*path_or_url*/) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Gets called when a file or URL is dropped on the plugin
|
||||
*/
|
||||
virtual void drop_url (const std::string & /*path_or_url*/)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Associate a plugin with the plugin declaration for that service (getter)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -34,8 +34,8 @@ namespace tl
|
|||
|
||||
static DeferredMethodScheduler *s_inst = 0;
|
||||
|
||||
DeferredMethodScheduler::DeferredMethodScheduler (QObject *parent)
|
||||
: QObject (parent),
|
||||
DeferredMethodScheduler::DeferredMethodScheduler ()
|
||||
: QObject (0),
|
||||
m_disabled (0), m_scheduled (false)
|
||||
{
|
||||
connect (&m_timer, SIGNAL (timeout ()), this, SLOT (timer ()));
|
||||
|
|
@ -47,6 +47,9 @@ DeferredMethodScheduler::DeferredMethodScheduler (QObject *parent)
|
|||
connect (&m_fallback_timer, SIGNAL (timeout ()), this, SLOT (timer ()));
|
||||
m_fallback_timer.setInterval (500);
|
||||
m_fallback_timer.setSingleShot (false);
|
||||
|
||||
tl_assert (! s_inst);
|
||||
s_inst = this;
|
||||
}
|
||||
|
||||
DeferredMethodScheduler::~DeferredMethodScheduler ()
|
||||
|
|
@ -57,12 +60,8 @@ DeferredMethodScheduler::~DeferredMethodScheduler ()
|
|||
DeferredMethodScheduler *
|
||||
DeferredMethodScheduler::instance ()
|
||||
{
|
||||
static QMutex lock;
|
||||
lock.lock ();
|
||||
if (s_inst == 0) {
|
||||
s_inst = new DeferredMethodScheduler (qApp);
|
||||
}
|
||||
lock.unlock ();
|
||||
// NOTE: this is not locked intentionally. The instance is shut down once in the application shortly before it
|
||||
// will terminate and it is created initially before any threads start.
|
||||
return s_inst;
|
||||
}
|
||||
|
||||
|
|
@ -98,7 +97,7 @@ DeferredMethodScheduler::unqueue (DeferredMethodBase *method)
|
|||
}
|
||||
|
||||
void
|
||||
DeferredMethodScheduler::enable (bool en)
|
||||
DeferredMethodScheduler::do_enable (bool en)
|
||||
{
|
||||
m_lock.lock ();
|
||||
if (en) {
|
||||
|
|
@ -129,7 +128,7 @@ DeferredMethodScheduler::timer ()
|
|||
m_timer.start ();
|
||||
} else {
|
||||
try {
|
||||
execute ();
|
||||
do_execute ();
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << tl::to_string (QObject::tr ("Exception caught: ")) << ex.msg ();
|
||||
} catch (std::exception &ex) {
|
||||
|
|
@ -141,7 +140,7 @@ DeferredMethodScheduler::timer ()
|
|||
}
|
||||
|
||||
void
|
||||
DeferredMethodScheduler::execute ()
|
||||
DeferredMethodScheduler::do_execute ()
|
||||
{
|
||||
std::list<DeferredMethodBase *> methods;
|
||||
|
||||
|
|
|
|||
|
|
@ -71,6 +71,16 @@ class TL_PUBLIC DeferredMethodScheduler
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor
|
||||
*/
|
||||
DeferredMethodScheduler ();
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~DeferredMethodScheduler ();
|
||||
|
||||
/**
|
||||
* @brief The singleton instance of the scheduler
|
||||
*/
|
||||
|
|
@ -93,17 +103,27 @@ public:
|
|||
* when the application is supposed only to show a progress bar and
|
||||
* therefore will process events but is not supposed to execute anything else.
|
||||
*
|
||||
* Enabling is cumulative: multiple enable(true) calls must be matched to
|
||||
* the same number of enable(false) calls.
|
||||
* Enabling is cumulative: multiple enable(true) calls must be matched to
|
||||
* the same number of enable(false) calls.
|
||||
*/
|
||||
void enable (bool en);
|
||||
static void enable (bool en)
|
||||
{
|
||||
if (instance ()) {
|
||||
instance ()->do_enable (en);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Execute all queued methods
|
||||
*
|
||||
*
|
||||
* This method can be called to force execution of all queued methods.
|
||||
*/
|
||||
void execute ();
|
||||
static void execute ()
|
||||
{
|
||||
if (instance ()) {
|
||||
instance ()->do_execute ();
|
||||
}
|
||||
}
|
||||
|
||||
private slots:
|
||||
void timer ();
|
||||
|
|
@ -115,10 +135,9 @@ private:
|
|||
QTimer m_timer, m_fallback_timer;
|
||||
QMutex m_lock;
|
||||
|
||||
DeferredMethodScheduler (QObject *parent);
|
||||
~DeferredMethodScheduler ();
|
||||
|
||||
virtual bool event (QEvent *event);
|
||||
void do_enable (bool en);
|
||||
void do_execute ();
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
@ -169,7 +188,9 @@ public:
|
|||
*/
|
||||
~DeferredMethod ()
|
||||
{
|
||||
DeferredMethodScheduler::instance ()->unqueue (this);
|
||||
if (DeferredMethodScheduler::instance ()) {
|
||||
DeferredMethodScheduler::instance ()->unqueue (this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -177,9 +198,13 @@ public:
|
|||
*/
|
||||
void operator() ()
|
||||
{
|
||||
// management of m_compressed and m_scheduled is done in the DeferredMethodScheduler -
|
||||
// there it is safely locked. Doing it there saves a private mutex for this object.
|
||||
DeferredMethodScheduler::instance ()->schedule (this);
|
||||
if (DeferredMethodScheduler::instance ()) {
|
||||
// management of m_compressed and m_scheduled is done in the DeferredMethodScheduler -
|
||||
// there it is safely locked. Doing it there saves a private mutex for this object.
|
||||
DeferredMethodScheduler::instance ()->schedule (this);
|
||||
} else {
|
||||
execute ();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -187,7 +212,9 @@ public:
|
|||
*/
|
||||
void cancel ()
|
||||
{
|
||||
DeferredMethodScheduler::instance ()->unqueue (this);
|
||||
if (DeferredMethodScheduler::instance ()) {
|
||||
DeferredMethodScheduler::instance ()->unqueue (this);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -196,7 +223,7 @@ public:
|
|||
void execute ()
|
||||
{
|
||||
// cancel execution which might be pending
|
||||
DeferredMethodScheduler::instance ()->unqueue (this);
|
||||
cancel ();
|
||||
(mp_t->*m_method) ();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
#include "tlString.h"
|
||||
|
||||
#include <QFileInfo>
|
||||
#include <QUrl>
|
||||
|
||||
namespace tl
|
||||
{
|
||||
|
|
@ -325,7 +326,8 @@ InputStream::InputStream (const std::string &abstract_path)
|
|||
mp_delegate = new InputPipe (ex.get ());
|
||||
#endif
|
||||
} else if (ex.test ("file:")) {
|
||||
mp_delegate = new InputZLibFile (ex.get ());
|
||||
QUrl url (tl::to_qstring (abstract_path));
|
||||
mp_delegate = new InputZLibFile (tl::to_string (url.toLocalFile ()));
|
||||
} else {
|
||||
mp_delegate = new InputZLibFile (abstract_path);
|
||||
}
|
||||
|
|
@ -345,7 +347,8 @@ std::string InputStream::absolute_path (const std::string &abstract_path)
|
|||
return abstract_path;
|
||||
#endif
|
||||
} else if (ex.test ("file:")) {
|
||||
return tl::to_string (QFileInfo (tl::to_qstring (ex.get ())).absoluteFilePath ());
|
||||
QUrl url (tl::to_qstring (abstract_path));
|
||||
return tl::to_string (QFileInfo (url.toLocalFile ()).absoluteFilePath ());
|
||||
} else {
|
||||
return tl::to_string (QFileInfo (tl::to_qstring (abstract_path)).absoluteFilePath ());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@ public:
|
|||
|
||||
TEST(1)
|
||||
{
|
||||
tl::DeferredMethodScheduler scheduler ();
|
||||
|
||||
g_na = g_nb = 0;
|
||||
|
||||
QCoreApplication::instance ()->processEvents ();
|
||||
|
|
@ -70,8 +72,8 @@ TEST(1)
|
|||
EXPECT_EQ (g_na, 0);
|
||||
EXPECT_EQ (g_nb, 0);
|
||||
|
||||
tl::DeferredMethodScheduler::instance ()->enable (false);
|
||||
tl::DeferredMethodScheduler::instance ()->enable (false);
|
||||
tl::DeferredMethodScheduler::enable (false);
|
||||
tl::DeferredMethodScheduler::enable (false);
|
||||
|
||||
QCoreApplication::instance ()->processEvents ();
|
||||
|
||||
|
|
@ -80,7 +82,7 @@ TEST(1)
|
|||
EXPECT_EQ (g_na, 0);
|
||||
EXPECT_EQ (g_nb, 0);
|
||||
|
||||
tl::DeferredMethodScheduler::instance ()->enable (true);
|
||||
tl::DeferredMethodScheduler::enable (true);
|
||||
|
||||
x->db ();
|
||||
x->db ();
|
||||
|
|
@ -92,7 +94,7 @@ TEST(1)
|
|||
EXPECT_EQ (g_na, 0);
|
||||
EXPECT_EQ (g_nb, 0);
|
||||
|
||||
tl::DeferredMethodScheduler::instance ()->enable (true);
|
||||
tl::DeferredMethodScheduler::enable (true);
|
||||
|
||||
QCoreApplication::instance ()->processEvents ();
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue