Browse Source

Directories now gets updated automatically when files are deleted, added or renamed (max 1 sec delay).

merge-requests/365/head
eidheim 10 years ago
parent
commit
50d684b576
  1. 147
      src/directories.cc
  2. 12
      src/directories.h
  3. 2
      src/juci.cc
  4. 1
      src/notebook.cc
  5. 19
      src/window.cc
  6. 1
      src/window.h

147
src/directories.cc

@ -26,6 +26,7 @@ Directories::Directories() {
auto iter = tree_store->get_iter(path);
if (iter) {
auto path_str=iter->get_value(column_record.path);
if(path_str!="") {
if (boost::filesystem::is_directory(boost::filesystem::path(path_str))) {
tree_view.row_expanded(path) ? tree_view.collapse_row(path) : tree_view.expand_row(path, false);
} else {
@ -33,73 +34,113 @@ Directories::Directories() {
on_row_activated(path_str);
}
}
}
});
tree_view.signal_test_expand_row().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){
if(iter->children().begin()->get_value(column_record.path)=="") {
update_mutex.lock();
add_path(iter->get_value(column_record.path), *iter);
update_mutex.unlock();
}
return false;
});
tree_view.signal_row_collapsed().connect([this](const Gtk::TreeModel::iterator& iter, const Gtk::TreeModel::Path& path){
update_mutex.lock();
last_write_times.erase(iter->get_value(column_record.path));
update_mutex.unlock();
auto children=iter->children();
if(children) {
while(children) {
tree_store->erase(children.begin());
}
tree_store->append(iter->children());
auto child=tree_store->append(iter->children());
child->set_value(column_record.name, std::string("(empty)"));
}
});
update_dispatcher.connect([this](){
update_mutex.lock();
for(auto &path: update_paths) {
if(last_write_times.count(path)>0)
add_path(path, last_write_times.at(path).first);
}
update_paths.clear();
update_mutex.unlock();
});
std::thread update_thread([this](){
while(true) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
update_mutex.lock();
if(update_paths.size()==0) {
for(auto &last_write_time: last_write_times) {
try {
if(last_write_time.second.second<boost::filesystem::last_write_time(last_write_time.first)) {
update_paths.emplace_back(last_write_time.first);
}
}
catch(const std::exception &e) {
last_write_times.erase(last_write_time.first);
}
}
if(update_paths.size()>0)
update_dispatcher();
}
update_mutex.unlock();
}
});
update_thread.detach();
}
void Directories::open_folder(const boost::filesystem::path& dir_path) {
if(dir_path!="")
tree_store->clear();
void Directories::open(const boost::filesystem::path& dir_path) {
if(dir_path=="")
return;
auto new_path=dir_path;
INFO("Open folder");
if(dir_path=="") {
if(current_path=="")
return;
new_path=current_path;
}
std::vector<Gtk::TreeModel::Path> expanded_paths;
if(current_path==new_path) {
tree_view.map_expanded_rows([&expanded_paths](Gtk::TreeView* tree_view, const Gtk::TreeModel::Path& path){
expanded_paths.emplace_back(path);
});
}
tree_store->clear();
update_mutex.lock();
last_write_times.clear();
update_paths.clear();
update_mutex.unlock();
if(dir_path!="")
cmake=std::unique_ptr<CMake>(new CMake(new_path));
cmake=std::unique_ptr<CMake>(new CMake(dir_path));
auto project=cmake->get_functions_parameters("project");
if(project.size()>0 && project[0].second.size()>0)
tree_view.get_column(0)->set_title(project[0].second[0]);
else
tree_view.get_column(0)->set_title("");
add_path(new_path, Gtk::TreeModel::Row());
for(auto &path: expanded_paths)
tree_view.expand_row(path, false);
update_mutex.lock();
add_path(dir_path, Gtk::TreeModel::Row());
update_mutex.unlock();
current_path=new_path;
current_path=dir_path;
DEBUG("Folder opened");
}
void Directories::select_path(const boost::filesystem::path &path) {
void Directories::update() {
update_mutex.lock();
for(auto &last_write_time: last_write_times) {
add_path(last_write_time.first, last_write_time.second.first);
}
update_mutex.unlock();
}
void Directories::select(const boost::filesystem::path &path) {
if(current_path=="")
return;
if(path.string().substr(0, current_path.string().size())!=current_path.string())
return;
if(boost::filesystem::is_directory(path))
return;
std::list<boost::filesystem::path> paths;
auto parent_path=path.parent_path();
boost::filesystem::path parent_path;
if(boost::filesystem::is_directory(path))
parent_path=path;
else
parent_path=path.parent_path();
paths.emplace_front(parent_path);
while(parent_path!=current_path) {
parent_path=parent_path.parent_path();
@ -109,7 +150,9 @@ void Directories::select_path(const boost::filesystem::path &path) {
for(auto &a_path: paths) {
tree_store->foreach_iter([this, &a_path](const Gtk::TreeModel::iterator& iter){
if(iter->get_value(column_record.path)==a_path.string()) {
update_mutex.lock();
add_path(a_path, *iter);
update_mutex.unlock();
return true;
}
return false;
@ -121,7 +164,6 @@ void Directories::select_path(const boost::filesystem::path &path) {
auto tree_path=Gtk::TreePath(iter);
tree_view.expand_to_path(tree_path);
tree_view.set_cursor(tree_path);
selected_path=path;
return true;
}
return false;
@ -145,13 +187,15 @@ bool Directories::ignored(std::string path) {
}
void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent) {
auto children=tree_store->children();
last_write_times[dir_path.string()]={parent, boost::filesystem::last_write_time(dir_path)};
std::unique_ptr<Gtk::TreeNodeChildren> children; //Gtk::TreeNodeChildren is missing default constructor...
if(parent)
children=parent.children();
if(children) {
if(children.begin()->get_value(column_record.path)=="") {
tree_store->erase(parent->children().begin());
}
children=std::unique_ptr<Gtk::TreeNodeChildren>(new Gtk::TreeNodeChildren(parent.children()));
else
children=std::unique_ptr<Gtk::TreeNodeChildren>(new Gtk::TreeNodeChildren(tree_store->children()));
if(*children) {
if(children->begin()->get_value(column_record.path)=="")
tree_store->erase(children->begin());
}
std::unordered_set<std::string> not_deleted;
boost::filesystem::directory_iterator end_it;
@ -159,8 +203,8 @@ void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::T
auto filename=it->path().filename().string();
if (!ignored(filename)) {
bool already_added=false;
if(children) {
for(auto &child: children) {
if(*children) {
for(auto &child: *children) {
if(child.get_value(column_record.name)==filename) {
not_deleted.emplace(filename);
already_added=true;
@ -169,29 +213,44 @@ void Directories::add_path(const boost::filesystem::path& dir_path, const Gtk::T
}
}
if(!already_added) {
auto child = tree_store->append(children);
auto child = tree_store->append(*children);
not_deleted.emplace(filename);
child->set_value(column_record.name, filename);
child->set_value(column_record.path, it->path().string());
if (boost::filesystem::is_directory(*it)) {
child->set_value(column_record.id, "a"+filename);
tree_store->append(child->children());
auto grandchild=tree_store->append(child->children());
grandchild->set_value(column_record.name, std::string("(empty)"));
}
else
child->set_value(column_record.id, "b"+filename);
}
}
}
if(children) {
auto last_it=children.begin();
for(auto it=children.begin();it!=children.end();it++) {
if(*children) {
auto last_it=children->begin();
auto it=last_it;
while(it!=children->end()) {
if(not_deleted.count(it->get_value(column_record.name))==0) {
if(it==children->begin()) {
tree_store->erase(it);
it=children->begin();
last_it=it;
}
else {
tree_store->erase(it);
it=last_it;
it++;
}
}
else {
last_it=it;
it++;
}
}
else
tree_store->append(children);
}
if(!*children) {
auto child=tree_store->append(*children);
child->set_value(column_record.name, std::string("(empty)"));
}
}

12
src/directories.h

@ -6,6 +6,8 @@
#include <string>
#include "boost/filesystem.hpp"
#include "cmake.h"
#include <thread>
#include <mutex>
class Directories : public Gtk::ScrolledWindow {
public:
@ -28,8 +30,9 @@ public:
};
Directories();
void open_folder(const boost::filesystem::path& dir_path="");
void select_path(const boost::filesystem::path &path);
void open(const boost::filesystem::path& dir_path="");
void update();
void select(const boost::filesystem::path &path);
std::function<void(const std::string &file)> on_row_activated;
std::unique_ptr<CMake> cmake;
@ -41,7 +44,10 @@ private:
Gtk::TreeView tree_view;
Glib::RefPtr<Gtk::TreeStore> tree_store;
ColumnRecord column_record;
boost::filesystem::path selected_path;
std::unordered_map<std::string, std::pair<Gtk::TreeModel::Row, std::time_t> > last_write_times;
std::mutex update_mutex;
Glib::Dispatcher update_dispatcher;
std::vector<std::string> update_paths;
};
#endif // JUCI_DIRECTORIES_H_

2
src/juci.cc

@ -45,7 +45,7 @@ void app::on_activate() {
bool first_directory=true;
for(auto &directory: directories) {
if(first_directory) {
window->directories.open_folder(directory);
window->directories.open(directory);
first_directory=false;
}
else {

1
src/notebook.cc

@ -120,7 +120,6 @@ bool Notebook::save(int page) {
//TODO: recreate cmake even without directories open?
if(view->file_path.filename()=="CMakeLists.txt") {
if(directories.cmake && directories.cmake->project_path!="" && view->file_path.string().substr(0, directories.cmake->project_path.string().size())==directories.cmake->project_path.string() && CMake::create_compile_commands(directories.cmake->project_path)) {
directories.open_folder();
for(auto source_view: source_views) {
if(auto source_clang_view=dynamic_cast<Source::ClangView*>(source_view)) {
if(directories.cmake->project_path.string()==source_clang_view->project_path) {

19
src/window.cc

@ -91,7 +91,7 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil
if(auto menu_item=dynamic_cast<Gtk::MenuItem*>(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceRename")))
menu_item->set_sensitive((bool)notebook.get_current_view()->rename_similar_tokens);
directories.select_path(notebook.get_current_view()->file_path);
directories.select(notebook.get_current_view()->file_path);
Singleton::status()->set_text(notebook.get_current_view()->status);
}
@ -100,10 +100,6 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil
entry_box.hide();
});
compile_success.connect([this](){
directories.open_folder();
});
INFO("Window created");
} // Window constructor
@ -217,7 +213,6 @@ void Window::create_menu() {
if(notebook.get_current_page()==-1 || compiling)
return;
CMake cmake(notebook.get_current_view()->file_path);
directories.open_folder();
auto executables = cmake.get_functions_parameters("add_executable");
boost::filesystem::path executable_path;
if(executables.size()>0 && executables[0].second.size()>0) {
@ -233,7 +228,6 @@ void Window::create_menu() {
Singleton::terminal()->async_execute(Singleton::Config::terminal()->make_command, cmake.project_path, [this, executable_path, project_path](int exit_code){
compiling=false;
if(exit_code==EXIT_SUCCESS) {
compile_success();
//TODO: Windows...
auto executable_path_spaces_fixed=executable_path.string();
char last_char=0;
@ -261,15 +255,12 @@ void Window::create_menu() {
if(notebook.get_current_page()==-1 || compiling)
return;
CMake cmake(notebook.get_current_view()->file_path);
directories.open_folder();
if(cmake.project_path!="") {
compiling=true;
Singleton::terminal()->print("Compiling project "+cmake.project_path.string()+"\n");
//TODO: Windows...
Singleton::terminal()->async_execute(Singleton::Config::terminal()->make_command, cmake.project_path, [this](int exit_code){
compiling=false;
if(exit_code==EXIT_SUCCESS)
compile_success();
});
}
});
@ -369,7 +360,7 @@ void Window::new_file_entry() {
else {
if(juci::filesystem::write(p)) {
if(directories.current_path!="")
directories.open_folder();
directories.update();
notebook.open(boost::filesystem::canonical(p).string());
Singleton::terminal()->print("New file "+p.string()+" created.\n");
}
@ -420,7 +411,7 @@ void Window::new_cpp_project_dialog() {
std::string cmakelists="cmake_minimum_required(VERSION 2.8)\n\nproject("+project_name+")\n\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++1y -Wall\")\n\nadd_executable("+project_name+" main.cpp)\n";
std::string cpp_main="#include <iostream>\n\nusing namespace std;\n\nint main() {\n cout << \"Hello World!\" << endl;\n\n return 0;\n}\n";
if(juci::filesystem::write(cmakelists_path, cmakelists) && juci::filesystem::write(cpp_main_path, cpp_main)) {
directories.open_folder(project_path);
directories.open(project_path);
notebook.open(cpp_main_path);
Singleton::terminal()->print("C++ project "+project_name+" created.\n");
}
@ -444,7 +435,7 @@ void Window::open_folder_dialog() {
if(result==Gtk::RESPONSE_OK) {
std::string project_path=dialog.get_filename();
directories.open_folder(project_path);
directories.open(project_path);
}
}
@ -506,7 +497,7 @@ void Window::save_file_dialog() {
file << notebook.get_current_view()->get_buffer()->get_text();
file.close();
if(directories.current_path!="")
directories.open_folder();
directories.update();
notebook.open(path);
Singleton::terminal()->print("File saved to: " + notebook.get_current_view()->file_path.string()+"\n");
}

1
src/window.h

@ -36,7 +36,6 @@ private:
EntryBox entry_box;
Menu menu;
std::atomic<bool> compiling;
Glib::Dispatcher compile_success;
void create_menu();
void hide();

Loading…
Cancel
Save