mirror of https://github.com/KLayout/klayout.git
Macro editor now acts on more file changes
- Adding/removing folders to packages now will make them appear/disappear automatically in the macro editor. - Adding and removing files from folders will make them appear/disappear in the macro tree.
This commit is contained in:
parent
b3abb276a4
commit
4460819a6c
|
|
@ -1173,7 +1173,7 @@ MacroCollection::make_readonly (bool f)
|
|||
}
|
||||
|
||||
MacroCollection *
|
||||
MacroCollection::add_folder (const std::string &description, const std::string &path, const std::string &cat, bool readonly)
|
||||
MacroCollection::add_folder (const std::string &description, const std::string &path, const std::string &cat, bool readonly, bool force_create)
|
||||
{
|
||||
if (! path.empty () && path[0] == ':') {
|
||||
readonly = true;
|
||||
|
|
@ -1183,15 +1183,25 @@ MacroCollection::add_folder (const std::string &description, const std::string &
|
|||
|
||||
if (! file_info.exists ()) {
|
||||
|
||||
// Try to create the folder since it does not exist yet
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Folder does not exist yet - trying to create it: " << path;
|
||||
}
|
||||
if (! QDir::root ().mkpath (file_info.absoluteFilePath ())) {
|
||||
if (tl::verbosity () >= 10) {
|
||||
tl::error << "Unable to create folder path: " << path;
|
||||
// Try to create the folder since it does not exist yet or skip that one
|
||||
if (! force_create) {
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Folder does not exist - skipping: " << path;
|
||||
}
|
||||
return 0;
|
||||
|
||||
} else {
|
||||
|
||||
if (tl::verbosity () >= 20) {
|
||||
tl::log << "Folder does not exist yet - trying to create it: " << path;
|
||||
}
|
||||
if (! QDir::root ().mkpath (file_info.absoluteFilePath ())) {
|
||||
if (tl::verbosity () >= 10) {
|
||||
tl::error << "Unable to create folder path: " << path;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
file_info.refresh ();
|
||||
|
|
@ -1666,6 +1676,91 @@ MacroCollection &MacroCollection::root ()
|
|||
return ms_root;
|
||||
}
|
||||
|
||||
static bool sync_macros (lay::MacroCollection *current, lay::MacroCollection *actual)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (actual) {
|
||||
current->make_readonly (actual->is_readonly ());
|
||||
}
|
||||
|
||||
std::vector<lay::MacroCollection *> folders_to_delete;
|
||||
|
||||
for (lay::MacroCollection::child_iterator m = current->begin_children (); m != current->end_children (); ++m) {
|
||||
lay::MacroCollection *cm = actual ? actual->folder_by_name (m->first) : 0;
|
||||
if (! cm) {
|
||||
folders_to_delete.push_back (m->second);
|
||||
}
|
||||
}
|
||||
|
||||
if (actual) {
|
||||
for (lay::MacroCollection::child_iterator m = actual->begin_children (); m != actual->end_children (); ++m) {
|
||||
lay::MacroCollection *cm = current->folder_by_name (m->first);
|
||||
if (! cm) {
|
||||
cm = current->create_folder (m->first.c_str (), false);
|
||||
ret = true;
|
||||
}
|
||||
if (sync_macros(cm, m->second)) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete folders which do no longer exist
|
||||
for (std::vector<lay::MacroCollection *>::iterator m = folders_to_delete.begin (); m != folders_to_delete.end (); ++m) {
|
||||
ret = true;
|
||||
sync_macros (*m, 0);
|
||||
current->erase (*m);
|
||||
}
|
||||
|
||||
std::vector<lay::Macro *> macros_to_delete;
|
||||
|
||||
for (lay::MacroCollection::iterator m = current->begin (); m != current->end (); ++m) {
|
||||
lay::Macro *cm = actual ? actual->macro_by_name (m->first, m->second->format ()) : 0;
|
||||
if (! cm) {
|
||||
macros_to_delete.push_back (m->second);
|
||||
}
|
||||
}
|
||||
|
||||
if (actual) {
|
||||
for (lay::MacroCollection::iterator m = actual->begin (); m != actual->end (); ++m) {
|
||||
lay::Macro *cm = current->macro_by_name (m->first, m->second->format ());
|
||||
if (cm) {
|
||||
if (*cm != *m->second) {
|
||||
cm->assign (*m->second);
|
||||
}
|
||||
cm->set_readonly (m->second->is_readonly ());
|
||||
} else {
|
||||
cm = current->create (m->first.c_str (), m->second->format ());
|
||||
cm->assign (*m->second);
|
||||
cm->set_readonly (m->second->is_readonly ());
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// erase macros from collection which are no longer used
|
||||
for (std::vector<lay::Macro *>::const_iterator m = macros_to_delete.begin (); m != macros_to_delete.end (); ++m) {
|
||||
current->erase (*m);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void MacroCollection::reload ()
|
||||
{
|
||||
// create a new collection and synchronize
|
||||
|
||||
lay::MacroCollection new_collection;
|
||||
for (lay::MacroCollection::child_iterator c = begin_children (); c != end_children (); ++c) {
|
||||
new_collection.add_folder (c->second->description (), c->second->path (), c->second->category (), c->second->is_readonly (), false /* don't force to create */);
|
||||
}
|
||||
|
||||
// and synchronize current with the actual one
|
||||
sync_macros (this, &new_collection);
|
||||
}
|
||||
|
||||
static bool has_autorun_for (const lay::MacroCollection &collection, bool early)
|
||||
{
|
||||
for (lay::MacroCollection::const_child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) {
|
||||
|
|
|
|||
|
|
@ -666,8 +666,11 @@ public:
|
|||
* @brief Add a folder (will also scan the folder)
|
||||
*
|
||||
* @return A pointer to the new collection if successful
|
||||
*
|
||||
* If force_create is true (the default), the folder will be created if it does not
|
||||
* exist yet. On error, 0 is returned.
|
||||
*/
|
||||
MacroCollection *add_folder (const std::string &description, const std::string &path, const std::string &category, bool readonly);
|
||||
MacroCollection *add_folder (const std::string &description, const std::string &path, const std::string &category, bool readonly, bool force_create = true);
|
||||
|
||||
/**
|
||||
* @brief Gets the category tag of the collection
|
||||
|
|
@ -998,6 +1001,13 @@ public:
|
|||
*/
|
||||
void rescan ();
|
||||
|
||||
/**
|
||||
* @brief Reloads the macro collection
|
||||
*
|
||||
* This method is similar to rescan, but it will also remove folders and macros.
|
||||
*/
|
||||
void reload ();
|
||||
|
||||
/**
|
||||
* @brief Gets the root of the macro hierarchy corresponding to the configuration space
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -38,11 +38,13 @@ namespace lay
|
|||
{
|
||||
|
||||
MacroController::MacroController ()
|
||||
: mp_macro_editor (0), mp_mw (0), m_no_implicit_macros (false),
|
||||
dm_do_update_menu_with_macros (this, &MacroController::do_update_menu_with_macros)
|
||||
: mp_macro_editor (0), mp_mw (0), m_no_implicit_macros (false), m_file_watcher (0),
|
||||
dm_do_update_menu_with_macros (this, &MacroController::do_update_menu_with_macros),
|
||||
dm_sync_file_watcher (this, &MacroController::sync_file_watcher),
|
||||
dm_sync_files (this, &MacroController::sync_files)
|
||||
{
|
||||
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 ()));
|
||||
connect (&m_temp_macros, SIGNAL (menu_needs_update ()), this, SLOT (macro_collection_changed ()));
|
||||
connect (&m_temp_macros, SIGNAL (macro_collection_changed (MacroCollection *)), this, SLOT (macro_collection_changed ()));
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -70,8 +72,6 @@ MacroController::load ()
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
sync_implicit_macros (false);
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -83,32 +83,48 @@ MacroController::initialized (lay::PluginRoot *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 ()));
|
||||
if (! m_file_watcher) {
|
||||
m_file_watcher = new tl::FileSystemWatcher (this);
|
||||
connect (m_file_watcher, SIGNAL (fileChanged (const QString &)), this, SLOT (file_watcher_triggered ()));
|
||||
connect (m_file_watcher, SIGNAL (fileRemoved (const QString &)), this, SLOT (file_watcher_triggered ()));
|
||||
}
|
||||
|
||||
connect (&lay::MacroCollection::root (), SIGNAL (menu_needs_update ()), this, SLOT (macro_collection_changed ()));
|
||||
connect (&lay::MacroCollection::root (), SIGNAL (macro_collection_changed (MacroCollection *)), this, SLOT (macro_collection_changed ()));
|
||||
if (lay::TechnologyController::instance ()) {
|
||||
connect (lay::TechnologyController::instance (), SIGNAL (active_technology_changed ()), this, SLOT (update_menu_with_macros ()));
|
||||
connect (lay::TechnologyController::instance (), SIGNAL (technologies_edited ()), this, SLOT (technologies_edited ()));
|
||||
connect (lay::TechnologyController::instance (), SIGNAL (active_technology_changed ()), this, SLOT (macro_collection_changed ()));
|
||||
connect (lay::TechnologyController::instance (), SIGNAL (technologies_edited ()), this, SLOT (sync_with_external_sources ()));
|
||||
}
|
||||
if (lay::SaltController::instance ()) {
|
||||
connect (lay::SaltController::instance (), SIGNAL (salt_changed ()), this, SLOT (salt_changed ()));
|
||||
connect (lay::SaltController::instance (), SIGNAL (salt_changed ()), this, SLOT (sync_with_external_sources ()));
|
||||
}
|
||||
|
||||
// synchronize the macro collection with all external sources
|
||||
sync_implicit_macros (false);
|
||||
|
||||
// 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 ();
|
||||
macro_collection_changed ();
|
||||
}
|
||||
|
||||
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 ()));
|
||||
disconnect (&lay::MacroCollection::root (), SIGNAL (menu_needs_update ()), this, SLOT (macro_collection_changed ()));
|
||||
disconnect (&lay::MacroCollection::root (), SIGNAL (macro_collection_changed (MacroCollection *)), this, SLOT (macro_collection_changed ()));
|
||||
if (lay::TechnologyController::instance ()) {
|
||||
disconnect (lay::TechnologyController::instance (), SIGNAL (active_technology_changed ()), this, SLOT (update_menu_with_macros ()));
|
||||
disconnect (lay::TechnologyController::instance (), SIGNAL (technologies_edited ()), this, SLOT (technologies_edited ()));
|
||||
disconnect (lay::TechnologyController::instance (), SIGNAL (active_technology_changed ()), this, SLOT (macro_collection_changed ()));
|
||||
disconnect (lay::TechnologyController::instance (), SIGNAL (technologies_edited ()), this, SLOT (sync_with_external_sources ()));
|
||||
}
|
||||
if (lay::SaltController::instance ()) {
|
||||
disconnect (lay::SaltController::instance (), SIGNAL (salt_changed ()), this, SLOT (salt_changed ()));
|
||||
disconnect (lay::SaltController::instance (), SIGNAL (salt_changed ()), this, SLOT (sync_with_external_sources ()));
|
||||
}
|
||||
|
||||
if (m_file_watcher) {
|
||||
disconnect (m_file_watcher, SIGNAL (fileChanged (const QString &)), this, SLOT (file_watcher_triggered ()));
|
||||
disconnect (m_file_watcher, SIGNAL (fileRemoved (const QString &)), this, SLOT (file_watcher_triggered ()));
|
||||
delete m_file_watcher;
|
||||
m_file_watcher = 0;
|
||||
}
|
||||
|
||||
delete mp_macro_editor;
|
||||
|
|
@ -238,9 +254,6 @@ MacroController::drop_url (const std::string &path_or_url)
|
|||
|
||||
macro->save ();
|
||||
|
||||
// refresh macro editor to show new macro plus to install the menus
|
||||
refresh ();
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
|
@ -350,10 +363,16 @@ MacroController::sync_implicit_macros (bool check_autorun)
|
|||
|
||||
std::vector<lay::MacroCollection *> folders_to_delete;
|
||||
|
||||
// determine the paths that will be in use
|
||||
std::map<std::string, const ExternalPathDescriptor *> new_folders_by_path;
|
||||
for (std::vector<ExternalPathDescriptor>::const_iterator p = external_paths.begin (); p != external_paths.end (); ++p) {
|
||||
new_folders_by_path.insert (std::make_pair (p->path, p.operator-> ()));
|
||||
}
|
||||
|
||||
// determine the paths currently in use
|
||||
std::map<std::string, const ExternalPathDescriptor *> used_folders_by_path;
|
||||
std::map<std::string, const ExternalPathDescriptor *> prev_folders_by_path;
|
||||
for (std::vector<ExternalPathDescriptor>::const_iterator p = m_external_paths.begin (); p != m_external_paths.end (); ++p) {
|
||||
used_folders_by_path.insert (std::make_pair (p->path, p.operator-> ()));
|
||||
prev_folders_by_path.insert (std::make_pair (p->path, p.operator-> ()));
|
||||
}
|
||||
|
||||
lay::MacroCollection *root = &lay::MacroCollection::root ();
|
||||
|
|
@ -361,8 +380,8 @@ MacroController::sync_implicit_macros (bool check_autorun)
|
|||
for (lay::MacroCollection::child_iterator m = root->begin_children (); m != root->end_children (); ++m) {
|
||||
if (m->second->virtual_mode () == lay::MacroCollection::TechFolder ||
|
||||
m->second->virtual_mode () == lay::MacroCollection::SaltFolder) {
|
||||
std::map<std::string, const ExternalPathDescriptor *>::const_iterator u = used_folders_by_path.find (m->second->path ());
|
||||
if (u == used_folders_by_path.end ()) {
|
||||
std::map<std::string, const ExternalPathDescriptor *>::const_iterator u = new_folders_by_path.find (m->second->path ());
|
||||
if (u == new_folders_by_path.end ()) {
|
||||
// no longer used
|
||||
folders_to_delete.push_back (m->second);
|
||||
} else {
|
||||
|
|
@ -387,7 +406,7 @@ MacroController::sync_implicit_macros (bool check_autorun)
|
|||
|
||||
for (std::vector<ExternalPathDescriptor>::const_iterator p = m_external_paths.begin (); p != m_external_paths.end (); ++p) {
|
||||
|
||||
if (used_folders_by_path.find (p->path) != used_folders_by_path.end ()) {
|
||||
if (prev_folders_by_path.find (p->path) != prev_folders_by_path.end ()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -424,14 +443,6 @@ MacroController::sync_implicit_macros (bool check_autorun)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::refresh ()
|
||||
{
|
||||
if (mp_macro_editor) {
|
||||
mp_macro_editor->refresh ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::add_path (const std::string &path, const std::string &description, const std::string &category, bool readonly)
|
||||
{
|
||||
|
|
@ -530,27 +541,22 @@ MacroController::add_macro_items_to_menu (lay::MacroCollection &collection, int
|
|||
}
|
||||
|
||||
void
|
||||
MacroController::salt_changed ()
|
||||
MacroController::sync_with_external_sources ()
|
||||
{
|
||||
sync_implicit_macros (true);
|
||||
refresh ();
|
||||
update_menu_with_macros ();
|
||||
try {
|
||||
sync_implicit_macros (true);
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << ex.msg ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::technologies_edited ()
|
||||
{
|
||||
sync_implicit_macros (true);
|
||||
refresh ();
|
||||
update_menu_with_macros ();
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::update_menu_with_macros ()
|
||||
MacroController::macro_collection_changed ()
|
||||
{
|
||||
// empty action to macro table now we know it's invalid
|
||||
m_action_to_macro.clear ();
|
||||
dm_do_update_menu_with_macros ();
|
||||
dm_sync_file_watcher ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -597,6 +603,39 @@ MacroController::do_update_menu_with_macros ()
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::file_watcher_triggered ()
|
||||
{
|
||||
dm_sync_files ();
|
||||
}
|
||||
|
||||
static void
|
||||
add_collections_to_file_watcher (const lay::MacroCollection &collection, tl::FileSystemWatcher *watcher)
|
||||
{
|
||||
for (lay::MacroCollection::const_child_iterator c = collection.begin_children (); c != collection.end_children (); ++c) {
|
||||
if (! c->second->path ().empty () && c->second->path ()[0] != ':') {
|
||||
watcher->add_file (c->second->path ());
|
||||
add_collections_to_file_watcher (*c->second, watcher);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::sync_file_watcher ()
|
||||
{
|
||||
m_file_watcher->clear ();
|
||||
m_file_watcher->enable (false);
|
||||
add_collections_to_file_watcher (lay::MacroCollection::root (), m_file_watcher);
|
||||
m_file_watcher->enable (true);
|
||||
}
|
||||
|
||||
void
|
||||
MacroController::sync_files ()
|
||||
{
|
||||
tl::log << tl::to_string (tr ("Detected file system change in macro folders - updating"));
|
||||
lay::MacroCollection::root ().reload ();
|
||||
}
|
||||
|
||||
MacroController *
|
||||
MacroController::instance ()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
#include "layMacro.h"
|
||||
#include "tlObject.h"
|
||||
#include "tlDeferredExecution.h"
|
||||
#include "tlFileSystemWatcher.h"
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
|
@ -120,11 +121,6 @@ public:
|
|||
*/
|
||||
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 search path to the macros
|
||||
* After adding the paths, "load" needs to be called to actually load the macros.
|
||||
|
|
@ -163,19 +159,20 @@ public:
|
|||
|
||||
public slots:
|
||||
/**
|
||||
* @brief Update the menu with macros bound to a menu
|
||||
* @brief Updates the menu with macros bound to a menu
|
||||
*/
|
||||
void update_menu_with_macros ();
|
||||
void macro_collection_changed ();
|
||||
|
||||
/**
|
||||
* @brief Called when the technologies got changed
|
||||
* @brief Called when the technologies or the salt got changed
|
||||
*/
|
||||
void technologies_edited ();
|
||||
void sync_with_external_sources ();
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Called when the salt (packages) got changed
|
||||
* @brief Called when the file watcher detects a change in the file system
|
||||
*/
|
||||
void salt_changed ();
|
||||
void file_watcher_triggered ();
|
||||
|
||||
private:
|
||||
/**
|
||||
|
|
@ -215,17 +212,22 @@ private:
|
|||
lay::MacroEditorDialog *mp_macro_editor;
|
||||
lay::MainWindow *mp_mw;
|
||||
bool m_no_implicit_macros;
|
||||
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;
|
||||
std::vector< std::pair<std::string, std::string> > m_macro_categories;
|
||||
std::vector<InternalPathDescriptor> m_internal_paths;
|
||||
std::vector<ExternalPathDescriptor> m_external_paths;
|
||||
tl::FileSystemWatcher *m_file_watcher;
|
||||
tl::DeferredMethod<MacroController> dm_do_update_menu_with_macros;
|
||||
tl::DeferredMethod<MacroController> dm_sync_file_watcher;
|
||||
tl::DeferredMethod<MacroController> dm_sync_files;
|
||||
|
||||
void sync_implicit_macros (bool check_autorun);
|
||||
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 ();
|
||||
void sync_file_watcher ();
|
||||
void sync_files ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -253,7 +253,8 @@ MacroEditorDialog::MacroEditorDialog (QWidget * /*parent*/, lay::MacroCollection
|
|||
m_font_size (0),
|
||||
m_edit_trace_index (-1),
|
||||
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),
|
||||
dm_update_ui_to_run_mode (this, &MacroEditorDialog::do_update_ui_to_run_mode)
|
||||
{
|
||||
// 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.
|
||||
|
|
@ -264,6 +265,7 @@ MacroEditorDialog::MacroEditorDialog (QWidget * /*parent*/, lay::MacroCollection
|
|||
connect (mp_root, SIGNAL (macro_changed (Macro *)), this, SLOT (macro_changed (Macro *)));
|
||||
connect (mp_root, SIGNAL (macro_deleted (Macro *)), this, SLOT (macro_deleted (Macro *)));
|
||||
connect (mp_root, SIGNAL (macro_collection_deleted (MacroCollection *)), this, SLOT (macro_collection_deleted (MacroCollection *)));
|
||||
connect (mp_root, SIGNAL (macro_collection_changed (MacroCollection *)), this, SLOT (macro_collection_changed (MacroCollection *)));
|
||||
|
||||
m_categories = lay::MacroController::instance ()->macro_categories ();
|
||||
|
||||
|
|
@ -391,7 +393,6 @@ MacroEditorDialog::MacroEditorDialog (QWidget * /*parent*/, lay::MacroCollection
|
|||
watchList->addAction (actionDeleteWatches);
|
||||
watchList->addAction (actionClearWatches);
|
||||
|
||||
connect (actionAddWatch, SIGNAL (triggered ()), this, SLOT (add_watch ()));
|
||||
connect (actionAddWatch, SIGNAL (triggered ()), this, SLOT (add_watch ()));
|
||||
connect (actionEditWatch, SIGNAL (triggered ()), this, SLOT (edit_watch ()));
|
||||
connect (actionDeleteWatches, SIGNAL (triggered ()), this, SLOT (del_watches ()));
|
||||
|
|
@ -1025,7 +1026,7 @@ MacroEditorDialog::add_edit_trace (bool compress)
|
|||
}
|
||||
|
||||
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
|
||||
if (! page) {
|
||||
if (! page || ! page->macro ()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -1551,17 +1552,16 @@ MacroEditorDialog::macro_collection_deleted (lay::MacroCollection *collection)
|
|||
|
||||
std::map <Macro *, MacroEditorPage *>::iterator p = m_tab_widgets.find (*mc);
|
||||
if (p != m_tab_widgets.end ()) {
|
||||
// disable the macro on the page - we'll ask for updates when the file
|
||||
// watcher becomes active. So long, the macro is "zombie".
|
||||
p->second->connect_macro (0);
|
||||
tabWidget->blockSignals (true); // blockSignals prevents a reentrant call into set_current of the tree
|
||||
tabWidget->removeTab (tabWidget->indexOf (p->second));
|
||||
tabWidget->blockSignals (false);
|
||||
delete p->second;
|
||||
m_tab_widgets.erase (p);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
refresh_file_watcher ();
|
||||
update_ui_to_run_mode ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1573,15 +1573,20 @@ MacroEditorDialog::macro_deleted (lay::Macro *macro)
|
|||
|
||||
std::map <Macro *, MacroEditorPage *>::iterator page = m_tab_widgets.find (macro);
|
||||
if (page != m_tab_widgets.end ()) {
|
||||
// disable the macro on the page - we'll ask for updates when the file
|
||||
// watcher becomes active. So long, the macro is "zombie".
|
||||
page->second->connect_macro (0);
|
||||
tabWidget->blockSignals (true); // blockSignals prevents a reentrant call into set_current of the tree
|
||||
tabWidget->removeTab (tabWidget->indexOf (page->second));
|
||||
tabWidget->blockSignals (false);
|
||||
delete page->second;
|
||||
m_tab_widgets.erase (page);
|
||||
}
|
||||
|
||||
refresh_file_watcher ();
|
||||
update_ui_to_run_mode ();
|
||||
}
|
||||
|
||||
void
|
||||
MacroEditorDialog::macro_collection_changed (lay::MacroCollection * /*collection*/)
|
||||
{
|
||||
refresh_file_watcher ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -1624,7 +1629,7 @@ MacroEditorDialog::current_tab_changed (int index)
|
|||
update_ui_to_run_mode ();
|
||||
}
|
||||
|
||||
lay::Macro *MacroEditorDialog::create_macro_here(const char *prefix)
|
||||
lay::Macro *MacroEditorDialog::create_macro_here (const char *prefix)
|
||||
{
|
||||
lay::MacroEditorTree *mt = current_macro_tree ();
|
||||
MacroCollection *collection = mt->current_macro_collection ();
|
||||
|
|
@ -1954,11 +1959,14 @@ MacroEditorDialog::setup_button_clicked ()
|
|||
|
||||
m_save_all_on_run = data.save_all_on_run;
|
||||
|
||||
for (std::map<Macro *, MacroEditorPage *>::const_iterator f = m_tab_widgets.begin (); f != m_tab_widgets.end (); ++f) {
|
||||
f->second->set_ntab (m_ntab);
|
||||
f->second->set_nindent (m_nindent);
|
||||
f->second->apply_attributes ();
|
||||
f->second->set_font (m_font_family, m_font_size);
|
||||
for (int i = 0; i < tabWidget->count (); ++i) {
|
||||
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->widget (i));
|
||||
if (page) {
|
||||
page->set_ntab (m_ntab);
|
||||
page->set_nindent (m_nindent);
|
||||
page->apply_attributes ();
|
||||
page->set_font (m_font_family, m_font_size);
|
||||
}
|
||||
}
|
||||
|
||||
// write configuration
|
||||
|
|
@ -2090,14 +2098,16 @@ BEGIN_PROTECTED
|
|||
}
|
||||
|
||||
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->widget (index));
|
||||
if (! page || ! page->macro ()) {
|
||||
if (! page) {
|
||||
delete tabWidget->currentWidget ();
|
||||
return;
|
||||
}
|
||||
|
||||
std::map <Macro *, MacroEditorPage *>::iterator p = m_tab_widgets.find (page->macro ());
|
||||
if (p != m_tab_widgets.end ()) {
|
||||
m_tab_widgets.erase (p);
|
||||
for (std::map <Macro *, MacroEditorPage *>::iterator p = m_tab_widgets.begin (); p != m_tab_widgets.end (); ++p) {
|
||||
if (p->second == page) {
|
||||
m_tab_widgets.erase (p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
page->connect_macro (0);
|
||||
|
|
@ -2374,7 +2384,7 @@ MacroEditorDialog::file_changed (const QString &path)
|
|||
{
|
||||
m_changed_files.push_back (path);
|
||||
|
||||
// Wait a little to let more to allow for more reload requests to collect
|
||||
// Wait a little to allow for more reload requests to collect
|
||||
m_file_changed_timer->setInterval (300);
|
||||
m_file_changed_timer->start ();
|
||||
}
|
||||
|
|
@ -2419,79 +2429,6 @@ MacroEditorDialog::sync_file_watcher (lay::MacroCollection * /*collection*/)
|
|||
#endif
|
||||
}
|
||||
|
||||
bool
|
||||
MacroEditorDialog::sync_macros (lay::MacroCollection *current, lay::MacroCollection *actual)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
if (actual) {
|
||||
current->make_readonly (actual->is_readonly ());
|
||||
}
|
||||
|
||||
std::vector<lay::MacroCollection *> folders_to_delete;
|
||||
|
||||
for (lay::MacroCollection::child_iterator m = current->begin_children (); m != current->end_children (); ++m) {
|
||||
lay::MacroCollection *cm = actual ? actual->folder_by_name (m->first) : 0;
|
||||
if (! cm) {
|
||||
folders_to_delete.push_back (m->second);
|
||||
}
|
||||
}
|
||||
|
||||
if (actual) {
|
||||
for (lay::MacroCollection::child_iterator m = actual->begin_children (); m != actual->end_children (); ++m) {
|
||||
lay::MacroCollection *cm = current->folder_by_name (m->first);
|
||||
if (! cm) {
|
||||
cm = current->create_folder (m->first.c_str (), false);
|
||||
ret = true;
|
||||
}
|
||||
if (sync_macros(cm, m->second)) {
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delete folders which do no longer exist
|
||||
for (std::vector<lay::MacroCollection *>::iterator m = folders_to_delete.begin (); m != folders_to_delete.end (); ++m) {
|
||||
ret = true;
|
||||
sync_macros (*m, 0);
|
||||
current->erase (*m);
|
||||
}
|
||||
|
||||
std::vector<lay::Macro *> macros_to_delete;
|
||||
|
||||
for (lay::MacroCollection::iterator m = current->begin (); m != current->end (); ++m) {
|
||||
lay::Macro *cm = actual ? actual->macro_by_name (m->first, m->second->format ()) : 0;
|
||||
if (! cm) {
|
||||
macros_to_delete.push_back (m->second);
|
||||
}
|
||||
}
|
||||
|
||||
if (actual) {
|
||||
for (lay::MacroCollection::iterator m = actual->begin (); m != actual->end (); ++m) {
|
||||
lay::Macro *cm = current->macro_by_name (m->first, m->second->format ());
|
||||
if (cm) {
|
||||
if (*cm != *m->second) {
|
||||
cm->assign (*m->second);
|
||||
}
|
||||
cm->set_readonly (m->second->is_readonly ());
|
||||
} else {
|
||||
cm = current->create (m->first.c_str (), m->second->format ());
|
||||
cm->assign (*m->second);
|
||||
cm->set_readonly (m->second->is_readonly ());
|
||||
ret = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// erase macros from collection which are no longer used
|
||||
for (std::vector<lay::Macro *>::const_iterator m = macros_to_delete.begin (); m != macros_to_delete.end (); ++m) {
|
||||
current->erase (*m);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
MacroEditorDialog::refresh_file_watcher ()
|
||||
{
|
||||
|
|
@ -2519,18 +2456,13 @@ void
|
|||
MacroEditorDialog::reload_macros ()
|
||||
{
|
||||
m_file_watcher->clear ();
|
||||
|
||||
lay::MacroCollection new_root;
|
||||
|
||||
// create a new root
|
||||
for (lay::MacroCollection::child_iterator c = mp_root->begin_children (); c != mp_root->end_children (); ++c) {
|
||||
new_root.add_folder (c->second->description (), c->second->path (), c->second->category (), c->second->is_readonly ());
|
||||
try {
|
||||
mp_root->reload ();
|
||||
refresh_file_watcher ();
|
||||
} catch (...) {
|
||||
refresh_file_watcher ();
|
||||
throw;
|
||||
}
|
||||
|
||||
// and synchronize current with the actual one
|
||||
sync_macros (mp_root, &new_root);
|
||||
|
||||
refresh_file_watcher ();
|
||||
}
|
||||
|
||||
void
|
||||
|
|
@ -3058,18 +2990,26 @@ MacroEditorDialog::leave_breakpoint_mode ()
|
|||
|
||||
void
|
||||
MacroEditorDialog::update_ui_to_run_mode ()
|
||||
{
|
||||
dm_update_ui_to_run_mode ();
|
||||
}
|
||||
|
||||
void
|
||||
MacroEditorDialog::do_update_ui_to_run_mode ()
|
||||
{
|
||||
double alpha = 0.95;
|
||||
|
||||
MacroEditorPage *page = dynamic_cast<MacroEditorPage *> (tabWidget->currentWidget ());
|
||||
|
||||
dbgOn->setEnabled (! m_in_exec);
|
||||
runButton->setEnabled ((! m_in_exec && (mp_run_macro || (page && page->macro ()->interpreter () != lay::Macro::None))) || m_in_breakpoint);
|
||||
runThisButton->setEnabled ((! m_in_exec && page && page->macro ()->interpreter () != lay::Macro::None) || m_in_breakpoint);
|
||||
runButton->setEnabled ((! m_in_exec && (mp_run_macro || (page && page->macro () && page->macro ()->interpreter () != lay::Macro::None))) || m_in_breakpoint);
|
||||
runThisButton->setEnabled ((! m_in_exec && page && page->macro () && page->macro ()->interpreter () != lay::Macro::None) || m_in_breakpoint);
|
||||
singleStepButton->setEnabled (! m_in_exec || m_in_breakpoint);
|
||||
nextStepButton->setEnabled (! m_in_exec || m_in_breakpoint);
|
||||
stopButton->setEnabled (m_in_exec);
|
||||
pauseButton->setEnabled (m_in_exec && ! m_in_breakpoint);
|
||||
breakpointButton->setEnabled (page && page->macro ());
|
||||
clearBreakpointsButton->setEnabled (page && page->macro ());
|
||||
|
||||
for (std::vector<lay::MacroEditorTree *>::const_iterator mt = m_macro_trees.begin (); mt != m_macro_trees.end (); ++mt) {
|
||||
(*mt)->setEditTriggers (m_in_exec ? QAbstractItemView::NoEditTriggers : QAbstractItemView::SelectedClicked);
|
||||
|
|
|
|||
|
|
@ -193,6 +193,7 @@ private slots:
|
|||
void macro_changed (Macro *macro);
|
||||
void macro_deleted (Macro *macro);
|
||||
void macro_collection_deleted (MacroCollection *collection);
|
||||
void macro_collection_changed (MacroCollection *collection);
|
||||
void add_watch ();
|
||||
void edit_watch ();
|
||||
void del_watches ();
|
||||
|
|
@ -249,10 +250,10 @@ private:
|
|||
void run (int stop_stack_depth, lay::Macro *macro);
|
||||
lay::Macro *current_run_macro ();
|
||||
void update_ui_to_run_mode ();
|
||||
void do_update_ui_to_run_mode ();
|
||||
void set_run_macro (lay::Macro *m);
|
||||
void apply_search (bool if_needed);
|
||||
void process_events (QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents);
|
||||
bool sync_macros (lay::MacroCollection *current, lay::MacroCollection *actual);
|
||||
void sync_file_watcher (lay::MacroCollection *current);
|
||||
void do_refresh_file_watcher ();
|
||||
void refresh_file_watcher ();
|
||||
|
|
@ -310,6 +311,7 @@ private:
|
|||
QTimer *m_file_changed_timer;
|
||||
std::vector<QString> m_changed_files, m_removed_files;
|
||||
tl::DeferredMethod<MacroEditorDialog> dm_refresh_file_watcher;
|
||||
tl::DeferredMethod<MacroEditorDialog> dm_update_ui_to_run_mode;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -33,14 +33,21 @@ namespace lay
|
|||
static const std::string cfg_salt_manager_window_state ("salt-manager-window-state");
|
||||
|
||||
SaltController::SaltController ()
|
||||
: mp_salt_dialog (0), mp_mw (0)
|
||||
: mp_salt_dialog (0), mp_mw (0), m_file_watcher (0),
|
||||
dm_sync_file_watcher (this, &SaltController::sync_file_watcher),
|
||||
dm_sync_files (this, &SaltController::sync_files)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
SaltController::initialized (lay::PluginRoot *root)
|
||||
{
|
||||
if (! m_file_watcher) {
|
||||
m_file_watcher = new tl::FileSystemWatcher (this);
|
||||
connect (m_file_watcher, SIGNAL (fileChanged (const QString &)), this, SLOT (file_watcher_triggered ()));
|
||||
connect (m_file_watcher, SIGNAL (fileRemoved (const QString &)), this, SLOT (file_watcher_triggered ()));
|
||||
}
|
||||
|
||||
mp_mw = dynamic_cast <lay::MainWindow *> (root);
|
||||
|
||||
connect (&m_salt, SIGNAL (collections_changed ()), this, SIGNAL (salt_changed ()));
|
||||
|
|
@ -51,6 +58,13 @@ SaltController::uninitialize (lay::PluginRoot * /*root*/)
|
|||
{
|
||||
disconnect (&m_salt, SIGNAL (collections_changed ()), this, SIGNAL (salt_changed ()));
|
||||
|
||||
if (m_file_watcher) {
|
||||
disconnect (m_file_watcher, SIGNAL (fileChanged (const QString &)), this, SLOT (file_watcher_triggered ()));
|
||||
disconnect (m_file_watcher, SIGNAL (fileRemoved (const QString &)), this, SLOT (file_watcher_triggered ()));
|
||||
delete m_file_watcher;
|
||||
m_file_watcher = 0;
|
||||
}
|
||||
|
||||
delete mp_salt_dialog;
|
||||
mp_salt_dialog = 0;
|
||||
mp_mw = 0;
|
||||
|
|
@ -133,20 +147,47 @@ SaltController::show_editor ()
|
|||
mp_mw->config_set (cfg_salt_manager_window_state, lay::save_dialog_state (mp_salt_dialog));
|
||||
}
|
||||
|
||||
sync_file_watcher ();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SaltController::sync_file_watcher ()
|
||||
{
|
||||
m_file_watcher->clear ();
|
||||
m_file_watcher->enable (false);
|
||||
for (lay::Salt::flat_iterator g = m_salt.begin_flat (); g != m_salt.end_flat (); ++g) {
|
||||
m_file_watcher->add_file ((*g)->path ());
|
||||
}
|
||||
m_file_watcher->enable (true);
|
||||
}
|
||||
|
||||
void
|
||||
SaltController::sync_files ()
|
||||
{
|
||||
tl::log << tl::to_string (tr ("Detected file system change in packages - updating"));
|
||||
emit salt_changed ();
|
||||
}
|
||||
|
||||
void
|
||||
SaltController::add_path (const std::string &path)
|
||||
{
|
||||
try {
|
||||
tl::log << tl::to_string (tr ("Scanning %1 for packages").arg (tl::to_qstring (path)));
|
||||
m_salt.add_location (path);
|
||||
dm_sync_file_watcher ();
|
||||
} catch (tl::Exception &ex) {
|
||||
tl::error << ex.msg ();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
SaltController::file_watcher_triggered ()
|
||||
{
|
||||
dm_sync_files ();
|
||||
}
|
||||
|
||||
void
|
||||
SaltController::set_salt_mine_url (const std::string &url)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@
|
|||
#include "layCommon.h"
|
||||
#include "layPlugin.h"
|
||||
#include "laySalt.h"
|
||||
#include "tlFileSystemWatcher.h"
|
||||
#include "tlDeferredExecution.h"
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
|
@ -145,6 +147,12 @@ public:
|
|||
*/
|
||||
static SaltController *instance ();
|
||||
|
||||
private slots:
|
||||
/**
|
||||
* @brief Called when the file watcher detects a change in the file system
|
||||
*/
|
||||
void file_watcher_triggered ();
|
||||
|
||||
signals:
|
||||
/**
|
||||
* @brief This signal is emitted if the salt changed
|
||||
|
|
@ -156,6 +164,12 @@ private:
|
|||
lay::MainWindow *mp_mw;
|
||||
std::string m_salt_mine_url;
|
||||
lay::Salt m_salt, m_salt_mine;
|
||||
tl::FileSystemWatcher *m_file_watcher;
|
||||
tl::DeferredMethod<SaltController> dm_sync_file_watcher;
|
||||
tl::DeferredMethod<SaltController> dm_sync_files;
|
||||
|
||||
void sync_file_watcher ();
|
||||
void sync_files ();
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue