00001 00005 /* Copyright © 2009, 2010 James Legg. 00006 This program is free software: you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation, either version 3 of the License, or 00009 (at your option) any later version. 00010 */ 00011 #include "NewForm.h" 00012 00013 #include <gtkmm/stock.h> 00014 #include <gtkmm/messagedialog.h> 00015 00016 #include <Debug.h> 00017 00018 NewForm::NewForm(Gtk::Window & window) 00019 : Gtk::VBox(false, 2) 00020 , window(window) 00021 , caption("Loading") 00022 , create_button(Gtk::Stock::NEW) 00023 , list_model_ptr(Gtk::ListStore::create(theme_model_columns)) 00024 , m_loading(true) 00025 { 00026 // caption 00027 pack_start(caption, false, true); 00028 caption.show(); 00029 00030 // theme icon view 00031 theme_icon_view.set_model(list_model_ptr); 00032 theme_icon_view.set_text_column(0); 00033 theme_icon_view.set_pixbuf_column(1); 00034 theme_icon_view.set_tooltip_column(2); 00035 theme_icon_view.signal_item_activated().connect(sigc::mem_fun(*this, &NewForm::on_item_activated)); 00036 00037 // pack and show icon view container 00038 m_scrolled_window.add(theme_icon_view); 00039 m_scrolled_window.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); 00040 pack_start(m_scrolled_window); 00041 theme_icon_view.show(); 00042 // Show area, only to reduce flicker in normal case when themes are found. 00043 m_scrolled_window.show(); 00044 00045 // create button 00046 create_button.get_image()->show(); 00047 pack_end(create_button, false, true); 00048 create_button.signal_clicked().connect(sigc::mem_fun(*this, &NewForm::on_new_button_clicked)); 00049 // Show create button, only to reduce flicker in normal case. 00050 create_button.show(); 00051 } 00052 00053 NewForm::~NewForm() 00054 { 00055 00056 } 00057 00058 void NewForm::find_themes() 00059 { 00060 if (m_loading) 00061 { 00062 m_loading = false; 00063 // Add themes to the theme_icon_view. 00064 set_themes(); 00065 // check we found some. 00066 test_themes_avaliable(); 00067 } 00068 } 00069 00070 void NewForm::grab_focus() 00071 { 00072 theme_icon_view.grab_focus(); 00073 } 00074 00075 void NewForm::set_themes() 00076 { 00077 add_themes_from("data"); 00078 } 00079 00080 void NewForm::add_themes_from(std::string path) 00081 { 00082 DEBUG_MESSAGE("Monitoring directory " << path); 00083 try 00084 { 00085 // get file list in this directory. 00086 Glib::RefPtr<Gio::File> file = Gio::File::create_for_path(path); 00087 // monitor the directory. 00088 dir_mon.push_back(file->monitor_directory()); 00089 dir_mon.back()->signal_changed().connect(sigc::bind(sigc::mem_fun(*this, &NewForm::on_dir_changed), path)); 00090 // get the files in the directory. 00091 Glib::RefPtr<Gio::FileEnumerator> dir = file->enumerate_children("standard::*"); 00092 Glib::RefPtr<Gio::FileInfo> file_info; 00093 // iterate over files. 00094 while (file_info = dir->next_file()) 00095 { 00096 add_file(file_info, path); 00097 } 00098 dir->close(); 00099 } 00100 catch (Gio::Error err) 00101 { 00102 DEBUG_MESSAGE("Cannot access " << path << ": " << err.what()); 00103 // nevermind, path probably doesn't exist anymore. 00104 } 00105 } 00106 00107 void NewForm::on_dir_changed(const Glib::RefPtr<Gio::File>& file, 00108 const Glib::RefPtr<Gio::File>& other_file, 00109 Gio::FileMonitorEvent event_type, 00110 std::string path) 00111 { 00112 DEBUG_MESSAGE("A theme directory has changed."); 00113 Glib::RefPtr<Gio::FileInfo> file_info(file->query_info("standard:*")); 00114 switch (event_type) 00115 { 00116 case Gio::FILE_MONITOR_EVENT_CREATED: 00117 // new file, add to list or directories to check if valid. 00118 if (add_file(file_info, path)) 00119 { 00120 // redraw the list 00121 theme_icon_view.queue_draw(); 00122 test_themes_avaliable(); 00123 return; 00124 } 00125 case Gio::FILE_MONITOR_EVENT_DELETED: 00127 { 00128 Gtk::ListStore::Children children = list_model_ptr->children(); 00129 std::string name = path + '/' + file_info->get_name(); 00130 for (Gtk::ListStore::Children::iterator it = children.begin(); 00131 it != children.end(); ++it) 00132 { 00133 Gtk::TreeModel::Row row = *it; 00134 if (it->get_value(theme_model_columns.file) == name) 00135 { 00136 // Found it. 00137 // remove from list 00138 DEBUG_MESSAGE("Removing deleted file from the list."); 00139 list_model_ptr->erase(it); 00140 theme_icon_view.queue_draw(); 00141 test_themes_avaliable(); 00142 return; 00143 } 00144 } 00145 } 00146 // Cannot find it. It is probably a directory. 00147 /* It is easiest to clear the list and start again than to work 00148 * out what was in the directory. 00149 */ 00150 list_model_ptr->clear(); 00151 dir_mon.clear(); 00152 set_themes(); 00153 theme_icon_view.queue_draw(); 00154 test_themes_avaliable(); 00155 return; 00156 default: 00157 // different event, ignore. 00158 break; 00159 } 00160 } 00161 00162 void NewForm::test_themes_avaliable() 00163 { 00164 Gtk::ListStore::Children children = list_model_ptr->children(); 00165 if (children.begin() == children.end()) 00166 { 00167 // No themes. Try to explain... 00168 caption.set_text( 00169 "You have no themes available!\n\n" 00170 "You can copy theme files into a folder under racer's data directory. " 00171 "Make sure your themes are in a non-hidden file, named without any " 00172 "'.' characters, not ending in '~', and containing the word " 00173 "'theme' (case sensative). You can place themes in any number of " 00174 "folders under racer/data meeting the same restrictions.\n\n" 00175 "You can also create a new theme in Blender and export it with " 00176 "the script provided. For details, please read " 00177 "http://sourceforge.net/apps/mediawiki/racer/index.php?title=Making_themes\n\n" 00178 "You cannot create or edit a track without a theme, so until you do " 00179 "one of the above this editor is useless." 00180 ); 00181 caption.set_selectable(); 00182 caption.set_line_wrap(); 00183 // hide the icons and button 00184 m_scrolled_window.hide(); 00185 create_button.hide(); 00186 } else { 00187 // themes are avaliable 00188 caption.set_text("Please select a theme for your new track:"); 00189 caption.set_selectable(false); 00190 caption.set_line_wrap(false); 00191 // show the icons and button 00192 m_scrolled_window.show(); 00193 create_button.show(); 00194 00195 // pick the first theme. 00196 theme_icon_view.select_path(Gtk::TreeModel::Path(children.begin())); 00197 } 00198 } 00199 00200 void NewForm::on_new_button_clicked() 00201 { 00202 // If a valid theme is selected, signal it. 00203 Gtk::IconView::ArrayHandle_TreePaths selection = theme_icon_view.get_selected_items(); 00204 if (selection.size() == 1) 00205 { 00206 Gtk::TreePath path = *selection.begin(); 00207 Gtk::TreeModel::Row row = *list_model_ptr->get_iter(path); 00208 m_signal_theme_picked.emit(row->get_value(theme_model_columns.file)); 00209 } else 00210 { 00211 DEBUG_MESSAGE("Invalid selection."); 00212 Gtk::MessageDialog dialog(window, 00213 "Invalid theme selection", 00214 false, 00215 Gtk::MESSAGE_ERROR, 00216 Gtk::BUTTONS_OK, 00217 true); 00218 dialog.set_secondary_text( 00219 "You must select the theme for the new track before pressing new."); 00220 dialog.run(); 00221 } 00222 } 00223 00224 sigc::signal<void, std::string> NewForm::signal_theme_picked() 00225 { 00226 return m_signal_theme_picked; 00227 } 00228 00229 void NewForm::on_item_activated(const Gtk::TreeModel::Path & path) 00230 { 00231 Gtk::TreeModel::Row row = *list_model_ptr->get_iter(path); 00232 m_signal_theme_picked.emit(row->get_value(theme_model_columns.file)); 00233 } 00234 00235 bool NewForm::add_file(Glib::RefPtr<Gio::FileInfo> file_info, std::string path) 00236 { 00237 std::string file_name = file_info->get_name(); 00238 if ( file_info->is_hidden() 00239 || file_name.find("theme") == std::string::npos 00240 || file_name.find(".") != std::string::npos 00241 || file_name[file_name.size() - 1] == '~') 00242 { 00243 /* remove hidden files, files which don't contain the word 00244 * 'theme', files ending in ~, and files containing dots. 00245 */ 00246 return false; 00247 } 00248 switch (file_info->get_file_type()) 00249 { 00250 case Gio::FILE_TYPE_NOT_KNOWN: 00251 case Gio::FILE_TYPE_SPECIAL: 00252 case Gio::FILE_TYPE_MOUNTABLE: 00253 case Gio::FILE_TYPE_SHORTCUT: 00254 // not a theme. 00255 return false; 00256 break; 00257 case Gio::FILE_TYPE_DIRECTORY: 00258 // a directory which could contain a theme. Monitor it. 00259 add_themes_from(path + '/' + file_name); 00260 return true; 00261 break; 00262 case Gio::FILE_TYPE_REGULAR: 00263 case Gio::FILE_TYPE_SYMBOLIC_LINK: 00264 // these can be a theme. Add them to the list. 00265 std::string base_name = Glib::path_get_basename(file_name); 00266 // add to list displayed. 00267 Gtk::ListStore::iterator it = list_model_ptr->append(); 00268 (*it)[theme_model_columns.name] = file_name; 00269 (*it)[theme_model_columns.file] = path + '/' + base_name; 00270 break; 00271 } 00272 return true; 00273 }
Generated at Mon Sep 6 00:41:13 2010 by Doxygen version 1.4.7 for Racer version svn335.