diff --git a/src/api.cc b/src/api.cc index b1ac39b..fa93820 100644 --- a/src/api.cc +++ b/src/api.cc @@ -205,8 +205,7 @@ void libjuci::IterToWordEnd(Gtk::TextIter &iter) { } Glib::RefPtr libjuci::BufferFromNotebook() { - return Glib::RefPtr(PluginApi::notebook - ->CurrentSourceView()->get_buffer()); + return Glib::RefPtr(PluginApi::notebook->get_current_view()->get_buffer()); } Gtk::TextIter libjuci::IterFromNotebook() { diff --git a/src/config.cc b/src/config.cc index 8671110..a75b078 100644 --- a/src/config.cc +++ b/src/config.cc @@ -1,11 +1,9 @@ #include "singletons.h" #include "config.h" #include "logging.h" -#include -#include -#include #include #include "files.h" +#include "sourcefile.h" MainConfig::MainConfig() { find_or_create_config_files(); @@ -22,12 +20,9 @@ void MainConfig::find_or_create_config_files() { for (auto &file : files) { auto path = boost::filesystem::path(Singleton::config_dir() + file); if (!boost::filesystem::is_regular_file(path)) { - std::ofstream output; - output.open(path.string()); - if (file == "config.json") output << configjson; - if (file == "plugins.py") output << pluginspy; - if (file == "menu.xml") output << menuxml; - output.close(); + if (file == "config.json") juci::filesystem::save(path, configjson); + if (file == "plugins.py") juci::filesystem::save(path, pluginspy); + if (file == "menu.xml") juci::filesystem::save(path, menuxml); } } } @@ -39,41 +34,28 @@ void MainConfig::GenerateSource() { auto source_json = cfg.get_child("source"); auto syntax_json = source_json.get_child("syntax"); auto colors_json = source_json.get_child("colors"); - auto extensions_json = source_json.get_child("extensions"); auto visual_json = source_json.get_child("visual"); for (auto &i : visual_json) { - if (i.first == "background") { + if (i.first == "background") source_cfg->background = i.second.get_value(); - } - else if (i.first == "background_selected") { + else if (i.first == "background_selected") source_cfg->background_selected = i.second.get_value(); - } - else if (i.first == "background_tooltips") { + else if (i.first == "background_tooltips") source_cfg->background_tooltips = i.second.get_value(); - } - else if (i.first == "show_line_numbers") { + else if (i.first == "show_line_numbers") source_cfg->show_line_numbers = i.second.get_value() == "1" ? true : false; - } - else if (i.first == "highlight_current_line") { + else if (i.first == "highlight_current_line") source_cfg->highlight_current_line = i.second.get_value() == "1" ? true : false; - } - else if (i.first == "font") { + else if (i.first == "font") source_cfg->font = i.second.get_value(); - } } source_cfg->tab_size = source_json.get("tab_size"); - for (unsigned c = 0; c < source_cfg->tab_size; c++) { + for (unsigned c = 0; c < source_cfg->tab_size; c++) source_cfg->tab+=" "; - } - for (auto &i : colors_json) { + for (auto &i : colors_json) source_cfg->tags[i.first]=i.second.get_value(); - } - for (auto &i : syntax_json) { + for (auto &i : syntax_json) source_cfg->types[i.first]=i.second.get_value(); - } - for (auto &i : extensions_json) { - source_cfg->extensions.emplace_back(i.second.get_value()); - } DEBUG("Source cfg fetched"); } @@ -82,12 +64,10 @@ void MainConfig::GenerateTerminalCommands() { boost::property_tree::ptree source_json = cfg.get_child("project"); boost::property_tree::ptree compile_commands_json = source_json.get_child("compile_commands"); boost::property_tree::ptree run_commands_json = source_json.get_child("run_commands"); - for (auto &i : compile_commands_json) { + for (auto &i : compile_commands_json) terminal_cfg->compile_commands.emplace_back(i.second.get_value()); - } - for (auto &i : run_commands_json) { + for (auto &i : run_commands_json) terminal_cfg->run_command=(i.second.get_value()); //TODO: run_commands array->one run_command? - } } void MainConfig::GenerateKeybindings() { @@ -97,12 +77,7 @@ void MainConfig::GenerateKeybindings() { std::cerr << "menu.xml not found" << std::endl; throw; } - std::ifstream input(path.string()); - std::string line; - if (input.is_open()) { - while (getline(input, line)) - menu->ui += line; - } + menu->ui = juci::filesystem::open(path); boost::property_tree::ptree keys_json = cfg.get_child("keybindings"); for (auto &i : keys_json) { auto key=i.second.get_value(); @@ -118,8 +93,8 @@ void MainConfig::GenerateDirectoryFilter() { boost::property_tree::ptree ignore_json = dir_json.get_child("ignore"); boost::property_tree::ptree except_json = dir_json.get_child("exceptions"); for ( auto &i : except_json ) - dir_cfg->AddException(i.second.get_value()); + dir_cfg->exceptions.emplace_back(i.second.get_value()); for ( auto &i : ignore_json ) - dir_cfg->AddIgnore(i.second.get_value()); + dir_cfg->ignored.emplace_back(i.second.get_value()); DEBUG("Directory filter fetched"); } diff --git a/src/directories.cc b/src/directories.cc index 65a28dd..7c6505f 100644 --- a/src/directories.cc +++ b/src/directories.cc @@ -1,104 +1,109 @@ #include "directories.h" +#include "sourcefile.h" #include "logging.h" #include "singletons.h" +#include +#include "boost/algorithm/string.hpp" -Directories::Controller::Controller() { +namespace sigc { + SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE +} + +Directories::Directories() { DEBUG("adding treeview to scrolledwindow"); - m_ScrolledWindow.add(m_TreeView); - m_ScrolledWindow.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + add(tree_view); + set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + tree_store = Gtk::TreeStore::create(column_record); + tree_view.set_model(tree_store); + tree_view.append_column("", column_record.name); + tree_store->set_sort_column(0, Gtk::SortType::SORT_ASCENDING); + + tree_view.signal_row_activated().connect([this](const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column){ + INFO("Directory navigation"); + auto iter = tree_store->get_iter(path); + if (iter) { + Gtk::TreeModel::Row row = *iter; + std::string upath = Glib::ustring(row[column_record.path]); + boost::filesystem::path fs_path(upath); + if (boost::filesystem::is_directory(fs_path)) { + tree_view.row_expanded(path) ? tree_view.collapse_row(path) : tree_view.expand_row(path, false); + } else { + std::stringstream sstm; + sstm << row[column_record.path]; + if(on_row_activated) + on_row_activated(sstm.str()); + } + } + }); } -void Directories::Controller:: -open_folder(const boost::filesystem::path& dir_path) { +void Directories::open_folder(const boost::filesystem::path& dir_path) { INFO("Open folder"); - m_refTreeModel = Gtk::TreeStore::create(view()); - m_TreeView.set_model(m_refTreeModel); - m_TreeView.remove_all_columns(); - DEBUG("Getting project name from CMakeLists.txt"); - std::string project_name = GetCmakeVarValue(dir_path, "project"); - m_TreeView.append_column(project_name, view().m_col_name); - int row_id = 0; - Gtk::TreeModel::Row row; - DEBUG("Listing directories"); - list_dirs(dir_path, row, row_id); - DEBUG("Sorting directories"); - m_refTreeModel->set_sort_column(0, Gtk::SortType::SORT_ASCENDING); + tree_store->clear(); + tree_view.get_column(0)->set_title(get_cmakelists_variable(dir_path, "project")); + add_paths(dir_path, Gtk::TreeModel::Row(), 0); DEBUG("Folder opened"); } -bool Directories::Controller::IsIgnored(std::string path) { +bool Directories::ignored(std::string path) { DEBUG("Checking if file-/directory is filtered"); std::transform(path.begin(), path.end(), path.begin(), ::tolower); - if (Singleton::Config::directories()->IsException(path)) { - return false; + + for(std::string &i : Singleton::Config::directories()->exceptions) { + if(i == path) + return false; } - if (Singleton::Config::directories()->IsIgnored(path)) { - return true; + for(auto &i : Singleton::Config::directories()->ignored) { + if(path.find(i, 0) != std::string::npos) + return true; } + return false; } -void Directories::Controller:: -list_dirs(const boost::filesystem::path& dir_path, - Gtk::TreeModel::Row &parent, - unsigned row_id) { - + +void Directories::add_paths(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &parent, unsigned row_id) { boost::filesystem::directory_iterator end_itr; Gtk::TreeModel::Row child; Gtk::TreeModel::Row row; DEBUG(""); // Fill the treeview - for ( boost::filesystem::directory_iterator itr( dir_path ); - itr != end_itr; - ++itr ) { - if (!IsIgnored(itr->path().filename().string())) { + for(boost::filesystem::directory_iterator itr(dir_path);itr != end_itr;++itr) { + if (!ignored(itr->path().filename().string())) { if (boost::filesystem::is_directory(itr->status())) { - if (count(itr->path().string()) > count(dir_path.string())) { // is child - child = *(m_refTreeModel->append(parent.children())); + if (boost::filesystem::canonical(itr->path()) > boost::filesystem::canonical(dir_path)) { // is child + child = *(tree_store->append(parent.children())); std::string col_id("a"+itr->path().filename().string()); - child[view().m_col_id] = col_id; - child[view().m_col_name] = itr->path().filename().string(); - child[view().m_col_path] = itr->path().string(); - list_dirs(itr->path(), child, row_id); + child[column_record.id] = col_id; + child[column_record.name] = itr->path().filename().string(); + child[column_record.path] = itr->path().string(); + add_paths(itr->path(), child, row_id); } else { - row = *(m_refTreeModel->append()); + row = *(tree_store->append()); std::string col_id("a"+itr->path().filename().string()); - row[view().m_col_path] = itr->path().string(); - row[view().m_col_id] = col_id; - row[view().m_col_name] = itr->path().filename().string(); - list_dirs(itr->path(), parent, row_id); + row[column_record.path] = itr->path().string(); + row[column_record.id] = col_id; + row[column_record.name] = itr->path().filename().string(); + add_paths(itr->path(), parent, row_id); } } else { // is a file - child = *(m_refTreeModel->append(parent.children())); + child = *(tree_store->append(parent.children())); std::string col_id("b"+itr->path().filename().string()); - child[view().m_col_id] = col_id; - child[view().m_col_name] = itr->path().filename().string(); - child[view().m_col_path] = itr->path().string(); + child[column_record.id] = col_id; + child[column_record.name] = itr->path().filename().string(); + child[column_record.path] = itr->path().string(); } } } } -int Directories::Controller::count(const std::string path) { - int count = 0; - for (size_t i = 0; i < path.size(); i++) - if (path[i] == '/') - count++; - return count; -} - -std::string Directories::Controller:: -GetCmakeVarValue(const boost::filesystem::path& dir_path, std::string command_name) { +std::string Directories::get_cmakelists_variable(const boost::filesystem::path& dir_path, std::string command_name) { INFO("fetches cmake variable value for: "+command_name); std::string project_name; std::string project_name_var; boost::filesystem::directory_iterator end_itr; - for (boost::filesystem::directory_iterator itr( dir_path ); - itr != end_itr; - ++itr ) { + for (boost::filesystem::directory_iterator itr( dir_path );itr != end_itr;++itr ) { if (itr->path().filename().string() == "CMakeLists.txt") { - std::ifstream ifs(itr->path().string()); - std::string line; - while (std::getline(ifs, line)) { + for (auto &line : juci::filesystem::lines(itr->path())) { if (line.find(command_name+"(", 0) != std::string::npos || line.find(command_name+" (", 0) != std::string::npos ) { size_t variable_start = line.find("{", 0); @@ -133,8 +138,7 @@ GetCmakeVarValue(const boost::filesystem::path& dir_path, std::string command_na } } } - std::ifstream ifs2(itr->path().string()); - while (std::getline(ifs2, line)) { + for (auto &line : juci::filesystem::lines(itr->path())) { if (line.find("set(", 0) != std::string::npos || line.find("set (", 0) != std::string::npos) { if( line.find(project_name_var, 0) != std::string::npos) { @@ -155,25 +159,3 @@ GetCmakeVarValue(const boost::filesystem::path& dir_path, std::string command_na INFO("Couldn't find value in CMakeLists.txt"); return "no project name"; } - -void Directories::Config::AddIgnore(std::string filter) { - ignore_list_.push_back(filter); -} - -void Directories::Config::AddException(std::string filter) { - exception_list_.push_back(filter); -} - -bool Directories::Config::IsIgnored(std::string str) { - for ( auto &i : ignore_list() ) - if (str.find(i, 0) != std::string::npos) - return true; - return false; -} - -bool Directories::Config::IsException(std::string str) { - for ( std::string &i : exception_list() ) - if (i == str) - return true; - return false; -} diff --git a/src/directories.h b/src/directories.h index c6363c5..3391998 100644 --- a/src/directories.h +++ b/src/directories.h @@ -2,69 +2,42 @@ #define JUCI_DIRECTORIES_H_ #include -#include +#include +#include #include "boost/filesystem.hpp" -#include "boost/algorithm/string.hpp" -#include -#include -#include -#include - -namespace Directories { +class Directories : public Gtk::ScrolledWindow { +public: class Config { public: - std::vector ignore_list() { return ignore_list_; } - std::vector exception_list() { return exception_list_; } - void AddIgnore(std::string filter); - void AddException(std::string filter); - bool IsException(std::string path); - bool IsIgnored(std::string path); - private: - std::vector ignore_list_; - std::vector exception_list_; + std::vector ignored; + std::vector exceptions; }; - class View : public Gtk::TreeModel::ColumnRecord { + + class ColumnRecord : public Gtk::TreeModel::ColumnRecord { public: - View() { - add(m_col_id); - add(m_col_name); - add(m_col_path); + ColumnRecord() { + add(id); + add(name); + add(path); } - Gtk::TreeModelColumn m_col_id; - Gtk::TreeModelColumn m_col_name; - Gtk::TreeModelColumn m_col_path; + Gtk::TreeModelColumn id; + Gtk::TreeModelColumn name; + Gtk::TreeModelColumn path; }; - class Model { }; - - class Controller { - public: - Controller(); - View& view() { return view_;} - Model& model() { return model_;} - Gtk::ScrolledWindow& widget() {return m_ScrolledWindow;} - void open_folder(const boost::filesystem::path& dir_path); - void list_dirs(const boost::filesystem::path& dir_path, - Gtk::TreeModel::Row &row, unsigned depth); - std::string GetCmakeVarValue(const boost::filesystem::path& dir_path, std::string command_name); - int count(const std::string path); - - // Child widgets: - Gtk::Box m_VBox; - Gtk::ScrolledWindow m_ScrolledWindow; - Gtk::TreeView m_TreeView; - Glib::RefPtr m_refTreeModel; - bool IsIgnored(std::string path); - - private: - View view_; - Model model_; - - protected: - void on_treeview_row_activated(const Gtk::TreeModel::Path& path, - Gtk::TreeViewColumn* column); - }; -} // namespace Directories + Directories(); + void open_folder(const boost::filesystem::path& dir_path); + std::string get_cmakelists_variable(const boost::filesystem::path& dir_path, std::string command_name); + + std::function on_row_activated; + +private: + void add_paths(const boost::filesystem::path& dir_path, const Gtk::TreeModel::Row &row, unsigned depth); + Gtk::TreeView tree_view; + Glib::RefPtr tree_store; + ColumnRecord column_record; + bool ignored(std::string path); +}; #endif // JUCI_DIRECTORIES_H_ diff --git a/src/files.h b/src/files.h index dde0b17..fa34cd7 100644 --- a/src/files.h +++ b/src/files.h @@ -155,3 +155,71 @@ const std::string pluginspy = " juci.initPlugin(current_file) \n" "loadplugins() \n"; +const std::string snippetpy = +"#!/usr/bin/python \n" +"#snippet plugin \n" +"import juci_to_python_api as juci, inspect \n" +" \n" +"def initPlugin(): \n" +" juci.addMenuElement(\"Snippet\") \n" +" juci.addSubMenuElement(\"SnippetMenu\", #name of parent menu \n" +" \"Insert snippet\", #menu description \n" +" \"insertSnippet()\", #function to execute \n" +" inspect.getfile(inspect.currentframe()), #plugin path \n" +" \"space\") \n" +"snippets = {} \n" +" \n" +"snippets[\"for\"] = \"\"\"\ \n" +"for(int i=0; i \n" +" \n" +"int main(int argc, char *argv[]) { \n" +" std::cout << \"Hello, world! << std::endl; \n" +"} \n" +"\"\"\" \n" +" \n" +"def getSnippet(word): \n" +" try: \n" +" output = snippets[word] \n" +" except KeyError: \n" +" output = word \n" +" return output \n" +" \n" +"def insertSnippet(): \n" +" theWord=juci.getWord() \n" +" output=getSnippet(theWord) \n" +" juci.replaceWord(output) \n"; + + diff --git a/src/juci.cc b/src/juci.cc index a6326dc..629c22b 100644 --- a/src/juci.cc +++ b/src/juci.cc @@ -40,7 +40,7 @@ void Juci::on_activate() { window->directories.open_folder(directory); } for(auto &f: files) - window->notebook.open_file(f); + window->notebook.open(f); } int main(int argc, char *argv[]) { diff --git a/src/juci.h b/src/juci.h index 244c9ac..4ce2cb2 100644 --- a/src/juci.h +++ b/src/juci.h @@ -1,7 +1,6 @@ #ifndef JUCI_JUCI_H_ #define JUCI_JUCI_H_ -#include "config.h" #include "window.h" #include "logging.h" @@ -13,7 +12,6 @@ public: void on_activate(); private: - MainConfig main_config; std::unique_ptr window; std::string directory; std::vector files; diff --git a/src/menu.cc b/src/menu.cc index d20b74d..7a040d3 100644 --- a/src/menu.cc +++ b/src/menu.cc @@ -7,7 +7,7 @@ Menu::Menu() : box(Gtk::ORIENTATION_VERTICAL) { action_group = Gtk::ActionGroup::create(); ui_manager = Gtk::UIManager::create(); - action_group->add(Gtk::Action::create("FileNew", "New File")); + action_group->add(Gtk::Action::create("FileMenu", "File")); action_group->add(Gtk::Action::create("EditMenu", "Edit")); action_group->add(Gtk::Action::create("WindowMenu", "_Window")); action_group->add(Gtk::Action::create("WindowSplitWindow", "Split window"), Gtk::AccelKey(key_map["split_window"]), [this]() { @@ -25,10 +25,6 @@ Gtk::Widget& Menu::get_widget() { return *ui_manager->get_widget("/MenuBar"); } -Gtk::Menu& Menu::get_source_menu() { - return *(Gtk::Menu*)ui_manager->get_widget("/MenuBar/SourceMenu"); -} - void Menu::build() { try { ui_manager->add_ui_from_string(ui); diff --git a/src/menu.h b/src/menu.h index 40e3cb3..9dcc6eb 100644 --- a/src/menu.h +++ b/src/menu.h @@ -9,7 +9,6 @@ class Menu { public: Menu(); Gtk::Widget& get_widget(); - Gtk::Menu& get_source_menu(); void build(); Gtk::Box box; diff --git a/src/notebook.cc b/src/notebook.cc index aedd553..3c60ccb 100644 --- a/src/notebook.cc +++ b/src/notebook.cc @@ -1,8 +1,7 @@ -#include #include "notebook.h" #include "logging.h" +#include "sourcefile.h" #include "singletons.h" -#include //TODO: remove using namespace std; //TODO: remove namespace sigc { @@ -10,92 +9,68 @@ namespace sigc { } Notebook::Notebook() : Gtk::Notebook() { - INFO("Create notebook"); Gsv::init(); +} - auto menu=Singleton::menu(); - INFO("Notebook create signal handlers"); - menu->action_group->add(Gtk::Action::create("FileMenu", "File")); - - menu->action_group->add(Gtk::Action::create("WindowCloseTab", "Close tab"), Gtk::AccelKey(menu->key_map["close_tab"]), [this]() { - close_current_page(); - }); +int Notebook::size() { + return get_n_pages(); +} - menu->action_group->add(Gtk::Action::create("EditUndo", "Undo"), Gtk::AccelKey(menu->key_map["edit_undo"]), [this]() { - INFO("On undo"); - Glib::RefPtr undo_manager = CurrentSourceView()->get_source_buffer()->get_undo_manager(); - if (Pages() != 0 && undo_manager->can_undo()) { - undo_manager->undo(); - } - INFO("Done undo"); - }); +Source::View* Notebook::get_view(int page) { + if(page>=size()) + return nullptr; + return source_views.at(page).get(); +} - menu->action_group->add(Gtk::Action::create("EditRedo", "Redo"), Gtk::AccelKey(menu->key_map["edit_redo"]), [this]() { - INFO("On Redo"); - Glib::RefPtr undo_manager = - CurrentSourceView()->get_source_buffer()->get_undo_manager(); - if (Pages() != 0 && undo_manager->can_redo()) { - undo_manager->redo(); - } - INFO("Done Redo"); - }); - - menu->action_group->add(Gtk::Action::create("SourceGotoDeclaration", "Go to declaration"), Gtk::AccelKey(menu->key_map["source_goto_declaration"]), [this]() { - if(CurrentPage()!=-1) { - if(CurrentSourceView()->get_declaration_location) { - auto location=CurrentSourceView()->get_declaration_location(); - if(location.first.size()>0) { - open_file(location.first); - CurrentSourceView()->get_buffer()->place_cursor(CurrentSourceView()->get_buffer()->get_iter_at_offset(location.second)); - while(gtk_events_pending()) - gtk_main_iteration(); - CurrentSourceView()->scroll_to(CurrentSourceView()->get_buffer()->get_insert(), 0.0, 1.0, 0.5); - } - } - } - }); - - menu->action_group->add(Gtk::Action::create("SourceGotoMethod", "Go to method"), Gtk::AccelKey(menu->key_map["source_goto_method"]), [this]() { - if(CurrentPage()!=-1) { - if(CurrentSourceView()->goto_method) { - CurrentSourceView()->goto_method(); - } - } - }); +Source::View* Notebook::get_current_view() { + INFO("Getting sourceview"); + if(get_current_page()==-1) + return nullptr; + return get_view(get_current_page()); } -void Notebook::open_file(std::string path) { +void Notebook::open(std::string path) { INFO("Notebook open file"); INFO("Notebook create page"); - for(int c=0;cview->file_path) { + for(int c=0;cfile_path) { set_current_page(c); return; } } - source_views.emplace_back(new Source(path, project_path)); + + auto tmp_project_path=project_path; + if(tmp_project_path=="") { + tmp_project_path=boost::filesystem::path(path).parent_path().string(); + } + auto language=Source::guess_language(path); + if(language && (language->get_id()=="chdr" || language->get_id()=="c" || language->get_id()=="cpp" || language->get_id()=="objc")) + source_views.emplace_back(new Source::ClangView(path, tmp_project_path)); + else + source_views.emplace_back(new Source::GenericView(path, tmp_project_path, language)); + scrolled_windows.emplace_back(new Gtk::ScrolledWindow()); hboxes.emplace_back(new Gtk::HBox()); - scrolled_windows.back()->add(*source_views.back()->view); + scrolled_windows.back()->add(*source_views.back()); hboxes.back()->pack_start(*scrolled_windows.back(), true, true); - boost::filesystem::path file_path(source_views.back()->view->file_path); + boost::filesystem::path file_path(source_views.back()->file_path); std::string title=file_path.filename().string(); append_page(*hboxes.back(), title); show_all_children(); - set_current_page(Pages()-1); - set_focus_child(*source_views.back()->view); - CurrentSourceView()->get_buffer()->set_modified(false); + set_current_page(size()-1); + set_focus_child(*source_views.back()); + get_current_view()->get_buffer()->set_modified(false); //Add star on tab label when the page is not saved: - auto source_view=CurrentSourceView(); - CurrentSourceView()->get_buffer()->signal_modified_changed().connect([this, source_view]() { + auto source_view=get_current_view(); + get_current_view()->get_buffer()->signal_modified_changed().connect([this, source_view]() { boost::filesystem::path file_path(source_view->file_path); std::string title=file_path.filename().string(); if(source_view->get_buffer()->get_modified()) title+="*"; int page=-1; - for(int c=0;cview.get()==source_view) { + for(int c=0;c=size()) + return false; + auto view=get_view(page); + if (view->file_path != "" && view->get_buffer()->get_modified()) { + juci::filesystem::save(view->file_path, view->get_buffer()->get_text()); + view->get_buffer()->set_modified(false); + Singleton::terminal()->print("File saved to: " +view->file_path+"\n"); + return true; + } + return false; +} + +bool Notebook::save_current() { + INFO("Notebook save current file"); + if(get_current_page()==-1) + return false; + return save(get_current_page()); +} + bool Notebook::close_current_page() { INFO("Notebook close page"); - if (Pages() != 0) { - if(CurrentSourceView()->get_buffer()->get_modified()){ + if (size() != 0) { + if(get_current_view()->get_buffer()->get_modified()){ if(!save_modified_dialog()) return false; } - int page = CurrentPage(); + int page = get_current_page(); remove_page(page); source_views.erase(source_views.begin()+ page); scrolled_windows.erase(scrolled_windows.begin()+page); @@ -121,26 +116,13 @@ bool Notebook::close_current_page() { return true; } -Source::View* Notebook::CurrentSourceView() { - INFO("Getting sourceview"); - return source_views.at(CurrentPage())->view.get(); -} - -int Notebook::CurrentPage() { - return get_current_page(); -} - -int Notebook::Pages() { - return get_n_pages(); -} - bool Notebook::save_modified_dialog() { - INFO("Notebook::save_dialog"); + INFO("Notebook::save_modified_dialog"); Gtk::MessageDialog dialog((Gtk::Window&)(*get_toplevel()), "Save file!", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO); - dialog.set_secondary_text("Do you want to save: " + CurrentSourceView()->file_path+" ?"); + dialog.set_secondary_text("Do you want to save: " + get_current_view()->file_path+" ?"); int result = dialog.run(); if(result==Gtk::RESPONSE_YES) { - CurrentSourceView()->save(); + save_current(); return true; } else if(result==Gtk::RESPONSE_NO) { diff --git a/src/notebook.h b/src/notebook.h index 0f8f356..79fb9f9 100644 --- a/src/notebook.h +++ b/src/notebook.h @@ -3,29 +3,27 @@ #include #include "gtkmm.h" -#include "entrybox.h" #include "source.h" -#include "directories.h" #include #include #include #include -#include "clangmm.h" class Notebook : public Gtk::Notebook { public: Notebook(); - Source::View* CurrentSourceView(); - int CurrentPage(); + Source::View* get_view(int page); + int size(); + Source::View* get_current_view(); bool close_current_page(); - void open_file(std::string filename); - int Pages(); + void open(std::string filename); + bool save(int page); + bool save_current(); std::string project_path; - std::vector > source_views; private: bool save_modified_dialog(); - + std::vector > source_views; std::vector > scrolled_windows; std::vector > hboxes; }; diff --git a/src/source.cc b/src/source.cc index f97c5b5..0df15fb 100644 --- a/src/source.cc +++ b/src/source.cc @@ -1,7 +1,6 @@ #include "source.h" #include "sourcefile.h" #include -#include #include #include "logging.h" #include @@ -16,14 +15,22 @@ namespace sigc { SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE } -bool Source::Config::legal_extension(std::string e) const { - std::transform(e.begin(), e.end(),e.begin(), ::tolower); - if (find(extensions.begin(), extensions.end(), e) != extensions.end()) { - DEBUG("Legal extension"); - return true; +Glib::RefPtr Source::guess_language(const std::string &file_path) { + auto language_manager=Gsv::LanguageManager::get_default(); + bool result_uncertain = false; + auto content_type = Gio::content_type_guess(file_path, NULL, 0, result_uncertain); + if(result_uncertain) { + content_type.clear(); + } + auto language=language_manager->guess_language(file_path, content_type); + if(!language) { + auto path=boost::filesystem::path(file_path); + auto filename=path.filename().string(); + auto extension=path.extension(); + if(filename=="CMakeLists.txt") + language=language_manager->get_language("cmake"); } - DEBUG("Ilegal extension"); - return false; + return language; } ////////////// @@ -34,13 +41,10 @@ file_path(file_path), project_path(project_path) { set_smart_home_end(Gsv::SMART_HOME_END_BEFORE); set_show_line_numbers(Singleton::Config::source()->show_line_numbers); set_highlight_current_line(Singleton::Config::source()->highlight_current_line); - sourcefile s(file_path); get_source_buffer()->get_undo_manager()->begin_not_undoable_action(); - get_source_buffer()->set_text(s.get_content()); + get_source_buffer()->set_text(juci::filesystem::open(file_path)); get_source_buffer()->get_undo_manager()->end_not_undoable_action(); - - get_buffer()->place_cursor(get_buffer()->get_iter_at_offset(0)); - + get_buffer()->place_cursor(get_buffer()->get_iter_at_offset(0)); search_settings = gtk_source_search_settings_new(); gtk_source_search_settings_set_wrap_around(search_settings, true); search_context = gtk_source_search_context_new(get_source_buffer()->gobj(), search_settings); @@ -56,20 +60,6 @@ file_path(file_path), project_path(project_path) { g_signal_connect(search_context, "notify::occurrences-count", G_CALLBACK(search_occurrences_updated), this); } -bool Source::View::save() { - INFO("Source save file"); - if (file_path != "" && get_buffer()->get_modified()) { - std::ofstream file; - file.open (file_path); - file << get_buffer()->get_text(); - file.close(); - get_buffer()->set_modified(false); - Singleton::terminal()->print("File saved to: " +file_path+"\n"); - return true; - } - return false; -} - void Source::View::search_occurrences_updated(GtkWidget* widget, GParamSpec* property, gpointer data) { auto view=(Source::View*)data; if(view->update_search_occurrences) @@ -241,7 +231,7 @@ bool Source::View::on_key_press_event(GdkEventKey* key) { ///////////////////// //// GenericView //// ///////////////////// -Source::GenericView::GenericView(const std::string& file_path, const std::string& project_path) : View(file_path, project_path) { +Source::GenericView::GenericView(const std::string& file_path, const std::string& project_path, Glib::RefPtr language) : View(file_path, project_path) { auto style_scheme_manager=Gsv::StyleSchemeManager::get_default(); //TODO: add?: style_scheme_manager->prepend_search_path("~/.juci/"); auto scheme=style_scheme_manager->get_scheme("classic"); @@ -252,20 +242,6 @@ Source::GenericView::GenericView(const std::string& file_path, const std::string cout << "TODO, in progress: def:comment in scheme " << scheme->get_name() << " has color " << style->property_foreground() << endl; } - auto language_manager=Gsv::LanguageManager::get_default(); - bool result_uncertain = false; - auto content_type = Gio::content_type_guess(file_path, get_buffer()->get_text(), result_uncertain); - if(result_uncertain) { - content_type.clear(); - } - auto language=language_manager->guess_language(file_path, content_type); - if(!language) { - auto path=boost::filesystem::path(file_path); - auto filename=path.filename().string(); - auto extension=path.extension(); - if(filename=="CMakeLists.txt") - language=language_manager->get_language("cmake"); - } if(language) { get_source_buffer()->set_language(language); Singleton::terminal()->print("Language for file "+file_path+" set to "+language->get_name()+".\n"); @@ -1038,18 +1014,3 @@ Source::ClangViewAutocomplete(file_path, project_path) { } }; } - -//////////////// -//// Source //// -//////////////// - -Source::Source(const std::string& file_path, std::string project_path) { - if(project_path=="") { - project_path=boost::filesystem::path(file_path).parent_path().string(); - } - if (Singleton::Config::source()->legal_extension(file_path.substr(file_path.find_last_of(".") + 1))) - view=std::unique_ptr(new ClangView(file_path, project_path)); - else - view=std::unique_ptr(new GenericView(file_path, project_path)); - INFO("Source Controller with childs constructed"); -} diff --git a/src/source.h b/src/source.h index af7f347..d695093 100644 --- a/src/source.h +++ b/src/source.h @@ -15,16 +15,15 @@ #include "selectiondialog.h" #include -class Source { -public: +namespace Source { + Glib::RefPtr guess_language(const std::string &file_path); + class Config { public: - bool legal_extension(std::string e) const ; unsigned tab_size; bool show_line_numbers, highlight_current_line; std::string tab, background, background_selected, background_tooltips, font; char tab_char=' '; - std::vector extensions; std::unordered_map tags, types; }; // class Config @@ -50,8 +49,6 @@ public: View(const std::string& file_path, const std::string& project_path); ~View(); - bool save(); - void search_highlight(const std::string &text, bool case_sensitive, bool regex); std::function update_search_occurrences; void search_forward(); @@ -82,7 +79,7 @@ public: class GenericView : public View { public: - GenericView(const std::string& file_path, const std::string& project_path); + GenericView(const std::string& file_path, const std::string& project_path, Glib::RefPtr language); }; class ClangViewParse : public View { @@ -167,9 +164,5 @@ public: ClangView(const std::string& file_path, const std::string& project_path): ClangViewRefactor(file_path, project_path) {} }; - - Source(const std::string& file_path, std::string project_path); - - std::unique_ptr view; }; // class Source #endif // JUCI_SOURCE_H_ diff --git a/src/sourcefile.cc b/src/sourcefile.cc index 0374584..0583f06 100644 --- a/src/sourcefile.cc +++ b/src/sourcefile.cc @@ -1,92 +1,32 @@ #include "sourcefile.h" -#include -#include -#include -#include +#include -using namespace std; - -sourcefile::sourcefile(const string &input_filename) - : lines(), filename(input_filename) { - open(input_filename); -} - -/** - * - */ -void sourcefile::open(const string &filename) { - Gio::init(); - - // Creates/Opens a file specified by the input string. - Glib::RefPtr file = Gio::File::create_for_path(filename); - - if (!file) // Gio::File has overloaded operator - cerr << "Was not able to open file: " << filename << endl; - - // Creates pointer for filestream - - if (!file->query_exists()) { - file->create_file()->close(); - } - - Glib::RefPtr stream = file->read(); - - if (!stream) // error message on stream failure - cerr << filename << " returned an empty stream" << endl; - - Glib::RefPtr - datainput = Gio::DataInputStream::create(stream); - - string line; - while (datainput->read_line(line)) { - lines.push_back(line); +std::string juci::filesystem::open(std::string path) { + std::string res; + for (auto &line : lines(path)) { + res += line; } - - datainput->close(); - stream->close(); -} - -vector sourcefile::get_lines() { - return lines; -} - -string sourcefile::get_line(int line_number) { - return lines[line_number]; -} - -int sourcefile::save(const string &text) { - Gio::init(); - - // Creates/Opens a file specified by the input string. - Glib::RefPtr file = Gio::File::create_for_path(filename); - - if (!file) // Gio::File has overloaded operator - cerr << "Was not able to open file: " << filename << endl; - - // Creates - Glib::RefPtr stream = - file->query_exists() ? file->replace() : file->create_file(); - - if (!stream) // error message on stream failure - cerr << filename << " returned an empty stream" << endl; - - Glib::RefPtr - output = Gio::DataOutputStream::create(stream); - - output->put_string(text); - - output->close(); - stream->close(); - - - return 0; + return res; } -string sourcefile::get_content() { - string res; - for (auto line : lines) { - res.append(line).append("\n"); +std::vector juci::filesystem::lines(std::string path) { + std::vector res; + std::ifstream input(path); + if (input.is_open()) { + do { res.emplace_back(); } while(getline(input, res.back())); } + input.close(); return res; } +int juci::filesystem::save(std::string path, std::string new_content) { + std::ofstream output(path); + if(output.is_open()) { + output << new_content; + } else { + output.close(); + return 1; + } + output.close(); + return 0; +} \ No newline at end of file diff --git a/src/sourcefile.h b/src/sourcefile.h index 2afc263..c86bc89 100644 --- a/src/sourcefile.h +++ b/src/sourcefile.h @@ -1,21 +1,20 @@ #ifndef JUCI_SOURCEFILE_H_ #define JUCI_SOURCEFILE_H_ - -#include #include +#include +#include -class sourcefile { -public: - explicit sourcefile(const std::string &filename); - std::vector get_lines(); - std::string get_content(); - std::string get_line(int line_number); - int save(const std::string &text); - -private: - void open(const std::string &filename); - std::vector lines; - std::string filename; -}; - +namespace juci { + class filesystem { + public: + static std::string open(std::string); + static std::string open(boost::filesystem::path path) { return open(path.string()); } + static std::vector lines(std::string); + static std::vector lines(boost::filesystem::path path) { return lines(path.string()); }; + static int save(std::string, std::string); + static int save(boost::filesystem::path path, std::string new_content) { return save(path.string(), new_content); } + static int save(std::string path) { return save(path, ""); }; + static int save(boost::filesystem::path path) { return save(path, ""); }; + }; +} // namepace juci #endif // JUCI_SOURCEFILE_H_ diff --git a/src/window.cc b/src/window.cc index 3065fcb..b02a95d 100644 --- a/src/window.cc +++ b/src/window.cc @@ -1,203 +1,217 @@ #include "window.h" #include "logging.h" #include "singletons.h" +#include "sourcefile.h" +#include "config.h" +#include "api.h" namespace sigc { SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE } -Window::Window() : notebook(), plugin_api(¬ebook), box(Gtk::ORIENTATION_VERTICAL) { +Window::Window() : box(Gtk::ORIENTATION_VERTICAL) { INFO("Create Window"); set_title("juCi++"); set_default_size(600, 400); set_events(Gdk::POINTER_MOTION_MASK|Gdk::FOCUS_CHANGE_MASK|Gdk::SCROLL_MASK); add(box); - //TODO: see TODO Window::on_directory_navigation - directories.m_TreeView.signal_row_activated().connect(sigc::mem_fun(*this, &Window::on_directory_navigation)); + + MainConfig(); //Read the configs here + PluginApi(&this->notebook); //Initialise plugins + add_menu(); + + box.pack_start(entry_box, Gtk::PACK_SHRINK); + + directory_and_notebook_panes.pack1(directories, true, true); //TODO: should be pack1(directories, ...) Clean up directories.* + directory_and_notebook_panes.pack2(notebook); + directory_and_notebook_panes.set_position(120); + + vpaned.set_position(300); + vpaned.pack1(directory_and_notebook_panes, true, false); + vpaned.pack2(Singleton::terminal()->view, true, true); + box.pack_end(vpaned); + show_all_children(); + + directories.on_row_activated=[this](const std::string &file) { + notebook.open(file); + }; + + entry_box.signal_show().connect([this](){ + std::vector focus_chain; + focus_chain.emplace_back(&entry_box); + box.set_focus_chain(focus_chain); + }); + entry_box.signal_hide().connect([this](){ + box.unset_focus_chain(); + }); + entry_box.signal_hide().connect([this]() { + if(notebook.get_current_page()!=-1) { + notebook.get_current_view()->grab_focus(); + } + }); + + notebook.signal_switch_page().connect([this](Gtk::Widget* page, guint page_num) { + if(search_entry_shown && entry_box.labels.size()>0 && notebook.get_current_page()!=-1) { + notebook.get_current_view()->update_search_occurrences=[this](int number){ + entry_box.labels.begin()->update(0, std::to_string(number)); + }; + notebook.get_current_view()->search_highlight(last_search, case_sensitive_search, regex_search); + } + + if(notebook.get_current_page()!=-1) { + if(auto menu_item=dynamic_cast(Singleton::menu()->ui_manager->get_widget("/MenuBar/SourceMenu/SourceGotoDeclaration"))) + menu_item->set_sensitive((bool)notebook.get_current_view()->get_declaration_location); + + if(auto menu_item=dynamic_cast(Singleton::menu()->ui_manager->get_widget("/MenuBar/SourceMenu/SourceGotoMethod"))) + menu_item->set_sensitive((bool)notebook.get_current_view()->goto_method); + + if(auto menu_item=dynamic_cast(Singleton::menu()->ui_manager->get_widget("/MenuBar/SourceMenu/SourceRename"))) + menu_item->set_sensitive((bool)notebook.get_current_view()->rename_similar_tokens); + } + }); + INFO("Window created"); +} // Window constructor + +void Window::add_menu() { auto menu=Singleton::menu(); INFO("Adding actions to menu"); menu->action_group->add(Gtk::Action::create("FileQuit", "Quit juCi++"), Gtk::AccelKey(menu->key_map["quit"]), [this]() { - hide(); - }); + hide(); + }); menu->action_group->add(Gtk::Action::create("FileNewFile", "New file"), Gtk::AccelKey(menu->key_map["new_file"]), [this]() { - new_file_entry(); - }); + new_file_entry(); + }); menu->action_group->add(Gtk::Action::create("FileOpenFile", "Open file"), Gtk::AccelKey(menu->key_map["open_file"]), [this]() { - open_file_dialog(); - }); + open_file_dialog(); + }); menu->action_group->add(Gtk::Action::create("FileOpenFolder", "Open folder"), Gtk::AccelKey(menu->key_map["open_folder"]), [this]() { - open_folder_dialog(); - }); + open_folder_dialog(); + }); menu->action_group->add(Gtk::Action::create("FileSaveAs", "Save as"), Gtk::AccelKey(menu->key_map["save_as"]), [this]() { - save_file_dialog(); - }); + save_file_dialog(); + }); menu->action_group->add(Gtk::Action::create("FileSave", "Save"), Gtk::AccelKey(menu->key_map["save"]), [this]() { - notebook.CurrentSourceView()->save(); - }); - + notebook.save_current(); + }); + menu->action_group->add(Gtk::Action::create("EditCopy", "Copy"), Gtk::AccelKey(menu->key_map["edit_copy"]), [this]() { - auto widget=get_focus(); - if(auto entry=dynamic_cast(widget)) - entry->copy_clipboard(); - else if(auto text_view=dynamic_cast(widget)) + auto widget=get_focus(); + if(auto entry=dynamic_cast(widget)) + entry->copy_clipboard(); + else if(auto text_view=dynamic_cast(widget)) text_view->get_buffer()->copy_clipboard(Gtk::Clipboard::get()); - }); + }); menu->action_group->add(Gtk::Action::create("EditCut", "Cut"), Gtk::AccelKey(menu->key_map["edit_cut"]), [this]() { - auto widget=get_focus(); - if(auto entry=dynamic_cast(widget)) - entry->cut_clipboard(); - else { - if (notebook.Pages() != 0) - notebook.CurrentSourceView()->get_buffer()->cut_clipboard(Gtk::Clipboard::get()); - } - }); + auto widget=get_focus(); + if(auto entry=dynamic_cast(widget)) + entry->cut_clipboard(); + else if(notebook.get_current_page()!=-1) + notebook.get_current_view()->get_buffer()->cut_clipboard(Gtk::Clipboard::get()); + }); menu->action_group->add(Gtk::Action::create("EditPaste", "Paste"), Gtk::AccelKey(menu->key_map["edit_paste"]), [this]() { - auto widget=get_focus(); - if(auto entry=dynamic_cast(widget)) - entry->paste_clipboard(); - else { - if (notebook.Pages() != 0) - notebook.CurrentSourceView()->get_buffer()->paste_clipboard(Gtk::Clipboard::get()); - } - }); + auto widget=get_focus(); + if(auto entry=dynamic_cast(widget)) + entry->paste_clipboard(); + else if(notebook.get_current_page()!=-1) + notebook.get_current_view()->get_buffer()->paste_clipboard(Gtk::Clipboard::get()); + }); menu->action_group->add(Gtk::Action::create("EditFind", "Find"), Gtk::AccelKey(menu->key_map["edit_find"]), [this]() { - search_and_replace_entry(); - }); - - menu->action_group->add(Gtk::Action::create("SourceRename", "Rename function/variable"), Gtk::AccelKey(menu->key_map["source_rename"]), [this]() { - entry_box.clear(); - if(notebook.CurrentPage()!=-1) { - if(notebook.CurrentSourceView()->get_token && notebook.CurrentSourceView()->get_token_name) { - auto token=std::make_shared(notebook.CurrentSourceView()->get_token()); - if(token->size()>0 && notebook.CurrentSourceView()->get_token_name) { - auto token_name=std::make_shared(notebook.CurrentSourceView()->get_token_name()); - for(int c=0;cview->tag_similar_tokens) { - notebook.source_views.at(c)->view->tag_similar_tokens(*token); - } + search_and_replace_entry(); + }); + menu->action_group->add(Gtk::Action::create("EditUndo", "Undo"), Gtk::AccelKey(menu->key_map["edit_undo"]), [this]() { + INFO("On undo"); + if(notebook.get_current_page()!=-1) { + auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager(); + if (undo_manager->can_undo()) { + undo_manager->undo(); + } + } + INFO("Done undo"); + }); + menu->action_group->add(Gtk::Action::create("EditRedo", "Redo"), Gtk::AccelKey(menu->key_map["edit_redo"]), [this]() { + INFO("On Redo"); + if(notebook.get_current_page()!=-1) { + auto undo_manager = notebook.get_current_view()->get_source_buffer()->get_undo_manager(); + if(undo_manager->can_redo()) { + undo_manager->redo(); + } + } + INFO("Done Redo"); + }); + + menu->action_group->add(Gtk::Action::create("SourceGotoDeclaration", "Go to declaration"), Gtk::AccelKey(menu->key_map["source_goto_declaration"]), [this]() { + if(notebook.get_current_page()!=-1) { + if(notebook.get_current_view()->get_declaration_location) { + auto location=notebook.get_current_view()->get_declaration_location(); + if(location.first.size()>0) { + notebook.open(location.first); + notebook.get_current_view()->get_buffer()->place_cursor(notebook.get_current_view()->get_buffer()->get_iter_at_offset(location.second)); + while(gtk_events_pending()) + gtk_main_iteration(); + notebook.get_current_view()->scroll_to(notebook.get_current_view()->get_buffer()->get_insert(), 0.0, 1.0, 0.5); } - entry_box.labels.emplace_back(); - auto label_it=entry_box.labels.begin(); - label_it->update=[label_it](int state, const std::string& message){ - label_it->set_text("Warning: only opened and parsed tabs will have its content renamed, and modified files will be saved."); - }; - label_it->update(0, ""); - entry_box.entries.emplace_back(*token_name, [this, token_name, token](const std::string& content){ - if(notebook.CurrentPage()!=-1 && content!=*token_name) { - for(int c=0;cview->rename_similar_tokens) { - auto number=notebook.source_views.at(c)->view->rename_similar_tokens(*token, content); - if(number>0) { - Singleton::terminal()->print("Replaced "+std::to_string(number)+" occurrences in file "+notebook.source_views.at(c)->view->file_path+"\n"); - notebook.source_views.at(c)->view->save(); - } - } - } - entry_box.hide(); - } - }); - auto entry_it=entry_box.entries.begin(); - entry_box.buttons.emplace_back("Rename", [this, entry_it](){ - entry_it->activate(); - }); - entry_box.show(); } } - } - }); - + }); + menu->action_group->add(Gtk::Action::create("SourceGotoMethod", "Go to method"), Gtk::AccelKey(menu->key_map["source_goto_method"]), [this]() { + if(notebook.get_current_page()!=-1) { + if(notebook.get_current_view()->goto_method) { + notebook.get_current_view()->goto_method(); + } + } + }); + menu->action_group->add(Gtk::Action::create("SourceRename", "Rename"), Gtk::AccelKey(menu->key_map["source_rename"]), [this]() { + rename_token_entry(); + }); + menu->action_group->add(Gtk::Action::create("ProjectCompileAndRun", "Compile And Run"), Gtk::AccelKey(menu->key_map["compile_and_run"]), [this]() { - if(notebook.CurrentPage()==-1) - return; - notebook.CurrentSourceView()->save(); - if (running.try_lock()) { - std::thread execute([this]() { - std::string path = notebook.CurrentSourceView()->file_path; - size_t pos = path.find_last_of("/\\"); - if(pos != std::string::npos) { - path.erase(path.begin()+pos,path.end()); - Singleton::terminal()->SetFolderCommand(path); - } - Singleton::terminal()->Compile(); - std::string executable = directories.GetCmakeVarValue(path,"add_executable"); - Singleton::terminal()->Run(executable); - running.unlock(); - }); - execute.detach(); - } - }); - + if(notebook.get_current_page()==-1) + return; + notebook.save_current(); + if (running.try_lock()) { + std::thread execute([this]() { + std::string path = notebook.get_current_view()->file_path; + size_t pos = path.find_last_of("/\\"); + if(pos != std::string::npos) { + path.erase(path.begin()+pos,path.end()); + Singleton::terminal()->SetFolderCommand(path); + } + Singleton::terminal()->Compile(); + std::string executable = directories.get_cmakelists_variable(path,"add_executable"); + Singleton::terminal()->Run(executable); + running.unlock(); + }); + execute.detach(); + } + }); menu->action_group->add(Gtk::Action::create("ProjectCompile", "Compile"), Gtk::AccelKey(menu->key_map["compile"]), [this]() { - if(notebook.CurrentPage()==-1) - return; - notebook.CurrentSourceView()->save(); - if (running.try_lock()) { - std::thread execute([this]() { - std::string path = notebook.CurrentSourceView()->file_path; - size_t pos = path.find_last_of("/\\"); - if(pos != std::string::npos){ - path.erase(path.begin()+pos,path.end()); - Singleton::terminal()->SetFolderCommand(path); - } - Singleton::terminal()->Compile(); - running.unlock(); - }); - execute.detach(); - } - }); - INFO("Done adding actions to menu, building menu:") + if(notebook.get_current_page()==-1) + return; + notebook.save_current(); + if (running.try_lock()) { + std::thread execute([this]() { + std::string path = notebook.get_current_view()->file_path; + size_t pos = path.find_last_of("/\\"); + if(pos != std::string::npos){ + path.erase(path.begin()+pos,path.end()); + Singleton::terminal()->SetFolderCommand(path); + } + Singleton::terminal()->Compile(); + running.unlock(); + }); + execute.detach(); + } + }); + + menu->action_group->add(Gtk::Action::create("WindowCloseTab", "Close tab"), Gtk::AccelKey(menu->key_map["close_tab"]), [this]() { + notebook.close_current_page(); + }); add_accel_group(menu->ui_manager->get_accel_group()); menu->build(); INFO("Menu build") - box.pack_start(menu->get_widget(), Gtk::PACK_SHRINK); - box.pack_start(entry_box, Gtk::PACK_SHRINK); - - directory_and_notebook_panes.pack1(directories.widget(), true, true); //TODO: should be pack1(directories, ...) Clean up directories.* - directory_and_notebook_panes.pack2(notebook); - directory_and_notebook_panes.set_position(120); - - vpaned.set_position(300); - vpaned.pack1(directory_and_notebook_panes, true, false); - vpaned.pack2(Singleton::terminal()->view, true, true); - box.pack_end(vpaned); - show_all_children(); - - entry_box.signal_show().connect([this](){ - std::vector focus_chain; - focus_chain.emplace_back(&entry_box); - box.set_focus_chain(focus_chain); - }); - entry_box.signal_hide().connect([this](){ - box.unset_focus_chain(); - }); - entry_box.signal_hide().connect([this]() { - if(notebook.CurrentPage()!=-1) { - notebook.CurrentSourceView()->grab_focus(); - } - }); - notebook.signal_switch_page().connect([this](Gtk::Widget* page, guint page_num) { - if(search_entry_shown && entry_box.labels.size()>0 && notebook.CurrentPage()!=-1) { - notebook.CurrentSourceView()->update_search_occurrences=[this](int number){ - entry_box.labels.begin()->update(0, std::to_string(number)); - }; - notebook.CurrentSourceView()->search_highlight(last_search, case_sensitive_search, regex_search); - } - - if(notebook.CurrentPage()!=-1) { - if(auto menu_item=dynamic_cast(Singleton::menu()->ui_manager->get_widget("/MenuBar/SourceMenu/SourceGotoDeclaration"))) - menu_item->set_sensitive((bool)notebook.CurrentSourceView()->get_declaration_location); - - if(auto menu_item=dynamic_cast(Singleton::menu()->ui_manager->get_widget("/MenuBar/SourceMenu/SourceGotoMethod"))) - menu_item->set_sensitive((bool)notebook.CurrentSourceView()->goto_method); - - if(auto menu_item=dynamic_cast(Singleton::menu()->ui_manager->get_widget("/MenuBar/SourceMenu/SourceRename"))) - menu_item->set_sensitive((bool)notebook.CurrentSourceView()->rename_similar_tokens); - } - }); - - INFO("Window created"); -} // Window constructor + box.pack_start(menu->get_widget(), Gtk::PACK_SHRINK); +} bool Window::on_key_press_event(GdkEventKey *event) { if(event->keyval==GDK_KEY_Escape) @@ -236,7 +250,7 @@ bool Window::on_key_press_event(GdkEventKey *event) { } } #endif - + return Gtk::Window::on_key_press_event(event); } @@ -246,8 +260,8 @@ bool Window::on_delete_event (GdkEventAny *event) { } void Window::hide() { - auto size=notebook.source_views.size(); - for(size_t c=0;cprint("Error: "+p.string()+" already exists.\n"); } else { - std::ofstream f(p.string().c_str()); - if(f) { - notebook.open_file(boost::filesystem::canonical(p).string()); - Singleton::terminal()->print("New file "+p.string()+" created.\n"); - if(notebook.project_path!="") - directories.open_folder(notebook.project_path); //TODO: Do refresh instead - } - else { - Singleton::terminal()->print("Error: could not create new file "+p.string()+".\n"); - } - f.close(); + juci::filesystem::save(p); + notebook.open(boost::filesystem::canonical(p).string()); + Singleton::terminal()->print("New file "+p.string()+" created.\n"); + if(notebook.project_path!="") + directories.open_folder(notebook.project_path); //TODO: Do refresh instead } } entry_box.hide(); @@ -310,7 +318,6 @@ void Window::open_file_dialog() { Gtk::FileChooserDialog dialog("Please choose a file", Gtk::FILE_CHOOSER_ACTION_OPEN); if(notebook.project_path.size()>0) gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), notebook.project_path.c_str()); - std::cout << notebook.project_path << std::endl; dialog.set_transient_for(*this); dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); @@ -340,14 +347,16 @@ void Window::open_file_dialog() { if(result==Gtk::RESPONSE_OK) { std::string path = dialog.get_filename(); - notebook.open_file(path); + notebook.open(path); } } void Window::save_file_dialog() { + if(notebook.get_current_page()==-1) + return; INFO("Save file dialog"); Gtk::FileChooserDialog dialog(*this, "Please choose a file", Gtk::FILE_CHOOSER_ACTION_SAVE); - gtk_file_chooser_set_filename((GtkFileChooser*)dialog.gobj(), notebook.CurrentSourceView()->file_path.c_str()); + gtk_file_chooser_set_filename((GtkFileChooser*)dialog.gobj(), notebook.get_current_view()->file_path.c_str()); dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); dialog.add_button("_Save", Gtk::RESPONSE_OK); @@ -358,10 +367,10 @@ void Window::save_file_dialog() { if(path.size()>0) { std::ofstream file(path); if(file) { - file << notebook.CurrentSourceView()->get_buffer()->get_text(); + file << notebook.get_current_view()->get_buffer()->get_text(); file.close(); - notebook.open_file(path); - Singleton::terminal()->print("File saved to: " + notebook.CurrentSourceView()->file_path+"\n"); + notebook.open(path); + Singleton::terminal()->print("File saved to: " + notebook.get_current_view()->file_path+"\n"); if(notebook.project_path!="") directories.open_folder(notebook.project_path); //TODO: Do refresh instead } @@ -371,27 +380,6 @@ void Window::save_file_dialog() { } } -//TODO: move most of it to Directories -void Window::on_directory_navigation(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column) { - INFO("Directory navigation"); - Gtk::TreeModel::iterator iter = directories.m_refTreeModel->get_iter(path); - if (iter) { - Gtk::TreeModel::Row row = *iter; - std::string upath = Glib::ustring(row[directories.view().m_col_path]); - boost::filesystem::path fs_path(upath); - if (boost::filesystem::is_directory(fs_path)) { - directories.m_TreeView.row_expanded(path) ? - directories.m_TreeView.collapse_row(path) : - directories.m_TreeView.expand_row(path, false); - } else { - std::stringstream sstm; - sstm << row[directories.view().m_col_path]; - std::string file = sstm.str(); - notebook.open_file(file); - } - } -} - void Window::search_and_replace_entry() { entry_box.clear(); entry_box.labels.emplace_back(); @@ -408,81 +396,123 @@ void Window::search_and_replace_entry() { } }; entry_box.entries.emplace_back(last_search, [this](const std::string& content){ - if(notebook.CurrentPage()!=-1) - notebook.CurrentSourceView()->search_forward(); - }); + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->search_forward(); + }); auto search_entry_it=entry_box.entries.begin(); search_entry_it->set_placeholder_text("Find"); - if(notebook.CurrentPage()!=-1) { - notebook.CurrentSourceView()->update_search_occurrences=[label_it](int number){ + if(notebook.get_current_page()!=-1) { + notebook.get_current_view()->update_search_occurrences=[label_it](int number){ label_it->update(0, std::to_string(number)); }; - notebook.CurrentSourceView()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); + notebook.get_current_view()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); } search_entry_it->signal_key_press_event().connect([this](GdkEventKey* event){ - if(event->keyval==GDK_KEY_Return && event->state==GDK_SHIFT_MASK) { - if(notebook.CurrentPage()!=-1) - notebook.CurrentSourceView()->search_backward(); - } - return false; - }); + if(event->keyval==GDK_KEY_Return && event->state==GDK_SHIFT_MASK) { + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->search_backward(); + } + return false; + }); search_entry_it->signal_changed().connect([this, search_entry_it](){ - last_search=search_entry_it->get_text(); - if(notebook.CurrentPage()!=-1) - notebook.CurrentSourceView()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); - }); - + last_search=search_entry_it->get_text(); + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); + }); + entry_box.entries.emplace_back(last_replace, [this](const std::string &content){ - if(notebook.CurrentPage()!=-1) - notebook.CurrentSourceView()->replace_forward(content); - }); + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->replace_forward(content); + }); auto replace_entry_it=entry_box.entries.begin(); replace_entry_it++; replace_entry_it->set_placeholder_text("Replace"); replace_entry_it->signal_key_press_event().connect([this, replace_entry_it](GdkEventKey* event){ - if(event->keyval==GDK_KEY_Return && event->state==GDK_SHIFT_MASK) { - if(notebook.CurrentPage()!=-1) - notebook.CurrentSourceView()->replace_backward(replace_entry_it->get_text()); - } - return false; - }); + if(event->keyval==GDK_KEY_Return && event->state==GDK_SHIFT_MASK) { + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->replace_backward(replace_entry_it->get_text()); + } + return false; + }); replace_entry_it->signal_changed().connect([this, replace_entry_it](){ - last_replace=replace_entry_it->get_text(); - }); - + last_replace=replace_entry_it->get_text(); + }); + entry_box.buttons.emplace_back("Find", [this](){ - if(notebook.CurrentPage()!=-1) - notebook.CurrentSourceView()->search_forward(); - }); + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->search_forward(); + }); entry_box.buttons.emplace_back("Replace", [this, replace_entry_it](){ - if(notebook.CurrentPage()!=-1) - notebook.CurrentSourceView()->replace_forward(replace_entry_it->get_text()); - }); + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->replace_forward(replace_entry_it->get_text()); + }); entry_box.buttons.emplace_back("Replace all", [this, replace_entry_it](){ - if(notebook.CurrentPage()!=-1) - notebook.CurrentSourceView()->replace_all(replace_entry_it->get_text()); - }); + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->replace_all(replace_entry_it->get_text()); + }); entry_box.toggle_buttons.emplace_back("Match case"); entry_box.toggle_buttons.back().set_active(case_sensitive_search); entry_box.toggle_buttons.back().on_activate=[this, search_entry_it](){ case_sensitive_search=!case_sensitive_search; - if(notebook.CurrentPage()!=-1) - notebook.CurrentSourceView()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); }; entry_box.toggle_buttons.emplace_back("Use regex"); entry_box.toggle_buttons.back().set_active(regex_search); entry_box.toggle_buttons.back().on_activate=[this, search_entry_it](){ regex_search=!regex_search; - if(notebook.CurrentPage()!=-1) - notebook.CurrentSourceView()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); + if(notebook.get_current_page()!=-1) + notebook.get_current_view()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); }; entry_box.signal_hide().connect([this]() { - for(int c=0;cview->update_search_occurrences=nullptr; - notebook.source_views.at(c)->view->search_highlight("", case_sensitive_search, regex_search); - } - search_entry_shown=false; - }); + for(int c=0;cupdate_search_occurrences=nullptr; + notebook.get_view(c)->search_highlight("", case_sensitive_search, regex_search); + } + search_entry_shown=false; + }); search_entry_shown=true; entry_box.show(); } + +void Window::rename_token_entry() { + entry_box.clear(); + if(notebook.get_current_page()!=-1) { + if(notebook.get_current_view()->get_token && notebook.get_current_view()->get_token_name) { + auto token=std::make_shared(notebook.get_current_view()->get_token()); + if(token->size()>0 && notebook.get_current_view()->get_token_name) { + auto token_name=std::make_shared(notebook.get_current_view()->get_token_name()); + for(int c=0;ctag_similar_tokens) { + notebook.get_view(c)->tag_similar_tokens(*token); + } + } + entry_box.labels.emplace_back(); + auto label_it=entry_box.labels.begin(); + label_it->update=[label_it](int state, const std::string& message){ + label_it->set_text("Warning: only opened and parsed tabs will have its content renamed, and modified files will be saved."); + }; + label_it->update(0, ""); + entry_box.entries.emplace_back(*token_name, [this, token_name, token](const std::string& content){ + if(notebook.get_current_page()!=-1 && content!=*token_name) { + for(int c=0;crename_similar_tokens) { + auto number=notebook.get_view(c)->rename_similar_tokens(*token, content); + if(number>0) { + Singleton::terminal()->print("Replaced "+std::to_string(number)+" occurrences in file "+notebook.get_view(c)->file_path+"\n"); + notebook.save(c); + } + } + } + entry_box.hide(); + } + }); + auto entry_it=entry_box.entries.begin(); + entry_box.buttons.emplace_back("Rename", [this, entry_it](){ + entry_it->activate(); + }); + entry_box.show(); + } + } + } +} diff --git a/src/window.h b/src/window.h index 21dc235..8c505f9 100644 --- a/src/window.h +++ b/src/window.h @@ -1,15 +1,16 @@ #ifndef JUCI_WINDOW_H_ #define JUCI_WINDOW_H_ -#include "api.h" #include - +#include "directories.h" +#include "entrybox.h" +#include "notebook.h" class Window : public Gtk::Window { public: Window(); Notebook notebook; - Directories::Controller directories; + Directories directories; protected: bool on_key_press_event(GdkEventKey *event); bool on_delete_event (GdkEventAny *event); @@ -18,17 +19,17 @@ private: Gtk::VPaned vpaned; Gtk::Paned directory_and_notebook_panes; EntryBox entry_box; - PluginApi plugin_api; std::mutex running; + void add_menu(); void hide(); void new_file_entry(); void open_folder_dialog(); void open_file_dialog(); void save_file_dialog(); - void on_directory_navigation(const Gtk::TreeModel::Path& path, Gtk::TreeViewColumn* column); void search_and_replace_entry(); + void rename_token_entry(); std::string last_search; std::string last_replace; bool case_sensitive_search=true;