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
|
# Constructor
|
||||||
def initialize
|
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
|
# Registers the new interpreter
|
||||||
register("drc-dsl")
|
register("drc-dsl")
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# Implements the execute method
|
# Implements the execute method
|
||||||
|
|
@ -99,27 +108,6 @@ module DRC
|
||||||
DRC::execute_drc(macro)
|
DRC::execute_drc(macro)
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
# Register the new interpreters
|
# Register the new interpreters
|
||||||
|
|
|
||||||
246
src/lay/lay.pro
246
src/lay/lay.pro
|
|
@ -9,138 +9,140 @@ DEFINES += MAKE_LAY_LIBRARY
|
||||||
TEMPLATE = lib
|
TEMPLATE = lib
|
||||||
|
|
||||||
HEADERS = \
|
HEADERS = \
|
||||||
layApplication.h \
|
layApplication.h \
|
||||||
layClipDialog.h \
|
layClipDialog.h \
|
||||||
layCrashMessage.h \
|
layCrashMessage.h \
|
||||||
layFillDialog.h \
|
layFillDialog.h \
|
||||||
layGenericSyntaxHighlighter.h \
|
layGenericSyntaxHighlighter.h \
|
||||||
layGSIHelpProvider.h \
|
layGSIHelpProvider.h \
|
||||||
layHelpDialog.h \
|
layHelpDialog.h \
|
||||||
layHelpProvider.h \
|
layHelpProvider.h \
|
||||||
layHelpSource.h \
|
layHelpSource.h \
|
||||||
layLayoutStatisticsForm.h \
|
layLayoutStatisticsForm.h \
|
||||||
layLogViewerDialog.h \
|
layLogViewerDialog.h \
|
||||||
layMacro.h \
|
layMacro.h \
|
||||||
layMacroEditorDialog.h \
|
layMacroEditorDialog.h \
|
||||||
layMacroEditorPage.h \
|
layMacroEditorPage.h \
|
||||||
layMacroEditorSetupDialog.h \
|
layMacroEditorSetupDialog.h \
|
||||||
layMacroEditorTree.h \
|
layMacroEditorTree.h \
|
||||||
layMacroInterpreter.h \
|
layMacroInterpreter.h \
|
||||||
layMacroPropertiesDialog.h \
|
layMacroPropertiesDialog.h \
|
||||||
layMacroVariableView.h \
|
layMacroVariableView.h \
|
||||||
layMainConfigPages.h \
|
layMainConfigPages.h \
|
||||||
layMainWindow.h \
|
layMainWindow.h \
|
||||||
layNavigator.h \
|
layNavigator.h \
|
||||||
layProgress.h \
|
layProgress.h \
|
||||||
layProgressWidget.h \
|
layProgressWidget.h \
|
||||||
layResourceHelpProvider.h \
|
layResourceHelpProvider.h \
|
||||||
layRuntimeErrorForm.h \
|
layRuntimeErrorForm.h \
|
||||||
laySearchReplaceConfigPage.h \
|
laySearchReplaceConfigPage.h \
|
||||||
laySearchReplaceDialog.h \
|
laySearchReplaceDialog.h \
|
||||||
laySearchReplacePropertiesWidgets.h \
|
laySearchReplacePropertiesWidgets.h \
|
||||||
laySelectCellViewForm.h \
|
laySelectCellViewForm.h \
|
||||||
laySession.h \
|
laySession.h \
|
||||||
laySettingsForm.h \
|
laySettingsForm.h \
|
||||||
layTechnologySelector.h \
|
layTechnologySelector.h \
|
||||||
layTechSetupDialog.h \
|
layTechSetupDialog.h \
|
||||||
layTextProgress.h \
|
layTextProgress.h \
|
||||||
layVersion.h \
|
layVersion.h \
|
||||||
layCommon.h \
|
layCommon.h \
|
||||||
layConfig.h
|
layConfig.h \
|
||||||
|
layMacroController.h
|
||||||
|
|
||||||
FORMS = \
|
FORMS = \
|
||||||
ClipDialog.ui \
|
ClipDialog.ui \
|
||||||
CrashMessage.ui \
|
CrashMessage.ui \
|
||||||
Console.ui \
|
Console.ui \
|
||||||
DeleteModeDialog.ui \
|
DeleteModeDialog.ui \
|
||||||
FillDialog.ui \
|
FillDialog.ui \
|
||||||
HelpAboutDialog.ui \
|
HelpAboutDialog.ui \
|
||||||
KeyBindingsConfigPage.ui \
|
KeyBindingsConfigPage.ui \
|
||||||
LayoutStatistics.ui \
|
LayoutStatistics.ui \
|
||||||
LogViewerDialog.ui \
|
LogViewerDialog.ui \
|
||||||
MacroEditorDialog.ui \
|
MacroEditorDialog.ui \
|
||||||
MacroEditorSetupDialog.ui \
|
MacroEditorSetupDialog.ui \
|
||||||
MacroPropertiesDialog.ui \
|
MacroPropertiesDialog.ui \
|
||||||
MacroTemplateSelectionDialog.ui \
|
MacroTemplateSelectionDialog.ui \
|
||||||
MainConfigPage.ui \
|
MainConfigPage.ui \
|
||||||
MainConfigPage2.ui \
|
MainConfigPage2.ui \
|
||||||
MainConfigPage3.ui \
|
MainConfigPage3.ui \
|
||||||
MainConfigPage4.ui \
|
MainConfigPage4.ui \
|
||||||
MainConfigPage5.ui \
|
MainConfigPage5.ui \
|
||||||
MainConfigPage6.ui \
|
MainConfigPage6.ui \
|
||||||
ReplacePropertiesBox.ui \
|
ReplacePropertiesBox.ui \
|
||||||
ReplacePropertiesInstance.ui \
|
ReplacePropertiesInstance.ui \
|
||||||
ReplacePropertiesPath.ui \
|
ReplacePropertiesPath.ui \
|
||||||
ReplacePropertiesShape.ui \
|
ReplacePropertiesShape.ui \
|
||||||
ReplacePropertiesText.ui \
|
ReplacePropertiesText.ui \
|
||||||
RuntimeErrorForm.ui \
|
RuntimeErrorForm.ui \
|
||||||
SearchPropertiesBox.ui \
|
SearchPropertiesBox.ui \
|
||||||
SearchPropertiesInstance.ui \
|
SearchPropertiesInstance.ui \
|
||||||
SearchPropertiesPath.ui \
|
SearchPropertiesPath.ui \
|
||||||
SearchPropertiesShape.ui \
|
SearchPropertiesShape.ui \
|
||||||
SearchPropertiesText.ui \
|
SearchPropertiesText.ui \
|
||||||
SearchReplaceConfigPage.ui \
|
SearchReplaceConfigPage.ui \
|
||||||
SearchReplaceDialog.ui \
|
SearchReplaceDialog.ui \
|
||||||
SelectCellViewForm.ui \
|
SelectCellViewForm.ui \
|
||||||
SettingsForm.ui \
|
SettingsForm.ui \
|
||||||
TechBaseEditorPage.ui \
|
TechBaseEditorPage.ui \
|
||||||
TechComponentSetupDialog.ui \
|
TechComponentSetupDialog.ui \
|
||||||
TechLayerMappingEditorPage.ui \
|
TechLayerMappingEditorPage.ui \
|
||||||
TechMacrosPage.ui \
|
TechMacrosPage.ui \
|
||||||
TechSetupDialog.ui \
|
TechSetupDialog.ui \
|
||||||
XORToolDialog.ui \
|
XORToolDialog.ui \
|
||||||
TechLoadOptionsEditorPage.ui \
|
TechLoadOptionsEditorPage.ui \
|
||||||
TechSaveOptionsEditorPage.ui \
|
TechSaveOptionsEditorPage.ui \
|
||||||
MainConfigPage7.ui
|
MainConfigPage7.ui
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
gsiDeclLayApplication.cc \
|
gsiDeclLayApplication.cc \
|
||||||
gsiDeclLayHelpDialog.cc \
|
gsiDeclLayHelpDialog.cc \
|
||||||
gsiDeclLayMacro.cc \
|
gsiDeclLayMacro.cc \
|
||||||
gsiDeclLayMainWindow.cc \
|
gsiDeclLayMainWindow.cc \
|
||||||
layApplication.cc \
|
layApplication.cc \
|
||||||
layClipDialog.cc \
|
layClipDialog.cc \
|
||||||
layCrashMessage.cc \
|
layCrashMessage.cc \
|
||||||
layFillDialog.cc \
|
layFillDialog.cc \
|
||||||
layGenericSyntaxHighlighter.cc \
|
layGenericSyntaxHighlighter.cc \
|
||||||
layGSIHelpProvider.cc \
|
layGSIHelpProvider.cc \
|
||||||
layHelpDialog.cc \
|
layHelpDialog.cc \
|
||||||
layHelpProvider.cc \
|
layHelpProvider.cc \
|
||||||
layHelpSource.cc \
|
layHelpSource.cc \
|
||||||
layLayoutStatisticsForm.cc \
|
layLayoutStatisticsForm.cc \
|
||||||
layLogViewerDialog.cc \
|
layLogViewerDialog.cc \
|
||||||
layMacro.cc \
|
layMacro.cc \
|
||||||
layMacroEditorDialog.cc \
|
layMacroEditorDialog.cc \
|
||||||
layMacroEditorPage.cc \
|
layMacroEditorPage.cc \
|
||||||
layMacroEditorSetupDialog.cc \
|
layMacroEditorSetupDialog.cc \
|
||||||
layMacroEditorTree.cc \
|
layMacroEditorTree.cc \
|
||||||
layMacroInterpreter.cc \
|
layMacroInterpreter.cc \
|
||||||
layMacroPropertiesDialog.cc \
|
layMacroPropertiesDialog.cc \
|
||||||
layMacroVariableView.cc \
|
layMacroVariableView.cc \
|
||||||
layMainConfigPages.cc \
|
layMainConfigPages.cc \
|
||||||
layMainWindow.cc \
|
layMainWindow.cc \
|
||||||
layNavigator.cc \
|
layNavigator.cc \
|
||||||
layProgress.cc \
|
layProgress.cc \
|
||||||
layProgressWidget.cc \
|
layProgressWidget.cc \
|
||||||
layResourceHelpProvider.cc \
|
layResourceHelpProvider.cc \
|
||||||
layRuntimeErrorForm.cc \
|
layRuntimeErrorForm.cc \
|
||||||
laySearchReplaceConfigPage.cc \
|
laySearchReplaceConfigPage.cc \
|
||||||
laySearchReplaceDialog.cc \
|
laySearchReplaceDialog.cc \
|
||||||
laySearchReplacePlugin.cc \
|
laySearchReplacePlugin.cc \
|
||||||
laySearchReplacePropertiesWidgets.cc \
|
laySearchReplacePropertiesWidgets.cc \
|
||||||
laySelectCellViewForm.cc \
|
laySelectCellViewForm.cc \
|
||||||
laySession.cc \
|
laySession.cc \
|
||||||
laySettingsForm.cc \
|
laySettingsForm.cc \
|
||||||
layTechnologySelector.cc \
|
layTechnologySelector.cc \
|
||||||
layTechSetupDialog.cc \
|
layTechSetupDialog.cc \
|
||||||
layTextProgress.cc \
|
layTextProgress.cc \
|
||||||
layVersion.cc \
|
layVersion.cc \
|
||||||
|
layMacroController.cc
|
||||||
|
|
||||||
RESOURCES = layBuildInMacros.qrc \
|
RESOURCES = layBuildInMacros.qrc \
|
||||||
layHelpResources.qrc \
|
layHelpResources.qrc \
|
||||||
layLayoutStatistics.qrc \
|
layLayoutStatistics.qrc \
|
||||||
layMacroTemplates.qrc \
|
layMacroTemplates.qrc \
|
||||||
layResources.qrc \
|
layResources.qrc \
|
||||||
|
|
||||||
INCLUDEPATH += ../tl ../gsi ../db ../rdb ../laybasic ../ant ../img ../edt
|
INCLUDEPATH += ../tl ../gsi ../db ../rdb ../laybasic ../ant ../img ../edt
|
||||||
DEPENDPATH += ../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 "layProgress.h"
|
||||||
#include "layTextProgress.h"
|
#include "layTextProgress.h"
|
||||||
#include "layBackgroundAwareTreeStyle.h"
|
#include "layBackgroundAwareTreeStyle.h"
|
||||||
|
#include "layMacroController.h"
|
||||||
#include "gtf.h"
|
#include "gtf.h"
|
||||||
#include "gsiDecl.h"
|
#include "gsiDecl.h"
|
||||||
#include "gsiInterpreter.h"
|
#include "gsiInterpreter.h"
|
||||||
|
|
@ -500,6 +501,8 @@ Application::Application (int &argc, char **argv, bool non_ui_mode)
|
||||||
mp_qapp = this;
|
mp_qapp = this;
|
||||||
mp_qapp_gui = (non_ui_mode ? 0 : 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
|
// install a special style proxy to overcome the issue of black-on-black tree expanders
|
||||||
if (mp_qapp_gui) {
|
if (mp_qapp_gui) {
|
||||||
mp_qapp_gui->setStyle (new lay::BackgroundAwareTreeStyle (0));
|
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 ();
|
mp_plugin_root = new lay::PluginRoot ();
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize the plugins (this should be the last action in the constructor since the
|
// initialize the plugins for the first time
|
||||||
// main window should be functional now.
|
|
||||||
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
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);
|
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
|
||||||
pd->initialize (mp_mw);
|
pd->initialize (mp_plugin_root);
|
||||||
}
|
}
|
||||||
|
|
||||||
// establish the configuration
|
// establish the configuration
|
||||||
|
|
@ -1199,6 +1201,12 @@ Application::finish ()
|
||||||
void
|
void
|
||||||
Application::shutdown ()
|
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) {
|
if (mp_mw) {
|
||||||
delete mp_mw;
|
delete mp_mw;
|
||||||
mp_mw = 0;
|
mp_mw = 0;
|
||||||
|
|
@ -1357,9 +1365,10 @@ Application::run ()
|
||||||
macro->set_file_path (*m);
|
macro->set_file_path (*m);
|
||||||
if (macro->show_in_menu ()) {
|
if (macro->show_in_menu ()) {
|
||||||
// menu-based macros are just registered so they are shown in the menu
|
// menu-based macros are just registered so they are shown in the menu
|
||||||
if (mp_mw) {
|
lay::MacroController *mc = lay::MacroController::instance ();
|
||||||
tl::log << "Register macro '" << *m << "'";
|
if (mc) {
|
||||||
mp_mw->add_temp_macro (macro.release ());
|
tl::log << "Registering macro '" << *m << "'";
|
||||||
|
mc->add_temp_macro (macro.release ());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// other macros given with -rm are run
|
// other macros given with -rm are run
|
||||||
|
|
@ -1479,15 +1488,25 @@ Application::run ()
|
||||||
player.replay (m_gtf_replay_rate, m_gtf_replay_stop);
|
player.replay (m_gtf_replay_rate, m_gtf_replay_stop);
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the menus with the macro menu bindings as late as possible (now we
|
// Give the plugins a change to do some last-minute initialisation and checks
|
||||||
// can be sure that the menus are created propertly)
|
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||||
mp_mw->update_menu_with_macros ();
|
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
|
||||||
|
pd->initialized (mp_mw);
|
||||||
|
}
|
||||||
|
|
||||||
if (! m_no_gui && m_gtf_replay.empty () && ! mp_recorder) {
|
if (! m_no_gui && m_gtf_replay.empty () && ! mp_recorder) {
|
||||||
// Show initial tip window if required
|
// Show initial tip window if required
|
||||||
mp_mw->about_to_exec ();
|
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 ()) {
|
if (! m_run_macro.empty ()) {
|
||||||
|
|
@ -1586,7 +1605,7 @@ Application::process_events (QEventLoop::ProcessEventsFlags flags, bool silent)
|
||||||
if (mp_mw) {
|
if (mp_mw) {
|
||||||
|
|
||||||
if (silent) {
|
if (silent) {
|
||||||
tl::DeferredMethodScheduler::instance ()->enable (false);
|
mp_dm_scheduler->enable (false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if QT_VERSION < 0x050000
|
#if QT_VERSION < 0x050000
|
||||||
|
|
@ -1598,7 +1617,7 @@ Application::process_events (QEventLoop::ProcessEventsFlags flags, bool silent)
|
||||||
mp_mw->enter_busy_mode (false);
|
mp_mw->enter_busy_mode (false);
|
||||||
|
|
||||||
if (silent) {
|
if (silent) {
|
||||||
tl::DeferredMethodScheduler::instance ()->enable (true);
|
mp_dm_scheduler->enable (true);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@
|
||||||
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
namespace gsi
|
namespace gsi
|
||||||
{
|
{
|
||||||
|
|
@ -44,6 +45,11 @@ namespace gtf
|
||||||
class Recorder;
|
class Recorder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace tl
|
||||||
|
{
|
||||||
|
class DeferredMethodScheduler;
|
||||||
|
}
|
||||||
|
|
||||||
namespace lay
|
namespace lay
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
@ -339,6 +345,7 @@ private:
|
||||||
bool m_enable_undo;
|
bool m_enable_undo;
|
||||||
QCoreApplication *mp_qapp;
|
QCoreApplication *mp_qapp;
|
||||||
QApplication *mp_qapp_gui;
|
QApplication *mp_qapp_gui;
|
||||||
|
std::auto_ptr<tl::DeferredMethodScheduler> mp_dm_scheduler;
|
||||||
// HINT: the ruby interpreter must be destroyed before MainWindow
|
// 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.
|
// in order to maintain a valid MainWindow reference for ruby scripts and Ruby's GC all the time.
|
||||||
gsi::Interpreter *mp_ruby_interpreter;
|
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 "layQtTools.h"
|
||||||
#include "layConfig.h"
|
#include "layConfig.h"
|
||||||
#include "layWidgets.h"
|
#include "layWidgets.h"
|
||||||
|
#include "layProgress.h"
|
||||||
#include "tlString.h"
|
#include "tlString.h"
|
||||||
#include "tlClassRegistry.h"
|
#include "tlClassRegistry.h"
|
||||||
#include "tlExceptions.h"
|
#include "tlExceptions.h"
|
||||||
|
|
@ -253,6 +254,10 @@ MacroEditorDialog::MacroEditorDialog (QWidget * /*parent*/, lay::MacroCollection
|
||||||
m_add_edit_trace_enabled (true),
|
m_add_edit_trace_enabled (true),
|
||||||
dm_refresh_file_watcher (this, &MacroEditorDialog::do_refresh_file_watcher)
|
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);
|
Ui::MacroEditorDialog::setupUi (this);
|
||||||
|
|
||||||
connect (mp_root, SIGNAL (macro_changed (Macro *)), this, SLOT (macro_changed (Macro *)));
|
connect (mp_root, SIGNAL (macro_changed (Macro *)), this, SLOT (macro_changed (Macro *)));
|
||||||
|
|
|
||||||
|
|
@ -148,6 +148,12 @@ public:
|
||||||
void select_category (const std::string &cat);
|
void select_category (const std::string &cat);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
/**
|
||||||
|
* @brief Reloads all macros from the paths registered
|
||||||
|
*/
|
||||||
|
void refresh ();
|
||||||
|
|
||||||
|
private slots:
|
||||||
void help_button_clicked ();
|
void help_button_clicked ();
|
||||||
void add_button_clicked ();
|
void add_button_clicked ();
|
||||||
void close_button_clicked ();
|
void close_button_clicked ();
|
||||||
|
|
@ -166,7 +172,6 @@ public slots:
|
||||||
void properties_button_clicked ();
|
void properties_button_clicked ();
|
||||||
void setup_button_clicked ();
|
void setup_button_clicked ();
|
||||||
void breakpoint_button_clicked ();
|
void breakpoint_button_clicked ();
|
||||||
void refresh ();
|
|
||||||
void add_location ();
|
void add_location ();
|
||||||
void remove_location ();
|
void remove_location ();
|
||||||
void clear_breakpoints_button_clicked ();
|
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;
|
m_enable_event = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@
|
||||||
#include "tlAssert.h"
|
#include "tlAssert.h"
|
||||||
#include "tlDeferredExecution.h"
|
#include "tlDeferredExecution.h"
|
||||||
#include "tlStream.h"
|
#include "tlStream.h"
|
||||||
|
#include "tlExceptions.h"
|
||||||
#include "dbMemStatistics.h"
|
#include "dbMemStatistics.h"
|
||||||
#include "dbManager.h"
|
#include "dbManager.h"
|
||||||
#include "dbStream.h"
|
#include "dbStream.h"
|
||||||
|
|
@ -81,7 +82,6 @@
|
||||||
#include "layMainConfigPages.h"
|
#include "layMainConfigPages.h"
|
||||||
#include "layAbstractMenu.h"
|
#include "layAbstractMenu.h"
|
||||||
#include "layQtTools.h"
|
#include "layQtTools.h"
|
||||||
#include "tlExceptions.h"
|
|
||||||
#include "laySaveLayoutOptionsDialog.h"
|
#include "laySaveLayoutOptionsDialog.h"
|
||||||
#include "layLoadLayoutOptionsDialog.h"
|
#include "layLoadLayoutOptionsDialog.h"
|
||||||
#include "layLogViewerDialog.h"
|
#include "layLogViewerDialog.h"
|
||||||
|
|
@ -93,6 +93,7 @@
|
||||||
#include "laySelectCellViewForm.h"
|
#include "laySelectCellViewForm.h"
|
||||||
#include "layLayoutPropertiesForm.h"
|
#include "layLayoutPropertiesForm.h"
|
||||||
#include "layLayoutStatisticsForm.h"
|
#include "layLayoutStatisticsForm.h"
|
||||||
|
#include "layMacroController.h"
|
||||||
#include "ui_HelpAboutDialog.h"
|
#include "ui_HelpAboutDialog.h"
|
||||||
#include "gsi.h"
|
#include "gsi.h"
|
||||||
#include "gtf.h"
|
#include "gtf.h"
|
||||||
|
|
@ -410,7 +411,6 @@ MainWindow::MainWindow (QApplication *app, const char *name)
|
||||||
m_open_mode (0),
|
m_open_mode (0),
|
||||||
m_disable_tab_selected (false),
|
m_disable_tab_selected (false),
|
||||||
m_exited (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),
|
dm_do_update_menu (this, &MainWindow::do_update_menu),
|
||||||
m_grid_micron (0.001),
|
m_grid_micron (0.001),
|
||||||
m_default_grids_updated (true),
|
m_default_grids_updated (true),
|
||||||
|
|
@ -419,7 +419,6 @@ MainWindow::MainWindow (QApplication *app, const char *name)
|
||||||
m_synchronized_views (false),
|
m_synchronized_views (false),
|
||||||
m_synchronous (false),
|
m_synchronous (false),
|
||||||
m_busy (false),
|
m_busy (false),
|
||||||
m_work_in_progress (false),
|
|
||||||
mp_app (app)
|
mp_app (app)
|
||||||
{
|
{
|
||||||
setObjectName (QString::fromUtf8 (name));
|
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 &)));
|
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_assistant = new lay::HelpDialog (this);
|
||||||
|
|
||||||
mp_pr = new lay::ProgressReporter ();
|
mp_pr = new lay::ProgressReporter ();
|
||||||
|
|
@ -679,13 +668,6 @@ MainWindow::~MainWindow ()
|
||||||
{
|
{
|
||||||
lay::register_help_handler (0, 0);
|
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
|
// since the configuration actions unregister themselves, we need to do this before the main
|
||||||
// window is gone:
|
// window is gone:
|
||||||
m_ca_collection.clear ();
|
m_ca_collection.clear ();
|
||||||
|
|
@ -712,9 +694,6 @@ MainWindow::~MainWindow ()
|
||||||
delete mp_log_viewer_dialog;
|
delete mp_log_viewer_dialog;
|
||||||
mp_log_viewer_dialog = 0;
|
mp_log_viewer_dialog = 0;
|
||||||
|
|
||||||
delete mp_macro_editor;
|
|
||||||
mp_macro_editor = 0;
|
|
||||||
|
|
||||||
delete mp_assistant;
|
delete mp_assistant;
|
||||||
mp_assistant = 0;
|
mp_assistant = 0;
|
||||||
}
|
}
|
||||||
|
|
@ -1183,12 +1162,6 @@ MainWindow::close_all ()
|
||||||
void
|
void
|
||||||
MainWindow::about_to_exec ()
|
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;
|
bool f;
|
||||||
|
|
||||||
// TODO: later, each view may get it's own editable flag
|
// TODO: later, each view may get it's own editable flag
|
||||||
|
|
@ -1654,18 +1627,10 @@ void
|
||||||
MainWindow::apply_key_bindings ()
|
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) {
|
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)) {
|
if (menu ()->is_valid (kb->first)) {
|
||||||
|
|
||||||
lay::Action a = menu ()->action (kb->first);
|
lay::Action a = menu ()->action (kb->first);
|
||||||
a.set_shortcut (kb->second);
|
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 ()) {
|
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||||
return false;
|
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
|
||||||
|
if (! pd->can_exit (this)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string df_list;
|
std::string df_list;
|
||||||
|
|
@ -1901,6 +1869,8 @@ MainWindow::cm_view_log ()
|
||||||
void
|
void
|
||||||
MainWindow::cm_print ()
|
MainWindow::cm_print ()
|
||||||
{
|
{
|
||||||
|
// TODO: move to lay::LayoutView
|
||||||
|
|
||||||
BEGIN_PROTECTED
|
BEGIN_PROTECTED
|
||||||
|
|
||||||
// Late-initialize the printer to save time on startup
|
// Late-initialize the printer to save time on startup
|
||||||
|
|
@ -2295,116 +2265,6 @@ MainWindow::cm_redo ()
|
||||||
END_PROTECTED
|
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
|
void
|
||||||
MainWindow::bookmark_menu_show ()
|
MainWindow::bookmark_menu_show ()
|
||||||
{
|
{
|
||||||
|
|
@ -3475,6 +3335,8 @@ MainWindow::cm_adjust_origin ()
|
||||||
void
|
void
|
||||||
MainWindow::cm_new_cell ()
|
MainWindow::cm_new_cell ()
|
||||||
{
|
{
|
||||||
|
// TODO: move this function to lay::LayoutView
|
||||||
|
|
||||||
BEGIN_PROTECTED
|
BEGIN_PROTECTED
|
||||||
|
|
||||||
lay::LayoutView *curr = current_view ();
|
lay::LayoutView *curr = current_view ();
|
||||||
|
|
@ -4634,68 +4496,15 @@ MainWindow::show_progress_bar (bool show)
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (m_work_in_progress != show) {
|
mp_main_stack_widget->setCurrentIndex (show ? 1 : 0);
|
||||||
|
if (show) {
|
||||||
m_work_in_progress = show;
|
clear_current_pos ();
|
||||||
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 ();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
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
|
void
|
||||||
MainWindow::cm_technologies ()
|
MainWindow::cm_technologies ()
|
||||||
{
|
{
|
||||||
|
|
@ -4716,41 +4525,42 @@ MainWindow::cm_technologies ()
|
||||||
}
|
}
|
||||||
|
|
||||||
// because the macro-tech association might have changed, do this:
|
// 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
|
void
|
||||||
MainWindow::show_macro_editor (const std::string &cat, bool add)
|
MainWindow::show_macro_editor (const std::string &cat, bool add)
|
||||||
{
|
{
|
||||||
if (mp_macro_editor) {
|
lay::MacroController *mc = lay::MacroController::instance ();
|
||||||
mp_macro_editor->show (cat, add);
|
if (mc) {
|
||||||
|
mc->show_editor (cat, add);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MainWindow::cm_edit_drc_scripts ()
|
MainWindow::cm_edit_drc_scripts ()
|
||||||
{
|
{
|
||||||
|
// TODO: implement this as generic menu provided by the Interpreter
|
||||||
show_macro_editor ("drc", false);
|
show_macro_editor ("drc", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MainWindow::cm_new_drc_script ()
|
MainWindow::cm_new_drc_script ()
|
||||||
{
|
{
|
||||||
|
// TODO: implement this as generic menu provided by the Interpreter
|
||||||
show_macro_editor ("drc", true);
|
show_macro_editor ("drc", true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
MainWindow::cm_macro_editor ()
|
MainWindow::cm_macro_editor ()
|
||||||
{
|
{
|
||||||
|
// TODO: implement this as generic menu provided by the plugin declaration
|
||||||
show_macro_editor ();
|
show_macro_editor ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -5394,8 +5204,10 @@ MainWindow::dropEvent(QDropEvent *event)
|
||||||
QList<QUrl> urls = event->mimeData ()->urls ();
|
QList<QUrl> urls = event->mimeData ()->urls ();
|
||||||
for (QList<QUrl>::const_iterator url = urls.begin (); url != urls.end (); ++url) {
|
for (QList<QUrl>::const_iterator url = urls.begin (); url != urls.end (); ++url) {
|
||||||
|
|
||||||
|
QUrl eff_url (*url);
|
||||||
|
|
||||||
QString path;
|
QString path;
|
||||||
if (url->scheme () == QString::fromUtf8 ("file")) {
|
if (eff_url.scheme () == QString::fromUtf8 ("file")) {
|
||||||
path = url->toLocalFile ();
|
path = url->toLocalFile ();
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
|
|
@ -5452,101 +5264,38 @@ MainWindow::dropEvent(QDropEvent *event)
|
||||||
CFRelease( relCFURL );
|
CFRelease( relCFURL );
|
||||||
CFRelease( relCFStringRef );
|
CFRelease( relCFStringRef );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
eff_url = QUrl::fromLocalFile (path);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
} else if (url->scheme () == QString::fromUtf8 ("http") || url->scheme () == QString::fromUtf8 ("https")) {
|
} else if (eff_url.scheme () == QString::fromUtf8 ("http") || eff_url.scheme () == QString::fromUtf8 ("https")) {
|
||||||
path = url->toString ();
|
path = eff_url.toString ();
|
||||||
} else {
|
} else {
|
||||||
// other schemes are not supported currently.
|
// other schemes are not supported currently.
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
// Let the plugins decide if they accept the drop
|
||||||
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")) {
|
|
||||||
|
|
||||||
// load and run macro
|
for (tl::Registrar<lay::PluginDeclaration>::iterator cls = tl::Registrar<lay::PluginDeclaration>::begin (); cls != tl::Registrar<lay::PluginDeclaration>::end (); ++cls) {
|
||||||
std::auto_ptr<lay::Macro> macro (new lay::Macro ());
|
lay::PluginDeclaration *pd = const_cast<lay::PluginDeclaration *> (&*cls);
|
||||||
macro->load_from (tl::to_string (path));
|
if (pd->accepts_drop (tl::to_string (eff_url.toString ()))) {
|
||||||
macro->set_file_path (tl::to_string (path));
|
pd->drop_url (tl::to_string (eff_url.toString ()));
|
||||||
|
return;
|
||||||
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 ();
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} 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*/);
|
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);
|
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
|
* @brief Reimplementation of the plugin interface: handle a generic menu request
|
||||||
*/
|
*/
|
||||||
|
|
@ -829,11 +818,6 @@ public slots:
|
||||||
*/
|
*/
|
||||||
void show_help (const QString &url);
|
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
|
* @brief visibility of one of the dock widgets changed
|
||||||
*/
|
*/
|
||||||
|
|
@ -852,7 +836,6 @@ protected slots:
|
||||||
protected:
|
protected:
|
||||||
void update_content ();
|
void update_content ();
|
||||||
void do_update_menu ();
|
void do_update_menu ();
|
||||||
void do_update_menu_with_macros ();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TextProgressDelegate m_text_progress;
|
TextProgressDelegate m_text_progress;
|
||||||
|
|
@ -895,7 +878,6 @@ private:
|
||||||
QLabel *mp_tech_status_label;
|
QLabel *mp_tech_status_label;
|
||||||
bool m_disable_tab_selected;
|
bool m_disable_tab_selected;
|
||||||
bool m_exited;
|
bool m_exited;
|
||||||
tl::DeferredMethod<MainWindow> dm_do_update_menu_with_macros;
|
|
||||||
tl::DeferredMethod<MainWindow> dm_do_update_menu;
|
tl::DeferredMethod<MainWindow> dm_do_update_menu;
|
||||||
QTimer m_message_timer;
|
QTimer m_message_timer;
|
||||||
QTimer m_file_changed_timer;
|
QTimer m_file_changed_timer;
|
||||||
|
|
@ -914,16 +896,11 @@ private:
|
||||||
bool m_synchronized_views;
|
bool m_synchronized_views;
|
||||||
bool m_synchronous;
|
bool m_synchronous;
|
||||||
bool m_busy;
|
bool m_busy;
|
||||||
bool m_work_in_progress;
|
|
||||||
QApplication *mp_app;
|
QApplication *mp_app;
|
||||||
lay::MacroEditorDialog *mp_macro_editor;
|
|
||||||
lay::HelpDialog *mp_assistant;
|
lay::HelpDialog *mp_assistant;
|
||||||
std::string m_current_session;
|
std::string m_current_session;
|
||||||
std::string m_message;
|
std::string m_message;
|
||||||
std::auto_ptr<QPrinter> mp_printer;
|
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::vector<QString> m_changed_files;
|
||||||
|
|
||||||
std::map<std::string, lay::Action> m_actions_for_slot;
|
std::map<std::string, lay::Action> m_actions_for_slot;
|
||||||
|
|
@ -937,7 +914,6 @@ private:
|
||||||
|
|
||||||
void init_menu ();
|
void init_menu ();
|
||||||
|
|
||||||
bool eventFilter (QObject *watched, QEvent *event);
|
|
||||||
void closeEvent (QCloseEvent *event);
|
void closeEvent (QCloseEvent *event);
|
||||||
void resizeEvent (QResizeEvent *event);
|
void resizeEvent (QResizeEvent *event);
|
||||||
|
|
||||||
|
|
@ -963,8 +939,6 @@ private:
|
||||||
virtual void plugin_removed (lay::PluginDeclaration *cls);
|
virtual void plugin_removed (lay::PluginDeclaration *cls);
|
||||||
|
|
||||||
void libraries_changed ();
|
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 ();
|
void apply_key_bindings ();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,20 +23,40 @@
|
||||||
|
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
#include <QInputEvent>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include "layProgress.h"
|
#include "layProgress.h"
|
||||||
#include "layMainWindow.h"
|
#include "layMainWindow.h"
|
||||||
#include "layApplication.h"
|
#include "layProgressWidget.h"
|
||||||
#include "tlProgress.h"
|
#include "tlProgress.h"
|
||||||
|
#include "tlDeferredExecution.h"
|
||||||
|
|
||||||
namespace lay
|
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 ()
|
ProgressReporter::ProgressReporter ()
|
||||||
: m_start_time (), mp_pb (0), m_pw_visible (false)
|
: m_start_time (), mp_pb (0), m_pw_visible (false)
|
||||||
{
|
{
|
||||||
|
|
@ -55,11 +75,11 @@ ProgressReporter::set_progress_bar (lay::ProgressBar *pb)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (mp_pb) {
|
if (mp_pb) {
|
||||||
mp_pb->show_progress_bar (m_pw_visible);
|
set_visible (m_pw_visible);
|
||||||
}
|
}
|
||||||
mp_pb = pb;
|
mp_pb = pb;
|
||||||
if (mp_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
|
// make dialog visible after some time has passed
|
||||||
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
|
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
|
||||||
if (mp_pb) {
|
set_visible (true);
|
||||||
mp_pb->show_progress_bar (true);
|
|
||||||
}
|
|
||||||
m_pw_visible = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
update_and_yield ();
|
update_and_yield ();
|
||||||
|
|
@ -95,10 +112,9 @@ ProgressReporter::unregister_object (tl::Progress *progress)
|
||||||
|
|
||||||
// close or refresh window
|
// close or refresh window
|
||||||
if (mp_objects.empty ()) {
|
if (mp_objects.empty ()) {
|
||||||
if (mp_pb) {
|
if (m_pw_visible) {
|
||||||
mp_pb->show_progress_bar (false);
|
set_visible (false);
|
||||||
}
|
}
|
||||||
m_pw_visible = false;
|
|
||||||
m_start_time = tl::Clock ();
|
m_start_time = tl::Clock ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,10 +132,7 @@ ProgressReporter::trigger (tl::Progress *progress)
|
||||||
if (! mp_objects.empty () && mp_objects.front () == progress) {
|
if (! mp_objects.empty () && mp_objects.front () == progress) {
|
||||||
// make dialog visible after some time has passed
|
// make dialog visible after some time has passed
|
||||||
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
|
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
|
||||||
if (mp_pb) {
|
set_visible (true);
|
||||||
mp_pb->show_progress_bar (true);
|
|
||||||
}
|
|
||||||
m_pw_visible = true;
|
|
||||||
}
|
}
|
||||||
update_and_yield ();
|
update_and_yield ();
|
||||||
}
|
}
|
||||||
|
|
@ -130,10 +143,7 @@ ProgressReporter::yield (tl::Progress * /*progress*/)
|
||||||
{
|
{
|
||||||
// make dialog visible after some time has passed
|
// make dialog visible after some time has passed
|
||||||
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
|
if (! m_pw_visible && (tl::Clock::current () - m_start_time).seconds () > 1.0) {
|
||||||
if (mp_pb) {
|
set_visible (true);
|
||||||
mp_pb->show_progress_bar (true);
|
|
||||||
}
|
|
||||||
m_pw_visible = true;
|
|
||||||
update_and_yield ();
|
update_and_yield ();
|
||||||
} else if (m_pw_visible) {
|
} else if (m_pw_visible) {
|
||||||
// process events if necessary
|
// process events if necessary
|
||||||
|
|
@ -166,8 +176,67 @@ ProgressReporter::update_and_yield ()
|
||||||
void
|
void
|
||||||
ProgressReporter::process_events ()
|
ProgressReporter::process_events ()
|
||||||
{
|
{
|
||||||
if (m_pw_visible && lay::MainWindow::instance () && lay::Application::instance ()) {
|
if (m_pw_visible && lay::MainWindow::instance () && QApplication::instance ()) {
|
||||||
lay::Application::instance ()->process_events ();
|
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
|
class LAY_PUBLIC ProgressReporter
|
||||||
: public tl::ProgressAdaptor
|
: public QObject, public tl::ProgressAdaptor
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ProgressReporter ();
|
ProgressReporter ();
|
||||||
|
|
@ -64,6 +64,7 @@ public:
|
||||||
virtual void unregister_object (tl::Progress *progress);
|
virtual void unregister_object (tl::Progress *progress);
|
||||||
virtual void trigger (tl::Progress *progress);
|
virtual void trigger (tl::Progress *progress);
|
||||||
virtual void yield (tl::Progress *progress);
|
virtual void yield (tl::Progress *progress);
|
||||||
|
virtual bool eventFilter (QObject *dest, QEvent *event);
|
||||||
|
|
||||||
void signal_break ();
|
void signal_break ();
|
||||||
void set_progress_bar (lay::ProgressBar *pb);
|
void set_progress_bar (lay::ProgressBar *pb);
|
||||||
|
|
@ -76,8 +77,15 @@ private:
|
||||||
|
|
||||||
void process_events ();
|
void process_events ();
|
||||||
void update_and_yield ();
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,7 @@
|
||||||
#include "layPlugin.h"
|
#include "layPlugin.h"
|
||||||
#include "laybasicConfig.h"
|
#include "laybasicConfig.h"
|
||||||
#include "layMainWindow.h"
|
#include "layMainWindow.h"
|
||||||
|
#include "layMacroController.h"
|
||||||
#include "layTechnology.h"
|
#include "layTechnology.h"
|
||||||
#include "laybasicConfig.h"
|
#include "laybasicConfig.h"
|
||||||
#include "tlDeferredExecution.h"
|
#include "tlDeferredExecution.h"
|
||||||
|
|
@ -112,8 +113,12 @@ private:
|
||||||
lay::MainWindow *mw = lay::MainWindow::instance ();
|
lay::MainWindow *mw = lay::MainWindow::instance ();
|
||||||
if (mw) {
|
if (mw) {
|
||||||
mw->tech_message (tech_string_from_name (active_tech));
|
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
|
// 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 ();
|
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 *LayoutView::create_plugin (lay::PluginRoot *root, const lay::PluginDeclaration *cls)
|
||||||
{
|
{
|
||||||
lay::Plugin *p = cls->create_plugin (manager (), root, this);
|
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")));
|
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Save screenshot")));
|
||||||
|
|
||||||
// Execute all deferred methods - ensure there are no pending tasks
|
// Execute all deferred methods - ensure there are no pending tasks
|
||||||
tl::DeferredMethodScheduler::instance ()->execute ();
|
tl::DeferredMethodScheduler::execute ();
|
||||||
|
|
||||||
return mp_canvas->screenshot ();
|
return mp_canvas->screenshot ();
|
||||||
}
|
}
|
||||||
|
|
@ -2614,7 +2634,7 @@ LayoutView::save_screenshot (const std::string &fn)
|
||||||
writer.setText (QString::fromUtf8 ("Rect"), tl::to_qstring (desc));
|
writer.setText (QString::fromUtf8 ("Rect"), tl::to_qstring (desc));
|
||||||
|
|
||||||
// Execute all deferred methods - ensure there are no pending tasks
|
// Execute all deferred methods - ensure there are no pending tasks
|
||||||
tl::DeferredMethodScheduler::instance ()->execute ();
|
tl::DeferredMethodScheduler::execute ();
|
||||||
|
|
||||||
if (! writer.write (mp_canvas->screenshot ())) {
|
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 ()));
|
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")));
|
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Save image")));
|
||||||
|
|
||||||
// Execute all deferred methods - ensure there are no pending tasks
|
// Execute all deferred methods - ensure there are no pending tasks
|
||||||
tl::DeferredMethodScheduler::instance ()->execute ();
|
tl::DeferredMethodScheduler::execute ();
|
||||||
|
|
||||||
return mp_canvas->image (width, height);
|
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")));
|
tl::SelfTimer timer (tl::verbosity () >= 11, tl::to_string (QObject::tr ("Save image")));
|
||||||
|
|
||||||
// Execute all deferred methods - ensure there are no pending tasks
|
// 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);
|
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 ()));
|
writer.setText (QString::fromUtf8 ("Rect"), tl::to_qstring (vp.box ().to_string ()));
|
||||||
|
|
||||||
// Execute all deferred methods - ensure there are no pending tasks
|
// 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))) {
|
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 ()));
|
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 ()));
|
writer.setText (QString::fromUtf8 ("Rect"), tl::to_qstring (vp.box ().to_string ()));
|
||||||
|
|
||||||
// Execute all deferred methods - ensure there are no pending tasks
|
// 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))) {
|
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 ()));
|
throw tl::Exception (tl::to_string (QObject::tr ("Unable to write screenshot to file: %s (%s)")), fn, tl::to_string (writer.errorString ()));
|
||||||
|
|
|
||||||
|
|
@ -1878,6 +1878,16 @@ public:
|
||||||
return m_drawing_workers;
|
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
|
* @brief Localize a plugin by name
|
||||||
*
|
*
|
||||||
|
|
|
||||||
|
|
@ -264,6 +264,17 @@ public:
|
||||||
// .. the default implementation does nothing ..
|
// .. 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
|
* @brief Fetch the menu objects for this plugin
|
||||||
*
|
*
|
||||||
|
|
@ -369,6 +380,22 @@ public:
|
||||||
return m_editable_enabled;
|
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
|
* @brief Notifies that plugin root that a new plugin was registered
|
||||||
*
|
*
|
||||||
|
|
@ -661,6 +688,22 @@ public:
|
||||||
return 0;
|
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)
|
* @brief Associate a plugin with the plugin declaration for that service (getter)
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,8 @@ namespace tl
|
||||||
|
|
||||||
static DeferredMethodScheduler *s_inst = 0;
|
static DeferredMethodScheduler *s_inst = 0;
|
||||||
|
|
||||||
DeferredMethodScheduler::DeferredMethodScheduler (QObject *parent)
|
DeferredMethodScheduler::DeferredMethodScheduler ()
|
||||||
: QObject (parent),
|
: QObject (0),
|
||||||
m_disabled (0), m_scheduled (false)
|
m_disabled (0), m_scheduled (false)
|
||||||
{
|
{
|
||||||
connect (&m_timer, SIGNAL (timeout ()), this, SLOT (timer ()));
|
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 ()));
|
connect (&m_fallback_timer, SIGNAL (timeout ()), this, SLOT (timer ()));
|
||||||
m_fallback_timer.setInterval (500);
|
m_fallback_timer.setInterval (500);
|
||||||
m_fallback_timer.setSingleShot (false);
|
m_fallback_timer.setSingleShot (false);
|
||||||
|
|
||||||
|
tl_assert (! s_inst);
|
||||||
|
s_inst = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeferredMethodScheduler::~DeferredMethodScheduler ()
|
DeferredMethodScheduler::~DeferredMethodScheduler ()
|
||||||
|
|
@ -57,12 +60,8 @@ DeferredMethodScheduler::~DeferredMethodScheduler ()
|
||||||
DeferredMethodScheduler *
|
DeferredMethodScheduler *
|
||||||
DeferredMethodScheduler::instance ()
|
DeferredMethodScheduler::instance ()
|
||||||
{
|
{
|
||||||
static QMutex lock;
|
// NOTE: this is not locked intentionally. The instance is shut down once in the application shortly before it
|
||||||
lock.lock ();
|
// will terminate and it is created initially before any threads start.
|
||||||
if (s_inst == 0) {
|
|
||||||
s_inst = new DeferredMethodScheduler (qApp);
|
|
||||||
}
|
|
||||||
lock.unlock ();
|
|
||||||
return s_inst;
|
return s_inst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -98,7 +97,7 @@ DeferredMethodScheduler::unqueue (DeferredMethodBase *method)
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DeferredMethodScheduler::enable (bool en)
|
DeferredMethodScheduler::do_enable (bool en)
|
||||||
{
|
{
|
||||||
m_lock.lock ();
|
m_lock.lock ();
|
||||||
if (en) {
|
if (en) {
|
||||||
|
|
@ -129,7 +128,7 @@ DeferredMethodScheduler::timer ()
|
||||||
m_timer.start ();
|
m_timer.start ();
|
||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
execute ();
|
do_execute ();
|
||||||
} catch (tl::Exception &ex) {
|
} catch (tl::Exception &ex) {
|
||||||
tl::error << tl::to_string (QObject::tr ("Exception caught: ")) << ex.msg ();
|
tl::error << tl::to_string (QObject::tr ("Exception caught: ")) << ex.msg ();
|
||||||
} catch (std::exception &ex) {
|
} catch (std::exception &ex) {
|
||||||
|
|
@ -141,7 +140,7 @@ DeferredMethodScheduler::timer ()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
DeferredMethodScheduler::execute ()
|
DeferredMethodScheduler::do_execute ()
|
||||||
{
|
{
|
||||||
std::list<DeferredMethodBase *> methods;
|
std::list<DeferredMethodBase *> methods;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,16 @@ class TL_PUBLIC DeferredMethodScheduler
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* @brief Constructor
|
||||||
|
*/
|
||||||
|
DeferredMethodScheduler ();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Destructor
|
||||||
|
*/
|
||||||
|
~DeferredMethodScheduler ();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The singleton instance of the scheduler
|
* @brief The singleton instance of the scheduler
|
||||||
*/
|
*/
|
||||||
|
|
@ -96,14 +106,24 @@ public:
|
||||||
* Enabling is cumulative: multiple enable(true) calls must be matched to
|
* Enabling is cumulative: multiple enable(true) calls must be matched to
|
||||||
* the same number of enable(false) calls.
|
* 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
|
* @brief Execute all queued methods
|
||||||
*
|
*
|
||||||
* This method can be called to force execution of 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:
|
private slots:
|
||||||
void timer ();
|
void timer ();
|
||||||
|
|
@ -115,10 +135,9 @@ private:
|
||||||
QTimer m_timer, m_fallback_timer;
|
QTimer m_timer, m_fallback_timer;
|
||||||
QMutex m_lock;
|
QMutex m_lock;
|
||||||
|
|
||||||
DeferredMethodScheduler (QObject *parent);
|
|
||||||
~DeferredMethodScheduler ();
|
|
||||||
|
|
||||||
virtual bool event (QEvent *event);
|
virtual bool event (QEvent *event);
|
||||||
|
void do_enable (bool en);
|
||||||
|
void do_execute ();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -169,7 +188,9 @@ public:
|
||||||
*/
|
*/
|
||||||
~DeferredMethod ()
|
~DeferredMethod ()
|
||||||
{
|
{
|
||||||
DeferredMethodScheduler::instance ()->unqueue (this);
|
if (DeferredMethodScheduler::instance ()) {
|
||||||
|
DeferredMethodScheduler::instance ()->unqueue (this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -177,9 +198,13 @@ public:
|
||||||
*/
|
*/
|
||||||
void operator() ()
|
void operator() ()
|
||||||
{
|
{
|
||||||
// management of m_compressed and m_scheduled is done in the DeferredMethodScheduler -
|
if (DeferredMethodScheduler::instance ()) {
|
||||||
// there it is safely locked. Doing it there saves a private mutex for this object.
|
// management of m_compressed and m_scheduled is done in the DeferredMethodScheduler -
|
||||||
DeferredMethodScheduler::instance ()->schedule (this);
|
// 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 ()
|
void cancel ()
|
||||||
{
|
{
|
||||||
DeferredMethodScheduler::instance ()->unqueue (this);
|
if (DeferredMethodScheduler::instance ()) {
|
||||||
|
DeferredMethodScheduler::instance ()->unqueue (this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -196,7 +223,7 @@ public:
|
||||||
void execute ()
|
void execute ()
|
||||||
{
|
{
|
||||||
// cancel execution which might be pending
|
// cancel execution which might be pending
|
||||||
DeferredMethodScheduler::instance ()->unqueue (this);
|
cancel ();
|
||||||
(mp_t->*m_method) ();
|
(mp_t->*m_method) ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,7 @@
|
||||||
#include "tlString.h"
|
#include "tlString.h"
|
||||||
|
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
|
#include <QUrl>
|
||||||
|
|
||||||
namespace tl
|
namespace tl
|
||||||
{
|
{
|
||||||
|
|
@ -325,7 +326,8 @@ InputStream::InputStream (const std::string &abstract_path)
|
||||||
mp_delegate = new InputPipe (ex.get ());
|
mp_delegate = new InputPipe (ex.get ());
|
||||||
#endif
|
#endif
|
||||||
} else if (ex.test ("file:")) {
|
} 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 {
|
} else {
|
||||||
mp_delegate = new InputZLibFile (abstract_path);
|
mp_delegate = new InputZLibFile (abstract_path);
|
||||||
}
|
}
|
||||||
|
|
@ -345,7 +347,8 @@ std::string InputStream::absolute_path (const std::string &abstract_path)
|
||||||
return abstract_path;
|
return abstract_path;
|
||||||
#endif
|
#endif
|
||||||
} else if (ex.test ("file:")) {
|
} 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 {
|
} else {
|
||||||
return tl::to_string (QFileInfo (tl::to_qstring (abstract_path)).absoluteFilePath ());
|
return tl::to_string (QFileInfo (tl::to_qstring (abstract_path)).absoluteFilePath ());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@ public:
|
||||||
|
|
||||||
TEST(1)
|
TEST(1)
|
||||||
{
|
{
|
||||||
|
tl::DeferredMethodScheduler scheduler ();
|
||||||
|
|
||||||
g_na = g_nb = 0;
|
g_na = g_nb = 0;
|
||||||
|
|
||||||
QCoreApplication::instance ()->processEvents ();
|
QCoreApplication::instance ()->processEvents ();
|
||||||
|
|
@ -70,8 +72,8 @@ TEST(1)
|
||||||
EXPECT_EQ (g_na, 0);
|
EXPECT_EQ (g_na, 0);
|
||||||
EXPECT_EQ (g_nb, 0);
|
EXPECT_EQ (g_nb, 0);
|
||||||
|
|
||||||
tl::DeferredMethodScheduler::instance ()->enable (false);
|
tl::DeferredMethodScheduler::enable (false);
|
||||||
tl::DeferredMethodScheduler::instance ()->enable (false);
|
tl::DeferredMethodScheduler::enable (false);
|
||||||
|
|
||||||
QCoreApplication::instance ()->processEvents ();
|
QCoreApplication::instance ()->processEvents ();
|
||||||
|
|
||||||
|
|
@ -80,7 +82,7 @@ TEST(1)
|
||||||
EXPECT_EQ (g_na, 0);
|
EXPECT_EQ (g_na, 0);
|
||||||
EXPECT_EQ (g_nb, 0);
|
EXPECT_EQ (g_nb, 0);
|
||||||
|
|
||||||
tl::DeferredMethodScheduler::instance ()->enable (true);
|
tl::DeferredMethodScheduler::enable (true);
|
||||||
|
|
||||||
x->db ();
|
x->db ();
|
||||||
x->db ();
|
x->db ();
|
||||||
|
|
@ -92,7 +94,7 @@ TEST(1)
|
||||||
EXPECT_EQ (g_na, 0);
|
EXPECT_EQ (g_na, 0);
|
||||||
EXPECT_EQ (g_nb, 0);
|
EXPECT_EQ (g_nb, 0);
|
||||||
|
|
||||||
tl::DeferredMethodScheduler::instance ()->enable (true);
|
tl::DeferredMethodScheduler::enable (true);
|
||||||
|
|
||||||
QCoreApplication::instance ()->processEvents ();
|
QCoreApplication::instance ()->processEvents ();
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue