diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 3cbdb24..deec0b9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -88,13 +88,18 @@ set(source_files juci.h tooltips.cc singletons.h singletons.cc + dialogs.h cmake.h cmake.cc) if(MSYS) - list(APPEND source_files terminal_win.cc) + list(APPEND source_files terminal_win.cc dialogs_win.cc) + list(APPEND source_files dialogs_win.cc) + message("MSYS detected") else() - list(APPEND source_files terminal.cc) + list(APPEND source_files terminal.cc dialogs.cc) + list(APPEND source_files dialogs.cc) + message("UNIX detected") endif() if(${validation}) diff --git a/src/dialogs.cc b/src/dialogs.cc new file mode 100644 index 0000000..8ff3882 --- /dev/null +++ b/src/dialogs.cc @@ -0,0 +1,50 @@ +#include "dialogs.h" +#include "singletons.h" +#include +#include + +std::string open_dialog(const std::string &title, + const std::vector> buttons, + Gtk::FileChooserAction gtk_options) { + Gtk::FileChooserDialog dialog(title, gtk_options); + if(Singleton::directories()->current_path!="") + gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), Singleton::directories()->current_path.string().c_str()); + else + gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); + dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); + // dialog.set_transient_for(parent); TODO add parent + for (auto &button : buttons) + dialog.add_button(button.first, button.second); + return dialog.run() == Gtk::RESPONSE_OK ? dialog.get_filename() : ""; +} + + +std::string Dialog::select_folder() { + return open_dialog("Please choose a folder", + {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Open", Gtk::RESPONSE_OK)}, + Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); +} + +std::string Dialog::new_file() { + return open_dialog("Please create a new file", + {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL), std::make_pair("Save", Gtk::RESPONSE_OK)}, + Gtk::FILE_CHOOSER_ACTION_SAVE); +} + +std::string Dialog::new_folder() { + return open_dialog("Please create a new folder", + {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Create", Gtk::RESPONSE_OK)}, + Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER); +} + +std::string Dialog::select_file() { + return open_dialog("Please choose a folder", + {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Select", Gtk::RESPONSE_OK)}, + Gtk::FILE_CHOOSER_ACTION_OPEN); +} + +std::string Dialog::save_file() { + return open_dialog("Please choose a file", + {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Save", Gtk::RESPONSE_OK)}, + Gtk::FILE_CHOOSER_ACTION_OPEN); +} \ No newline at end of file diff --git a/src/dialogs.h b/src/dialogs.h new file mode 100644 index 0000000..5acf6ea --- /dev/null +++ b/src/dialogs.h @@ -0,0 +1,14 @@ +#ifndef JUCI_DIALOG_H_ +#define JUCI_DIALOG_H_ +#include + +class Dialog { + public: + static std::string select_folder(); + static std::string select_file(); + static std::string new_file(); + static std::string new_folder(); + static std::string save_file(); +}; // namespace Dialog + +#endif // JUCI_DIALOG_H_ \ No newline at end of file diff --git a/src/dialogs_win.cc b/src/dialogs_win.cc new file mode 100644 index 0000000..f245f31 --- /dev/null +++ b/src/dialogs_win.cc @@ -0,0 +1,52 @@ +#include "dialogs.h" +#include +#include + +std::string Dialog::select_folder() { + char selected_folder[MAX_PATH]; + char init_path[MAX_PATH]; + auto title = "Please select a folder"; + selected_folder[0] = 0; + init_path[0] = 0; + + BROWSEINFOA browse; + browse.hwndOwner = 0; + browse.pidlRoot = NULL; + browse.lpszTitle = title; + browse.pszDisplayName = init_path; + browse.ulFlags = 0; + browse.lpfn = NULL; + auto result = SHBrowseForFolder(&browse); + + if(result) + SHGetPathFromIDListA(result, selected_folder); + + std::string dir(selected_folder); + return dir; +} +/* +std::string Dialog::new_file() { + return open_dialog("Please create a new file", + {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL), std::make_pair("Save", Gtk::RESPONSE_OK)}, + Gtk::FILE_CHOOSER_ACTION_SAVE); +} + +std::string Dialog::new_folder() { + return open_dialog("Please create a new folder", + {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Create", Gtk::RESPONSE_OK)}, + Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER); +} + +std::string Dialog::select_file() { + return open_dialog("Please choose a folder", + {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Select", Gtk::RESPONSE_OK)}, + Gtk::FILE_CHOOSER_ACTION_OPEN); +} + +std::string Dialog::save_file() { + return open_dialog("Please choose a file", + {std::make_pair("Cancel", Gtk::RESPONSE_CANCEL),std::make_pair("Save", Gtk::RESPONSE_OK)}, + Gtk::FILE_CHOOSER_ACTION_OPEN); +} + +*/ \ No newline at end of file diff --git a/src/juci.cc b/src/juci.cc index a97b8ee..c83eb47 100644 --- a/src/juci.cc +++ b/src/juci.cc @@ -45,7 +45,7 @@ void app::on_activate() { bool first_directory=true; for(auto &directory: directories) { if(first_directory) { - window->directories.open(directory); + Singleton::directories()->open(directory); first_directory=false; } else { diff --git a/src/singletons.cc b/src/singletons.cc index 4633763..9040d55 100644 --- a/src/singletons.cc +++ b/src/singletons.cc @@ -5,12 +5,19 @@ std::unique_ptr Singleton::Config::directories_=std::unique std::unique_ptr Singleton::Config::terminal_=std::unique_ptr(new Terminal::Config()); std::unique_ptr Singleton::Config::window_ = std::unique_ptr(new Window::Config()); std::unique_ptr Singleton::terminal_=std::unique_ptr(); +std::unique_ptr Singleton::directories_=std::unique_ptr(); Terminal *Singleton::terminal() { if(!terminal_) terminal_=std::unique_ptr(new Terminal()); return terminal_.get(); } + +Directories *Singleton::directories() { + if(!directories_) + directories_=std::unique_ptr(new Directories()); + return directories_.get(); +} std::unique_ptr Singleton::status_=std::unique_ptr(); Gtk::Label *Singleton::status() { if(!status_) diff --git a/src/singletons.h b/src/singletons.h index 8fa6a86..33297ea 100644 --- a/src/singletons.h +++ b/src/singletons.h @@ -30,12 +30,14 @@ public: static std::string log_dir() { return std::string(getenv("HOME")) + "/.juci/log/"; } static std::string style_dir() { return std::string(getenv("HOME")) + "/.juci/styles/"; } static Terminal *terminal(); + static Directories *directories(); static Gtk::Label *status(); static Gtk::Label *info(); private: static std::unique_ptr terminal_; static std::unique_ptr status_; static std::unique_ptr info_; + static std::unique_ptr directories_; }; #endif // JUCI_SINGLETONS_H_ diff --git a/src/window.cc b/src/window.cc index 13bfa5a..0daf779 100644 --- a/src/window.cc +++ b/src/window.cc @@ -5,6 +5,7 @@ #include "config.h" //#include "api.h" #include +#include "dialogs.h" #include //TODO: remove using namespace std; //TODO: remove @@ -30,7 +31,7 @@ void Window::generate_keybindings() { } } -Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compiling(false) { +Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(*Singleton::directories()), compiling(false) { DEBUG("start"); set_title("juCi++"); set_default_size(600, 400); @@ -42,7 +43,7 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil create_menu(); box.pack_start(menu.get_widget(), Gtk::PACK_SHRINK); - directory_and_notebook_panes.pack1(directories, Gtk::SHRINK); + directory_and_notebook_panes.pack1(*Singleton::directories(), Gtk::SHRINK); notebook_vbox.pack_start(notebook); notebook_vbox.pack_end(entry_box, Gtk::PACK_SHRINK); directory_and_notebook_panes.pack2(notebook_vbox, Gtk::SHRINK); @@ -60,7 +61,7 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil box.pack_end(vpaned); show_all_children(); - directories.on_row_activated=[this](const std::string &file) { + Singleton::directories()->on_row_activated=[this](const std::string &file) { notebook.open(file); }; @@ -100,7 +101,7 @@ Window::Window() : box(Gtk::ORIENTATION_VERTICAL), notebook(directories), compil if(auto menu_item=dynamic_cast(menu.ui_manager->get_widget("/MenuBar/SourceMenu/SourceRename"))) menu_item->set_sensitive((bool)notebook.get_current_view()->rename_similar_tokens); - directories.select(notebook.get_current_view()->file_path); + Singleton::directories()->select(notebook.get_current_view()->file_path); if(auto source_view=dynamic_cast(notebook.get_current_view())) { if(source_view->reparse_needed) { @@ -140,23 +141,86 @@ void Window::create_menu() { hide(); }); menu.action_group->add(Gtk::Action::create("FileNewFile", "New File"), Gtk::AccelKey(menu.key_map["new_file"]), [this]() { - new_file_dialog(); + boost::filesystem::path path = Dialog::new_file(); + if(path!="") { + if(boost::filesystem::exists(path)) { + Singleton::terminal()->print("Error: "+path.string()+" already exists.\n"); + } + else { + if(juci::filesystem::write(path)) { + if(Singleton::directories()->current_path!="") + Singleton::directories()->update(); + notebook.open(path.string()); + Singleton::terminal()->print("New file "+path.string()+" created.\n"); + } + else + Singleton::terminal()->print("Error: could not create new file "+path.string()+".\n"); + } + } }); menu.action_group->add(Gtk::Action::create("FileNewFolder", "New Folder"), Gtk::AccelKey(menu.key_map["new_folder"]), [this]() { - new_folder_dialog(); + auto time_now=std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); + boost::filesystem::path path = Dialog::new_folder(); + if(boost::filesystem::last_write_time(path)>=time_now) { + if(Singleton::directories()->current_path!="") + Singleton::directories()->update(); + Singleton::terminal()->print("New folder "+path.string()+" created.\n"); + } + else + Singleton::terminal()->print("Error: "+path.string()+" already exists.\n"); + Singleton::directories()->select(path); }); menu.action_group->add(Gtk::Action::create("FileNewProject", "New Project")); menu.action_group->add(Gtk::Action::create("FileNewProjectCpp", "C++"), [this]() { - new_cpp_project_dialog(); + boost::filesystem::path project_path = Dialog::new_folder(); + auto project_name=project_path.filename().string(); + for(size_t c=0;cprint("Error: "+cmakelists_path.string()+" already exists.\n"); + return; + } + if(boost::filesystem::exists(cpp_main_path)) { + Singleton::terminal()->print("Error: "+cpp_main_path.string()+" already exists.\n"); + return; + } + std::string cmakelists="cmake_minimum_required(VERSION 2.8)\n\nproject("+project_name+")\n\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++1y -Wall\")\n\nadd_executable("+project_name+" main.cpp)\n"; + std::string cpp_main="#include \n\nusing namespace std;\n\nint main() {\n cout << \"Hello World!\" << endl;\n\n return 0;\n}\n"; + if(juci::filesystem::write(cmakelists_path, cmakelists) && juci::filesystem::write(cpp_main_path, cpp_main)) { + Singleton::directories()->open(project_path); + notebook.open(cpp_main_path); + Singleton::terminal()->print("C++ project "+project_name+" created.\n"); + } + else + Singleton::terminal()->print("Error: Could not create project "+project_path.string()+"\n"); }); menu.action_group->add(Gtk::Action::create("FileOpenFile", "Open File"), Gtk::AccelKey(menu.key_map["open_file"]), [this]() { - open_file_dialog(); + notebook.open(Dialog::select_file()); }); menu.action_group->add(Gtk::Action::create("FileOpenFolder", "Open Folder"), Gtk::AccelKey(menu.key_map["open_folder"]), [this]() { - open_folder_dialog(); + Singleton::directories()->open(Dialog::select_folder()); }); menu.action_group->add(Gtk::Action::create("FileSaveAs", "Save As"), Gtk::AccelKey(menu.key_map["save_as"]), [this]() { - save_file_dialog(); + auto path = Dialog::save_file(); + if(path.size()>0) { + std::ofstream file(path); + if(file) { + file << notebook.get_current_view()->get_buffer()->get_text(); + file.close(); + if(Singleton::directories()->current_path!="") + Singleton::directories()->update(); + notebook.open(path); + Singleton::terminal()->print("File saved to: " + notebook.get_current_view()->file_path.string()+"\n"); + } + else + Singleton::terminal()->print("Error saving file\n"); + } }); menu.action_group->add(Gtk::Action::create("FileSave", "Save"), Gtk::AccelKey(menu.key_map["save"]), [this]() { @@ -301,7 +365,7 @@ void Window::create_menu() { if(content!="") { last_run_command=content; Singleton::terminal()->async_print("Running: "+content+'\n'); - Singleton::terminal()->async_execute(content, directories.current_path, [this, content](int exit_code){ + Singleton::terminal()->async_execute(content, Singleton::directories()->current_path, [this, content](int exit_code){ Singleton::terminal()->async_print(content+" returned: "+boost::lexical_cast(exit_code)+'\n'); }); } @@ -388,173 +452,6 @@ void Window::hide() { Gtk::Window::hide(); } -void Window::new_file_dialog() { - Gtk::FileChooserDialog dialog("Please create a new file", Gtk::FILE_CHOOSER_ACTION_SAVE); - if(directories.current_path!="") - gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), directories.current_path.string().c_str()); - else - gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); - dialog.set_transient_for(*this); - 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) { - boost::filesystem::path path = dialog.get_filename(); - if(path!="") { - if(boost::filesystem::exists(path)) { - Singleton::terminal()->print("Error: "+path.string()+" already exists.\n"); - } - else { - if(juci::filesystem::write(path)) { - if(directories.current_path!="") - directories.update(); - notebook.open(path.string()); - Singleton::terminal()->print("New file "+path.string()+" created.\n"); - } - else - Singleton::terminal()->print("Error: could not create new file "+path.string()+".\n"); - } - } - } -} - -void Window::new_folder_dialog() { - auto time_now=std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()); - Gtk::FileChooserDialog dialog("Please create a new folder", Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER); - if(directories.current_path!="") - gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), directories.current_path.string().c_str()); - else - gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); - dialog.set_transient_for(*this); - dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); - dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); - dialog.add_button("Create", Gtk::RESPONSE_OK); - - int result = dialog.run(); - if(result==Gtk::RESPONSE_OK) { - boost::filesystem::path path=dialog.get_filename(); - if(boost::filesystem::last_write_time(path)>=time_now) { - if(directories.current_path!="") - directories.update(); - Singleton::terminal()->print("New folder "+path.string()+" created.\n"); - } - else - Singleton::terminal()->print("Error: "+path.string()+" already exists.\n"); - directories.select(path); - } -} - -void Window::new_cpp_project_dialog() { - Gtk::FileChooserDialog dialog("Please create and/or choose a folder", Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER); - if(directories.current_path!="") - gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), directories.current_path.string().c_str()); - else - gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); - dialog.set_transient_for(*this); - dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); - dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); - dialog.add_button("Create", Gtk::RESPONSE_OK); - - int result = dialog.run(); - if(result==Gtk::RESPONSE_OK) { - boost::filesystem::path project_path=dialog.get_filename(); - auto project_name=project_path.filename().string(); - for(size_t c=0;cprint("Error: "+cmakelists_path.string()+" already exists.\n"); - return; - } - if(boost::filesystem::exists(cpp_main_path)) { - Singleton::terminal()->print("Error: "+cpp_main_path.string()+" already exists.\n"); - return; - } - std::string cmakelists="cmake_minimum_required(VERSION 2.8)\n\nproject("+project_name+")\n\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} -std=c++1y -Wall\")\n\nadd_executable("+project_name+" main.cpp)\n"; - std::string cpp_main="#include \n\nusing namespace std;\n\nint main() {\n cout << \"Hello World!\" << endl;\n\n return 0;\n}\n"; - if(juci::filesystem::write(cmakelists_path, cmakelists) && juci::filesystem::write(cpp_main_path, cpp_main)) { - directories.open(project_path); - notebook.open(cpp_main_path); - Singleton::terminal()->print("C++ project "+project_name+" created.\n"); - } - else - Singleton::terminal()->print("Error: Could not create project "+project_path.string()+"\n"); - } -} - -void Window::open_folder_dialog() { - Gtk::FileChooserDialog dialog("Please choose a folder", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER); - if(directories.current_path!="") - gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), directories.current_path.string().c_str()); - else - gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); - dialog.set_transient_for(*this); - dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); - dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); - dialog.add_button("Open", Gtk::RESPONSE_OK); - - int result = dialog.run(); - - if(result==Gtk::RESPONSE_OK) { - std::string project_path=dialog.get_filename(); - directories.open(project_path); - } -} - -void Window::open_file_dialog() { - Gtk::FileChooserDialog dialog("Please choose a file", Gtk::FILE_CHOOSER_ACTION_OPEN); - if(directories.current_path!="") - gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), directories.current_path.string().c_str()); - else - gtk_file_chooser_set_current_folder((GtkFileChooser*)dialog.gobj(), boost::filesystem::current_path().string().c_str()); - dialog.set_transient_for(*this); - dialog.set_position(Gtk::WindowPosition::WIN_POS_CENTER_ALWAYS); - dialog.add_button("Cancel", Gtk::RESPONSE_CANCEL); - dialog.add_button("Open", Gtk::RESPONSE_OK); - - int result = dialog.run(); - - if(result==Gtk::RESPONSE_OK) { - std::string path = dialog.get_filename(); - notebook.open(path); - } -} - -void Window::save_file_dialog() { - if(notebook.get_current_page()==-1) - return; - Gtk::FileChooserDialog dialog(*this, "Please choose a file", Gtk::FILE_CHOOSER_ACTION_SAVE); - gtk_file_chooser_set_filename((GtkFileChooser*)dialog.gobj(), notebook.get_current_view()->file_path.string().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.get_current_view()->get_buffer()->get_text(); - file.close(); - if(directories.current_path!="") - directories.update(); - notebook.open(path); - Singleton::terminal()->print("File saved to: " + notebook.get_current_view()->file_path.string()+"\n"); - } - else - Singleton::terminal()->print("Error saving file\n"); - } - } -} - void Window::search_and_replace_entry() { entry_box.clear(); entry_box.labels.emplace_back(); diff --git a/src/window.h b/src/window.h index 5c8b349..5cfb91f 100644 --- a/src/window.h +++ b/src/window.h @@ -12,7 +12,6 @@ class Window : public Gtk::Window { public: Window(); - Directories directories; Notebook notebook; class Config { public: @@ -41,12 +40,6 @@ private: void create_menu(); void hide(); - void new_file_dialog(); - void new_folder_dialog(); - void new_cpp_project_dialog(); - void open_folder_dialog(); - void open_file_dialog(); - void save_file_dialog(); void search_and_replace_entry(); void goto_line_entry(); void rename_token_entry();