NewForm.cpp

Go to the documentation of this file.
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 }

Get Racer at SourceForge.net. Fast, secure and Free Open Source software downloads

Generated at Mon Sep 6 00:41:13 2010 by Doxygen version 1.4.7 for Racer version svn335.