diff --git a/src/dialogs.cpp b/src/dialogs.cpp index 7d86d1a..52f10dd 100644 --- a/src/dialogs.cpp +++ b/src/dialogs.cpp @@ -1,7 +1,7 @@ #include "dialogs.hpp" #include -Dialog::Message::Message(const std::string &text) : Gtk::Window(Gtk::WindowType::WINDOW_POPUP) { +Dialog::Message::Message(const std::string &text, std::function &&on_cancel, bool show_progress_bar) : Gtk::Window(Gtk::WindowType::WINDOW_POPUP) { auto g_application = g_application_get_default(); auto gio_application = Glib::wrap(g_application, true); auto application = Glib::RefPtr::cast_static(gio_application); @@ -17,6 +17,17 @@ Dialog::Message::Message(const std::string &text) : Gtk::Window(Gtk::WindowType: auto label = Gtk::manage(new Gtk::Label(text)); label->set_padding(10, 10); box->pack_start(*label); + if(on_cancel) { + auto cancel_button = Gtk::manage(new Gtk::Button("Cancel")); + cancel_button->signal_clicked().connect([label, on_cancel = std::move(on_cancel)] { + label->set_text("Canceling..."); + if(on_cancel) + on_cancel(); + }); + box->pack_start(*cancel_button); + } + if(show_progress_bar) + box->pack_start(progress_bar); add(*box); show_all_children(); @@ -26,6 +37,10 @@ Dialog::Message::Message(const std::string &text) : Gtk::Window(Gtk::WindowType: Gtk::Main::iteration(); } +void Dialog::Message::set_fraction(double fraction) { + progress_bar.set_fraction(fraction); +} + bool Dialog::Message::on_delete_event(GdkEventAny *event) { return true; } diff --git a/src/dialogs.hpp b/src/dialogs.hpp index d746826..b4be549 100644 --- a/src/dialogs.hpp +++ b/src/dialogs.hpp @@ -14,10 +14,14 @@ public: class Message : public Gtk::Window { public: - Message(const std::string &text); + Message(const std::string &text, std::function &&on_cancel = {}, bool show_progrss_bar = false); + void set_fraction(double fraction); protected: bool on_delete_event(GdkEventAny *event) override; + + private: + Gtk::ProgressBar progress_bar; }; private: diff --git a/src/source_clang.cpp b/src/source_clang.cpp index 778ba7d..80bdd67 100644 --- a/src/source_clang.cpp +++ b/src/source_clang.cpp @@ -1849,9 +1849,7 @@ void Source::ClangViewRefactor::wait_parsing() { } } if(message) { - for(;;) { - while(Gtk::Main::events_pending()) - Gtk::Main::iteration(); + while(true) { bool all_parsed = true; for(auto &clang_view : clang_views) { if(!clang_view->parsed) { @@ -1861,6 +1859,8 @@ void Source::ClangViewRefactor::wait_parsing() { } if(all_parsed) break; + while(Gtk::Main::events_pending()) + Gtk::Main::iteration(); std::this_thread::sleep_for(std::chrono::milliseconds(10)); } message->hide(); diff --git a/src/usages_clang.cpp b/src/usages_clang.cpp index 4ad15d4..4cba989 100644 --- a/src/usages_clang.cpp +++ b/src/usages_clang.cpp @@ -6,6 +6,7 @@ #include "utility.hpp" #include #include +#include #include #include @@ -161,13 +162,24 @@ std::vector Usages::Clang::get_usages(const boost::filesy // Wait for current caching to finish std::unique_ptr message; const std::string message_string = "Please wait while finding usages"; - if(cache_in_progress_count != 0) { - message = std::make_unique(message_string); + std::atomic canceled(false); + auto on_cancel = [&canceled] { + canceled = true; + }; + size_t tasks = cache_in_progress_count; + std::atomic tasks_completed = {0}; + if(tasks != 0) { + message = std::make_unique(message_string, std::move(on_cancel), true); while(cache_in_progress_count != 0) { + message->set_fraction((static_cast(tasks - cache_in_progress_count) / tasks) / 10.0); while(Gtk::Main::events_pending()) Gtk::Main::iteration(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } } + tasks_completed = tasks; + if(canceled) + return {}; // Use cache for(auto it = potential_paths.begin(); it != potential_paths.end();) { @@ -205,8 +217,9 @@ std::vector Usages::Clang::get_usages(const boost::filesy // Parse potential paths if(!potential_paths.empty()) { + tasks += potential_paths.size(); if(!message) - message = std::make_unique(message_string); + message = std::make_unique(message_string, std::move(on_cancel), true); std::vector threads; auto it = potential_paths.begin(); @@ -216,16 +229,19 @@ std::vector Usages::Clang::get_usages(const boost::filesy if(number_of_threads == 0) number_of_threads = 1; } + std::vector> completed_threads(number_of_threads); for(unsigned thread_id = 0; thread_id < number_of_threads; ++thread_id) { + completed_threads[thread_id] = false; threads.emplace_back([&potential_paths, &it, &build_path, - &project_path, &usages, &visited, &spelling, &cursor] { - while(true) { + &project_path, &usages, &visited, &spelling, &cursor, + thread_id, &completed_threads, &tasks_completed, &canceled] { + while(!canceled) { boost::filesystem::path path; { static Mutex mutex; LockGuard lock(mutex); if(it == potential_paths.end()) - return; + break; path = *it; ++it; } @@ -256,11 +272,26 @@ std::vector Usages::Clang::get_usages(const boost::filesy add_usages_from_includes(project_path, build_path, usages, visited, spelling, cursor, &translation_unit, true); } - // auto time = std::chrono::system_clock::now(); - // std::cout << std::chrono::duration_cast(time - before_time).count() << std::endl; + tasks_completed++; } + completed_threads[thread_id] = true; }); } + while(true) { + bool all_completed = true; + for(auto &completed_thread : completed_threads) { + if(!completed_thread) { + all_completed = false; + break; + } + } + if(all_completed) + break; + message->set_fraction(static_cast(tasks_completed) / tasks); + while(Gtk::Main::events_pending()) + Gtk::Main::iteration(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } for(auto &thread : threads) thread.join(); } @@ -268,6 +299,9 @@ std::vector Usages::Clang::get_usages(const boost::filesy if(message) message->hide(); + if(canceled) + return {}; + return usages; } @@ -364,6 +398,7 @@ void Usages::Clang::erase_all_caches_for_project(const boost::filesystem::path & while(cache_in_progress_count != 0) { while(Gtk::Main::events_pending()) Gtk::Main::iteration(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } message.hide(); } @@ -450,10 +485,8 @@ bool Usages::Clang::add_usages_from_cache(const boost::filesystem::path &path, s for(auto &path_and_last_write_time : cache.paths_and_last_write_times) { boost::system::error_code ec; auto last_write_time = boost::filesystem::last_write_time(path_and_last_write_time.first, ec); - if(ec || last_write_time != path_and_last_write_time.second) { - // std::cout << "updated file: " << path_and_last_write_time.first << ", included from " << path << std::endl; + if(ec || last_write_time != path_and_last_write_time.second) return false; - } } auto offsets = cache.get_similar_token_offsets(cursor.get_kind(), spelling, cursor.get_all_usr_extended()); diff --git a/src/window.cpp b/src/window.cpp index 1765ead..17b1600 100644 --- a/src/window.cpp +++ b/src/window.cpp @@ -129,6 +129,7 @@ Window::Window() { while(!Source::View::non_deleted_views.empty()) { while(Gtk::Main::events_pending()) Gtk::Main::iteration(); + std::this_thread::sleep_for(std::chrono::milliseconds(10)); } message.hide(); } diff --git a/tests/stubs/dialogs.cpp b/tests/stubs/dialogs.cpp index 087cb5e..50255e4 100644 --- a/tests/stubs/dialogs.cpp +++ b/tests/stubs/dialogs.cpp @@ -1,6 +1,8 @@ #include "dialogs.hpp" -Dialog::Message::Message(const std::string &text) : Gtk::Window(Gtk::WindowType::WINDOW_POPUP) {} +Dialog::Message::Message(const std::string &text, std::function &&on_cancel, bool show_progress_bar) : Gtk::Window(Gtk::WindowType::WINDOW_POPUP) {} + +void Dialog::Message::set_fraction(double fraction) {} bool Dialog::Message::on_delete_event(GdkEventAny *event) { return true;