diff --git a/juci/api.cc b/juci/api.cc index 14acce7..4cf9242 100644 --- a/juci/api.cc +++ b/juci/api.cc @@ -3,13 +3,13 @@ #include "singletons.h" Menu* PluginApi::menu_=nullptr; -Notebook::Controller* PluginApi::notebook_=nullptr; +Notebook* PluginApi::notebook=nullptr; ///////////////////////////// //// API ServiceProvider //// ///////////////////////////// -PluginApi::PluginApi() { +PluginApi::PluginApi(Notebook* notebook) { DEBUG("Adding pointers for the API"); - notebook_ = Singleton::notebook(); + this->notebook = notebook; menu_ = Singleton::menu(); DEBUG("Initiating plugins(from plugins.py).."); #ifndef __APPLE__ @@ -211,7 +211,7 @@ void libjuci::IterToWordEnd(Gtk::TextIter &iter) { } Glib::RefPtr libjuci::BufferFromNotebook() { - return Glib::RefPtr(PluginApi::notebook_ + return Glib::RefPtr(PluginApi::notebook ->CurrentSourceView()->get_buffer()); } diff --git a/juci/api.h b/juci/api.h index 3f97710..6292c07 100644 --- a/juci/api.h +++ b/juci/api.h @@ -12,9 +12,9 @@ //////////////////// class PluginApi { public: - PluginApi(); + PluginApi(Notebook* notebook); static Menu* menu_; - static Notebook::Controller* notebook_; + static Notebook* notebook; static void InitPlugins(); static std::string ProjectPath(); // for Python module: diff --git a/juci/juci.cc b/juci/juci.cc index 4ca0558..bd38c4b 100644 --- a/juci/juci.cc +++ b/juci/juci.cc @@ -36,12 +36,11 @@ void Juci::on_activate() { add_window(*window); window->show(); if(directory!="") { - //TODO: use the following instead, window->notebook.open_directory(directory); - Singleton::notebook()->project_path=directory; - Singleton::notebook()->directories.open_folder(directory); + window->notebook.project_path=directory; + window->directories.open_folder(directory); } for(auto &f: files) - Singleton::notebook()->open_file(f); + window->notebook.open_file(f); } int main(int argc, char *argv[]) { diff --git a/juci/juci.h b/juci/juci.h index 4ce2cb2..244c9ac 100644 --- a/juci/juci.h +++ b/juci/juci.h @@ -1,6 +1,7 @@ #ifndef JUCI_JUCI_H_ #define JUCI_JUCI_H_ +#include "config.h" #include "window.h" #include "logging.h" @@ -12,6 +13,7 @@ public: void on_activate(); private: + MainConfig main_config; std::unique_ptr window; std::string directory; std::vector files; diff --git a/juci/notebook.cc b/juci/notebook.cc index a309877..aedd553 100644 --- a/juci/notebook.cc +++ b/juci/notebook.cc @@ -9,90 +9,17 @@ namespace sigc { SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE } -Notebook::View::View() { - pack2(notebook); - set_position(120); -} - -Notebook::Controller::Controller() : - directories() { +Notebook::Notebook() : Gtk::Notebook() { INFO("Create notebook"); Gsv::init(); - clipboard = Gtk::Clipboard::get(); - view.pack1(directories.widget(), true, true); - CreateKeybindings(); - entry_box.signal_hide().connect([this]() { - if(CurrentPage()!=-1) { - CurrentSourceView()->grab_focus(); - } - }); - view.notebook.signal_switch_page().connect([this](Gtk::Widget* page, guint page_num) { - if(search_entry_shown && entry_box.labels.size()>0 && CurrentPage()!=-1) { - CurrentSourceView()->update_search_occurrences=[this](int number){ - entry_box.labels.begin()->update(0, std::to_string(number)); - }; - CurrentSourceView()->search_highlight(last_search, case_sensitive_search, regex_search); - } - - if(CurrentPage()!=-1) { - if(auto menu_item=dynamic_cast(Singleton::menu()->ui_manager->get_widget("/MenuBar/SourceMenu/SourceGotoDeclaration"))) - menu_item->set_sensitive((bool)CurrentSourceView()->get_declaration_location); - - if(auto menu_item=dynamic_cast(Singleton::menu()->ui_manager->get_widget("/MenuBar/SourceMenu/SourceGotoMethod"))) - menu_item->set_sensitive((bool)CurrentSourceView()->goto_method); - - if(auto menu_item=dynamic_cast(Singleton::menu()->ui_manager->get_widget("/MenuBar/SourceMenu/SourceRename"))) - menu_item->set_sensitive((bool)CurrentSourceView()->rename_similar_tokens); - } - }); - INFO("Notebook Controller Success"); -} // Constructor - -void Notebook::Controller::CreateKeybindings() { auto menu=Singleton::menu(); INFO("Notebook create signal handlers"); - directories.m_TreeView.signal_row_activated().connect(sigc::mem_fun(*this, &Notebook::Controller::OnDirectoryNavigation)); - menu->action_group->add(Gtk::Action::create("FileMenu", "File")); - menu->action_group->add(Gtk::Action::create("FileNewFile", "New file"), Gtk::AccelKey(menu->key_map["new_file"]), [this]() { - OnFileNewFile(); - }); menu->action_group->add(Gtk::Action::create("WindowCloseTab", "Close tab"), Gtk::AccelKey(menu->key_map["close_tab"]), [this]() { close_current_page(); }); - menu->action_group->add(Gtk::Action::create("EditFind", "Find"), Gtk::AccelKey(menu->key_map["edit_find"]), [this]() { - show_search_and_replace(); - }); - menu->action_group->add(Gtk::Action::create("EditCopy", "Copy"), Gtk::AccelKey(menu->key_map["edit_copy"]), [this]() { - auto window=(Gtk::Window*)view.get_toplevel(); - auto widget=window->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(clipboard); - }); - menu->action_group->add(Gtk::Action::create("EditCut", "Cut"), Gtk::AccelKey(menu->key_map["edit_cut"]), [this]() { - auto window=(Gtk::Window*)view.get_toplevel(); - auto widget=window->get_focus(); - if(auto entry=dynamic_cast(widget)) - entry->cut_clipboard(); - else { - if (Pages() != 0) - CurrentSourceView()->get_buffer()->cut_clipboard(clipboard); - } - }); - menu->action_group->add(Gtk::Action::create("EditPaste", "Paste"), Gtk::AccelKey(menu->key_map["edit_paste"]), [this]() { - auto window=(Gtk::Window*)view.get_toplevel(); - auto widget=window->get_focus(); - if(auto entry=dynamic_cast(widget)) - entry->paste_clipboard(); - else { - if (Pages() != 0) - CurrentSourceView()->get_buffer()->paste_clipboard(clipboard); - } - }); menu->action_group->add(Gtk::Action::create("EditUndo", "Undo"), Gtk::AccelKey(menu->key_map["edit_undo"]), [this]() { INFO("On undo"); @@ -135,153 +62,14 @@ void Notebook::Controller::CreateKeybindings() { } } }); - - menu->action_group->add(Gtk::Action::create("SourceRename", "Rename function/variable"), Gtk::AccelKey(menu->key_map["source_rename"]), [this]() { - entry_box.clear(); - if(CurrentPage()!=-1) { - if(CurrentSourceView()->get_token && CurrentSourceView()->get_token_name) { - auto token=std::make_shared(CurrentSourceView()->get_token()); - if(token->size()>0 && CurrentSourceView()->get_token_name) { - auto token_name=std::make_shared(CurrentSourceView()->get_token_name()); - for(int c=0;cview->tag_similar_tokens) { - source_views.at(c)->view->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(CurrentPage()!=-1 && content!=*token_name) { - for(int c=0;cview->rename_similar_tokens) { - auto number=source_views.at(c)->view->rename_similar_tokens(*token, content); - if(number>0) { - Singleton::terminal()->print("Replaced "+std::to_string(number)+" occurrences in file "+source_views.at(c)->view->file_path+"\n"); - 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(); - } - } - } - }); - - INFO("Notebook signal handlers sucsess"); -} - -void Notebook::Controller::show_search_and_replace() { - entry_box.clear(); - entry_box.labels.emplace_back(); - auto label_it=entry_box.labels.begin(); - label_it->update=[label_it](int state, const std::string& message){ - if(state==0) { - int number=stoi(message); - if(number==0) - label_it->set_text(""); - else if(number==1) - label_it->set_text("1 result found"); - else if(number>1) - label_it->set_text(std::to_string(number)+" results found"); - } - }; - entry_box.entries.emplace_back(last_search, [this](const std::string& content){ - if(CurrentPage()!=-1) - CurrentSourceView()->search_forward(); - }); - auto search_entry_it=entry_box.entries.begin(); - search_entry_it->set_placeholder_text("Find"); - if(CurrentPage()!=-1) { - CurrentSourceView()->update_search_occurrences=[label_it](int number){ - label_it->update(0, std::to_string(number)); - }; - CurrentSourceView()->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(CurrentPage()!=-1) - CurrentSourceView()->search_backward(); - } - return false; - }); - search_entry_it->signal_changed().connect([this, search_entry_it](){ - last_search=search_entry_it->get_text(); - if(CurrentPage()!=-1) - CurrentSourceView()->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(CurrentPage()!=-1) - CurrentSourceView()->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(CurrentPage()!=-1) - CurrentSourceView()->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(); - }); - - entry_box.buttons.emplace_back("Find", [this](){ - if(CurrentPage()!=-1) - CurrentSourceView()->search_forward(); - }); - entry_box.buttons.emplace_back("Replace", [this, replace_entry_it](){ - if(CurrentPage()!=-1) - CurrentSourceView()->replace_forward(replace_entry_it->get_text()); - }); - entry_box.buttons.emplace_back("Replace all", [this, replace_entry_it](){ - if(CurrentPage()!=-1) - CurrentSourceView()->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(CurrentPage()!=-1) - CurrentSourceView()->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(CurrentPage()!=-1) - CurrentSourceView()->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; - source_views.at(c)->view->search_highlight("", case_sensitive_search, regex_search); - } - search_entry_shown=false; - }); - search_entry_shown=true; - entry_box.show(); } -void Notebook::Controller::open_file(std::string path) { +void Notebook::open_file(std::string path) { INFO("Notebook open file"); INFO("Notebook create page"); for(int c=0;cview->file_path) { - view.notebook.set_current_page(c); + set_current_page(c); return; } } @@ -293,10 +81,10 @@ void Notebook::Controller::open_file(std::string path) { boost::filesystem::path file_path(source_views.back()->view->file_path); std::string title=file_path.filename().string(); - view.notebook.append_page(*hboxes.back(), title); - view.notebook.show_all_children(); - view.notebook.set_current_page(Pages()-1); - view.notebook.set_focus_child(*source_views.back()->view); + 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); //Add star on tab label when the page is not saved: auto source_view=CurrentSourceView(); @@ -313,142 +101,42 @@ void Notebook::Controller::open_file(std::string path) { } } if(page!=-1) - view.notebook.set_tab_label_text(*(view.notebook.get_nth_page(page)), title); + set_tab_label_text(*(get_nth_page(page)), title); }); } -bool Notebook::Controller::close_current_page() { +bool Notebook::close_current_page() { INFO("Notebook close page"); if (Pages() != 0) { if(CurrentSourceView()->get_buffer()->get_modified()){ - if(!save_dialog()) + if(!save_modified_dialog()) return false; } int page = CurrentPage(); - view.notebook.remove_page(page); + remove_page(page); source_views.erase(source_views.begin()+ page); scrolled_windows.erase(scrolled_windows.begin()+page); hboxes.erase(hboxes.begin()+page); } return true; } -void Notebook::Controller::OnFileNewFile() { - entry_box.clear(); - entry_box.entries.emplace_back("untitled", [this](const std::string& content){ - std::string filename=content; - if(filename!="") { - if(project_path!="" && !boost::filesystem::path(filename).is_absolute()) - filename=project_path+"/"+filename; - boost::filesystem::path p(filename); - if(boost::filesystem::exists(p)) { - Singleton::terminal()->print("Error: "+p.string()+" already exists.\n"); - } - else { - std::ofstream f(p.string().c_str()); - if(f) { - open_file(boost::filesystem::canonical(p).string()); - Singleton::terminal()->print("New file "+p.string()+" created.\n"); - if(project_path!="") - directories.open_folder(project_path); //TODO: Do refresh instead - } - else { - Singleton::terminal()->print("Error: could not create new file "+p.string()+".\n"); - } - f.close(); - } - } - entry_box.hide(); - }); - auto entry_it=entry_box.entries.begin(); - entry_box.buttons.emplace_back("Create file", [this, entry_it](){ - entry_it->activate(); - }); - entry_box.show(); -} -void Notebook::Controller -::OnDirectoryNavigation(const Gtk::TreeModel::Path& path, - Gtk::TreeViewColumn* column) { - INFO("Notebook 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(); - open_file(file); - } - } -} - -Source::View* Notebook::Controller::CurrentSourceView() { +Source::View* Notebook::CurrentSourceView() { INFO("Getting sourceview"); return source_views.at(CurrentPage())->view.get(); } -int Notebook::Controller::CurrentPage() { - return view.notebook.get_current_page(); -} - -int Notebook::Controller::Pages() { - return view.notebook.get_n_pages(); +int Notebook::CurrentPage() { + return get_current_page(); } -bool Notebook::Controller:: OnSaveFile(std::string path) { - INFO("Notebook save file with path"); - if (path != "" && CurrentSourceView()->get_buffer()->get_modified()) { - std::ofstream file; - file.open (path); - file << CurrentSourceView()->get_buffer()->get_text(); - file.close(); - boost::filesystem::path path(CurrentSourceView()->file_path); - std::string title=path.filename().string(); - CurrentSourceView()->get_buffer()->set_modified(false); - return true; - } - return false; -} - - -std::string Notebook::Controller::OnSaveFileAs(){ - INFO("Notebook save as"); - Gtk::FileChooserDialog dialog((Gtk::Window&)(*view.get_toplevel()), "Please choose a file", - Gtk::FILE_CHOOSER_ACTION_SAVE); - DEBUG("SET TRANSISTEN FPR"); - dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); - dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); - dialog.add_button("_Save", Gtk::RESPONSE_OK); - //dialog.set_current_name("Untitled"); - DEBUG("RUN DIALOG"); - int result = dialog.run(); - DEBUG("DIALOG RUNNING"); - switch (result) { - case(Gtk::RESPONSE_OK): { - DEBUG("get_filename()"); - std::string path = dialog.get_filename(); - return path; - } - case(Gtk::RESPONSE_CANCEL): { - break; - } - default: { - DEBUG("Unexpected button clicked."); - break; - } - } - return ""; +int Notebook::Pages() { + return get_n_pages(); } -bool Notebook::Controller::save_dialog() { - INFO("Notebook::Controller::save_dialog"); - Gtk::MessageDialog dialog((Gtk::Window&)(*view.get_toplevel()), "Save file!", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_YES_NO); +bool Notebook::save_modified_dialog() { + INFO("Notebook::save_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+" ?"); int result = dialog.run(); if(result==Gtk::RESPONSE_YES) { diff --git a/juci/notebook.h b/juci/notebook.h index 46ce462..0f8f356 100644 --- a/juci/notebook.h +++ b/juci/notebook.h @@ -12,46 +12,21 @@ #include #include "clangmm.h" -namespace Notebook { - class View : public Gtk::Paned { - public: - View(); - Gtk::Notebook notebook; - }; - class Controller { - public: - Controller(); - Source::View* CurrentSourceView(); - int CurrentPage(); - bool close_current_page(); - void OnFileNewFile(); - bool OnSaveFile(std::string path); - void OnDirectoryNavigation(const Gtk::TreeModel::Path& path, - Gtk::TreeViewColumn* column); - void open_file(std::string filename); - int Pages(); - View view; - std::string OnSaveFileAs(); - std::string project_path; - Directories::Controller directories; //Todo: make private after creating open_directory() - - EntryBox entry_box; - void show_search_and_replace(); - std::string last_search; - std::string last_replace; - bool case_sensitive_search=true; - bool regex_search=false; - bool search_entry_shown=false; - sigc::connection delayed_search_label_update; - - std::vector > source_views; - private: - void CreateKeybindings(); - bool save_dialog(); +class Notebook : public Gtk::Notebook { +public: + Notebook(); + Source::View* CurrentSourceView(); + int CurrentPage(); + bool close_current_page(); + void open_file(std::string filename); + int Pages(); + std::string project_path; + + std::vector > source_views; +private: + bool save_modified_dialog(); - std::vector > scrolled_windows; - std::vector > hboxes; - Glib::RefPtr clipboard; - }; // class controller -} // namespace Notebook + std::vector > scrolled_windows; + std::vector > hboxes; +}; #endif // JUCI_NOTEBOOK_H_ diff --git a/juci/singletons.cc b/juci/singletons.cc index d2c82f8..b9c19bd 100644 --- a/juci/singletons.cc +++ b/juci/singletons.cc @@ -5,18 +5,12 @@ std::unique_ptr Singleton::Config::terminal_=std::unique_ptr Singleton::Config::directories_=std::unique_ptr(new Directories::Config()); std::unique_ptr Singleton::terminal_=std::unique_ptr(); -std::unique_ptr Singleton::notebook_=std::unique_ptr(); std::unique_ptr Singleton::menu_=std::unique_ptr(); Terminal::Controller *Singleton::terminal() { if(!terminal_) terminal_=std::unique_ptr(new Terminal::Controller()); return terminal_.get(); } -Notebook::Controller *Singleton::notebook() { - if(!notebook_) - notebook_=std::unique_ptr(new Notebook::Controller()); - return notebook_.get(); -} Menu *Singleton::menu() { if(!menu_) menu_=std::unique_ptr(new Menu()); diff --git a/juci/singletons.h b/juci/singletons.h index 09cd50a..be8240a 100644 --- a/juci/singletons.h +++ b/juci/singletons.h @@ -21,11 +21,9 @@ public: }; static Terminal::Controller *terminal(); - static Notebook::Controller *notebook(); static Menu *menu(); private: static std::unique_ptr terminal_; - static std::unique_ptr notebook_; static std::unique_ptr menu_; }; diff --git a/juci/window.cc b/juci/window.cc index b223d8d..72194c1 100644 --- a/juci/window.cc +++ b/juci/window.cc @@ -6,87 +6,192 @@ namespace sigc { SIGC_FUNCTORS_DEDUCE_RESULT_TYPE_WITH_DECLTYPE } -Window::Window() : - window_box_(Gtk::ORIENTATION_VERTICAL) { +Window::Window() : notebook(), plugin_api(¬ebook), 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(window_box_); + add(box); + //TODO: see TODO Window::on_directory_navigation + directories.m_TreeView.signal_row_activated().connect(sigc::mem_fun(*this, &Window::on_directory_navigation)); auto menu=Singleton::menu(); menu->action_group->add(Gtk::Action::create("FileQuit", "Quit juCi++"), Gtk::AccelKey(menu->key_map["quit"]), [this]() { hide(); }); + menu->action_group->add(Gtk::Action::create("FileNewFile", "New file"), Gtk::AccelKey(menu->key_map["new_file"]), [this]() { + new_file_entry(); + }); menu->action_group->add(Gtk::Action::create("FileOpenFile", "Open file"), Gtk::AccelKey(menu->key_map["open_file"]), [this]() { - OnOpenFile(); + open_file_dialog(); }); menu->action_group->add(Gtk::Action::create("FileOpenFolder", "Open folder"), Gtk::AccelKey(menu->key_map["open_folder"]), [this]() { - OnFileOpenFolder(); + open_folder_dialog(); }); menu->action_group->add(Gtk::Action::create("FileSaveAs", "Save as"), Gtk::AccelKey(menu->key_map["save_as"]), [this]() { - SaveFileAs(); + save_file_dialog(); }); menu->action_group->add(Gtk::Action::create("FileSave", "Save"), Gtk::AccelKey(menu->key_map["save"]), [this]() { - SaveFile(); + notebook.CurrentSourceView()->save(); + }); + + 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)) + 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()); + } + }); + 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()); + } + }); + 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); + } + } + 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("ProjectCompileAndRun", "Compile And Run"), Gtk::AccelKey(menu->key_map["compile_and_run"]), [this]() { - SaveFile(); - if (running.try_lock()) { - std::thread execute([this]() { - std::string path = Singleton::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 = Singleton::notebook()->directories. - GetCmakeVarValue(path,"add_executable"); - Singleton::terminal()->Run(executable); - running.unlock(); - }); - execute.detach(); - } - }); + 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(); + } + }); menu->action_group->add(Gtk::Action::create("ProjectCompile", "Compile"), Gtk::AccelKey(menu->key_map["compile"]), [this]() { - SaveFile(); + if(notebook.CurrentPage()==-1) + return; + notebook.CurrentSourceView()->save(); if (running.try_lock()) { std::thread execute([this]() { - std::string path = Singleton::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(); - }); + 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(); } }); add_accel_group(menu->ui_manager->get_accel_group()); menu->build(); - - window_box_.pack_start(menu->get_widget(), Gtk::PACK_SHRINK); - - window_box_.pack_start(Singleton::notebook()->entry_box, Gtk::PACK_SHRINK); - paned_.set_position(300); - paned_.pack1(Singleton::notebook()->view, true, false); - paned_.pack2(Singleton::terminal()->view, true, true); - window_box_.pack_end(paned_); + 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(); - Singleton::notebook()->entry_box.signal_show().connect([this](){ + entry_box.signal_show().connect([this](){ std::vector focus_chain; - focus_chain.emplace_back(&Singleton::notebook()->entry_box); - window_box_.set_focus_chain(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(); + } }); - Singleton::notebook()->entry_box.signal_hide().connect([this](){ - window_box_.unset_focus_chain(); + 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"); @@ -94,7 +199,7 @@ Window::Window() : bool Window::on_key_press_event(GdkEventKey *event) { if(event->keyval==GDK_KEY_Escape) - Singleton::notebook()->entry_box.hide(); + entry_box.hide(); #ifdef __APPLE__ //For Apple's Command-left, right, up, down keys else if((event->state & GDK_META_MASK)>0) { if(event->keyval==GDK_KEY_Left) { @@ -139,17 +244,52 @@ bool Window::on_delete_event (GdkEventAny *event) { } void Window::hide() { - auto size=Singleton::notebook()->source_views.size(); + auto size=notebook.source_views.size(); for(size_t c=0;cclose_current_page()) + if(!notebook.close_current_page()) return; } Gtk::Window::hide(); } -void Window::OnFileOpenFolder() { - Gtk::FileChooserDialog dialog("Please choose a folder", - Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); +void Window::new_file_entry() { + entry_box.clear(); + entry_box.entries.emplace_back("untitled", [this](const std::string& content){ + std::string filename=content; + if(filename!="") { + if(notebook.project_path!="" && !boost::filesystem::path(filename).is_absolute()) + filename=notebook.project_path+"/"+filename; + boost::filesystem::path p(filename); + if(boost::filesystem::exists(p)) { + Singleton::terminal()->print("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(); + } + } + entry_box.hide(); + }); + auto entry_it=entry_box.entries.begin(); + entry_box.buttons.emplace_back("Create file", [this, entry_it](){ + entry_it->activate(); + }); + entry_box.show(); +} + +void Window::open_folder_dialog() { + Gtk::FileChooserDialog dialog("Please choose a folder", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); + if(notebook.project_path.size()>0) + gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), notebook.project_path.c_str()); dialog.set_transient_for(*this); //Add response buttons the the dialog: dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); @@ -157,31 +297,18 @@ void Window::OnFileOpenFolder() { int result = dialog.run(); - //Handle the response: - switch(result) - { - case(Gtk::RESPONSE_OK): - { - std::string project_path=dialog.get_filename(); - Singleton::notebook()->project_path=project_path; - Singleton::notebook()->directories.open_folder(project_path); - break; - } - case(Gtk::RESPONSE_CANCEL): - { - break; - } - default: - { - break; - } - } + if(result==Gtk::RESPONSE_OK) { + std::string project_path=dialog.get_filename(); + notebook.project_path=project_path; + directories.open_folder(project_path); + } } - -void Window::OnOpenFile() { - Gtk::FileChooserDialog dialog("Please choose a file", - Gtk::FILE_CHOOSER_ACTION_OPEN); +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); @@ -209,31 +336,151 @@ void Window::OnOpenFile() { int result = dialog.run(); - switch (result) { - case(Gtk::RESPONSE_OK): { + if(result==Gtk::RESPONSE_OK) { std::string path = dialog.get_filename(); - Singleton::notebook()->open_file(path); - break; - } - case(Gtk::RESPONSE_CANCEL): { - break; - } - default: { - break; + notebook.open_file(path); } +} + +void Window::save_file_dialog() { + 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()); + dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); + dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); + dialog.add_button("_Save", Gtk::RESPONSE_OK); + + int result = dialog.run(); + if(result==Gtk::RESPONSE_OK) { + auto path = dialog.get_filename(); + if(path.size()>0) { + std::ofstream file(path); + if(file) { + file << notebook.CurrentSourceView()->get_buffer()->get_text(); + file.close(); + notebook.open_file(path); + Singleton::terminal()->print("File saved to: " + notebook.CurrentSourceView()->file_path+"\n"); + if(notebook.project_path!="") + directories.open_folder(notebook.project_path); //TODO: Do refresh instead + } + else + Singleton::terminal()->print("Error saving file\n"); + } } } -//TODO: Move to notebook. Maybe also replace bool with void? -bool Window::SaveFile() { - return Singleton::notebook()->CurrentSourceView()->save(); +//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); + } + } } -bool Window::SaveFileAs() { - if(Singleton::notebook()->OnSaveFile(Singleton::notebook()->OnSaveFileAs())){ - Singleton::terminal()->print("File saved to: " + - Singleton::notebook()->CurrentSourceView()->file_path+"\n"); - return true; + +void Window::search_and_replace_entry() { + entry_box.clear(); + entry_box.labels.emplace_back(); + auto label_it=entry_box.labels.begin(); + label_it->update=[label_it](int state, const std::string& message){ + if(state==0) { + int number=stoi(message); + if(number==0) + label_it->set_text(""); + else if(number==1) + label_it->set_text("1 result found"); + else if(number>1) + label_it->set_text(std::to_string(number)+" results found"); + } + }; + entry_box.entries.emplace_back(last_search, [this](const std::string& content){ + if(notebook.CurrentPage()!=-1) + notebook.CurrentSourceView()->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){ + label_it->update(0, std::to_string(number)); + }; + notebook.CurrentSourceView()->search_highlight(search_entry_it->get_text(), case_sensitive_search, regex_search); } - Singleton::terminal()->print("File not saved"); - return false; + 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; + }); + 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); + }); + + entry_box.entries.emplace_back(last_replace, [this](const std::string &content){ + if(notebook.CurrentPage()!=-1) + notebook.CurrentSourceView()->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; + }); + replace_entry_it->signal_changed().connect([this, replace_entry_it](){ + last_replace=replace_entry_it->get_text(); + }); + + entry_box.buttons.emplace_back("Find", [this](){ + if(notebook.CurrentPage()!=-1) + notebook.CurrentSourceView()->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()); + }); + entry_box.buttons.emplace_back("Replace all", [this, replace_entry_it](){ + if(notebook.CurrentPage()!=-1) + notebook.CurrentSourceView()->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); + }; + 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); + }; + 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; + }); + search_entry_shown=true; + entry_box.show(); } diff --git a/juci/window.h b/juci/window.h index 1341cca..21dc235 100644 --- a/juci/window.h +++ b/juci/window.h @@ -2,28 +2,39 @@ #define JUCI_WINDOW_H_ #include "api.h" -#include "config.h" #include class Window : public Gtk::Window { public: Window(); - Gtk::Box window_box_; - MainConfig main_config; - PluginApi api; + Notebook notebook; + Directories::Controller directories; protected: bool on_key_press_event(GdkEventKey *event); bool on_delete_event (GdkEventAny *event); private: + Gtk::Box box; + Gtk::VPaned vpaned; + Gtk::Paned directory_and_notebook_panes; + EntryBox entry_box; + PluginApi plugin_api; std::mutex running; - Gtk::VPaned paned_; - //signal handlers + void hide(); - void OnOpenFile(); - void OnFileOpenFolder(); - bool SaveFile(); - bool SaveFileAs(); + 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(); + std::string last_search; + std::string last_replace; + bool case_sensitive_search=true; + bool regex_search=false; + bool search_entry_shown=false; + }; #endif // JUCI_WINDOW_H