/* * Copyright (c) 2002-2007 Daniel Elstner * * This file is part of regexxer. * * regexxer is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * regexxer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with regexxer; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #include "mainwindow.h" #include "filetree.h" #include "globalstrings.h" #include "pcreshell.h" #include "prefdialog.h" #include "statusline.h" #include "stringutils.h" #include "translation.h" #include #include #include #include #include #include #include #include namespace { enum { BUSY_GUI_UPDATE_INTERVAL = 16 }; typedef Glib::RefPtr FileBufferPtr; static const char *const selection_clipboard = "CLIPBOARD"; /* * List of authors to be displayed in the about dialog. */ static const char *const program_authors[] = { "Daniel Elstner ", "Murray Cumming ", 0 }; static const char *const program_license = "regexxer is free software; you can redistribute it and/or modify " "it under the terms of the GNU General Public License as published by " "the Free Software Foundation; either version 2 of the License, or " "(at your option) any later version.\n" "\n" "regexxer is distributed in the hope that it will be useful, " "but WITHOUT ANY WARRANTY; without even the implied warranty of " "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the " "GNU General Public License for more details.\n" "\n" "You should have received a copy of the GNU General Public License " "along with regexxer; if not, write to the Free Software Foundation, " "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA\n"; class FileErrorDialog : public Gtk::MessageDialog { public: FileErrorDialog(Gtk::Window& parent, const Glib::ustring& message, Gtk::MessageType type, const Regexxer::FileTree::Error& error); virtual ~FileErrorDialog(); }; FileErrorDialog::FileErrorDialog(Gtk::Window& parent, const Glib::ustring& message, Gtk::MessageType type, const Regexxer::FileTree::Error& error) : Gtk::MessageDialog(parent, message, false, type, Gtk::BUTTONS_OK, true) { using namespace Gtk; const Glib::RefPtr buffer = TextBuffer::create(); TextBuffer::iterator buffer_end = buffer->end(); typedef std::list ErrorList; const ErrorList& error_list = error.get_error_list(); for (ErrorList::const_iterator perr = error_list.begin(); perr != error_list.end(); ++perr) buffer_end = buffer->insert(buffer_end, *perr + '\n'); Box& box = *get_vbox(); Frame *const frame = new Frame(); box.pack_start(*manage(frame), PACK_EXPAND_WIDGET); frame->set_border_width(6); // HIG spacing frame->set_shadow_type(SHADOW_IN); ScrolledWindow *const scrollwin = new ScrolledWindow(); frame->add(*manage(scrollwin)); scrollwin->set_policy(POLICY_AUTOMATIC, POLICY_AUTOMATIC); TextView *const textview = new TextView(buffer); scrollwin->add(*manage(textview)); textview->set_editable(false); textview->set_cursor_visible(false); textview->set_wrap_mode(WRAP_WORD); textview->set_pixels_below_lines(8); set_default_size(400, 250); frame->show_all(); } FileErrorDialog::~FileErrorDialog() {} static void print_location(int linenumber, const Glib::ustring& subject, Regexxer::FileInfoPtr fileinfo) { std::cout << fileinfo->fullname << ':' << linenumber + 1 << ':'; std::string charset; if (Glib::get_charset(charset)) std::cout << subject.raw(); // charset is UTF-8 else std::cout << Glib::convert_with_fallback(subject.raw(), charset, "UTF-8"); std::cout << std::endl; } } // anonymous namespace namespace Regexxer { /**** Regexxer::InitState **************************************************/ InitState::InitState() : folder (), pattern (), regex (), substitution (), no_recursive (false), hidden (false), no_global (false), ignorecase (false), feedback (false), no_autorun (false) {} InitState::~InitState() {} /**** Regexxer::MainWindow::BusyAction *************************************/ class MainWindow::BusyAction { private: MainWindow& object_; BusyAction(const BusyAction&); BusyAction& operator=(const BusyAction&); public: explicit BusyAction(MainWindow& object) : object_ (object) { object_.busy_action_enter(); } ~BusyAction() { object_.busy_action_leave(); } }; /**** Regexxer::MainWindow *************************************************/ MainWindow::MainWindow() : toolbar_ (0), button_folder_ (0), entry_pattern_ (0), button_recursive_ (0), button_hidden_ (0), entry_regex_ (0), entry_substitution_ (0), button_multiple_ (0), button_caseless_ (0), filetree_ (0), textview_ (0), entry_preview_ (0), statusline_ (0), busy_action_running_ (false), busy_action_cancel_ (false), busy_action_iteration_ (0), undo_stack_ (new UndoStack()) { load_xml(); textview_->set_buffer(FileBuffer::create()); window_->set_title(PACKAGE_NAME); connect_signals(); } MainWindow::~MainWindow() {} void MainWindow::initialize(const InitState& init) { std::string folder; if (!init.folder.empty()) folder = init.folder.front(); if (!Glib::path_is_absolute(folder)) folder = Glib::build_filename(Glib::get_current_dir(), folder); const bool folder_exists = button_folder_->set_current_folder(folder); entry_pattern_->set_text((init.pattern.empty()) ? Glib::ustring(1, '*') : init.pattern); entry_regex_ ->set_text(init.regex); entry_substitution_->set_text(init.substitution); button_recursive_->set_active(!init.no_recursive); button_hidden_ ->set_active(init.hidden); button_multiple_ ->set_active(!init.no_global); button_caseless_ ->set_active(init.ignorecase); if (init.feedback) filetree_->signal_feedback.connect(&print_location); // Strangely, folder_exists seems to be always true, probably because the // file chooser works asynchronously but the GLib main loop isn't running // yet. As a work-around, explicitely check whether the directory exists // on the file system as well. if (folder_exists && !init.no_autorun && !init.folder.empty() && !init.pattern.empty() && Glib::file_test(folder, Glib::FILE_TEST_IS_DIR)) { Glib::signal_idle().connect(sigc::mem_fun(*this, &MainWindow::autorun_idle)); } } /**** Regexxer::MainWindow -- private **************************************/ void MainWindow::load_xml() { using Gnome::Glade::Xml; const Glib::RefPtr xml = Xml::create(glade_mainwindow_filename); Gtk::Window* mainwindow = 0; window_.reset(xml->get_widget("mainwindow", mainwindow)); xml->get_widget("toolbar", toolbar_); xml->get_widget("button_folder", button_folder_); xml->get_widget("button_recursive", button_recursive_); xml->get_widget("button_hidden", button_hidden_); xml->get_widget("entry_regex", entry_regex_); xml->get_widget("entry_substitution", entry_substitution_); xml->get_widget("button_multiple", button_multiple_); xml->get_widget("button_caseless", button_caseless_); xml->get_widget("filetree", filetree_); xml->get_widget("textview", textview_); xml->get_widget("entry_preview", entry_preview_); xml->get_widget("statusline", statusline_); xml->get_widget("combo_pattern_entry", entry_pattern_); controller_.load_xml(xml); } void MainWindow::connect_signals() { using sigc::bind; using sigc::mem_fun; window_->signal_hide ().connect(mem_fun(*this, &MainWindow::on_hide)); window_->signal_style_changed().connect(mem_fun(*this, &MainWindow::on_style_changed)); window_->signal_delete_event ().connect(mem_fun(*this, &MainWindow::on_delete_event)); entry_pattern_->signal_activate().connect(controller_.find_files.slot()); entry_pattern_->signal_changed ().connect(mem_fun(*this, &MainWindow::on_entry_pattern_changed)); entry_regex_ ->signal_activate().connect(controller_.find_matches.slot()); entry_substitution_->signal_activate().connect(controller_.find_matches.slot()); entry_substitution_->signal_changed ().connect(mem_fun(*this, &MainWindow::update_preview)); controller_.save_file .connect(mem_fun(*this, &MainWindow::on_save_file)); controller_.save_all .connect(mem_fun(*this, &MainWindow::on_save_all)); controller_.undo .connect(mem_fun(*this, &MainWindow::on_undo)); controller_.cut .connect(mem_fun(*this, &MainWindow::on_cut)); controller_.copy .connect(mem_fun(*this, &MainWindow::on_copy)); controller_.paste .connect(mem_fun(*this, &MainWindow::on_paste)); controller_.erase .connect(mem_fun(*this, &MainWindow::on_erase)); controller_.preferences .connect(mem_fun(*this, &MainWindow::on_preferences)); controller_.quit .connect(mem_fun(*this, &MainWindow::on_quit)); controller_.about .connect(mem_fun(*this, &MainWindow::on_about)); controller_.find_files .connect(mem_fun(*this, &MainWindow::on_find_files)); controller_.find_matches.connect(mem_fun(*this, &MainWindow::on_exec_search)); controller_.next_file .connect(bind(mem_fun(*this, &MainWindow::on_go_next_file), true)); controller_.prev_file .connect(bind(mem_fun(*this, &MainWindow::on_go_next_file), false)); controller_.next_match .connect(bind(mem_fun(*this, &MainWindow::on_go_next), true)); controller_.prev_match .connect(bind(mem_fun(*this, &MainWindow::on_go_next), false)); controller_.replace .connect(mem_fun(*this, &MainWindow::on_replace)); controller_.replace_file.connect(mem_fun(*this, &MainWindow::on_replace_file)); controller_.replace_all .connect(mem_fun(*this, &MainWindow::on_replace_all)); Gnome::Conf::Client::get_default_client() ->signal_value_changed().connect(mem_fun(*this, &MainWindow::on_conf_value_changed)); statusline_->signal_cancel_clicked.connect( mem_fun(*this, &MainWindow::on_busy_action_cancel)); filetree_->signal_switch_buffer.connect( mem_fun(*this, &MainWindow::on_filetree_switch_buffer)); filetree_->signal_bound_state_changed.connect( mem_fun(*this, &MainWindow::on_bound_state_changed)); filetree_->signal_file_count_changed.connect( mem_fun(*this, &MainWindow::on_filetree_file_count_changed)); filetree_->signal_match_count_changed.connect( mem_fun(*this, &MainWindow::on_filetree_match_count_changed)); filetree_->signal_modified_count_changed.connect( mem_fun(*this, &MainWindow::on_filetree_modified_count_changed)); filetree_->signal_pulse.connect( mem_fun(*this, &MainWindow::on_busy_action_pulse)); filetree_->signal_undo_stack_push.connect( mem_fun(*this, &MainWindow::on_undo_stack_push)); } bool MainWindow::autorun_idle() { controller_.find_files.activate(); if (!busy_action_cancel_ && entry_regex_->get_text_length() > 0) controller_.find_matches.activate(); return false; } void MainWindow::on_hide() { on_busy_action_cancel(); // Kill the dialogs if they're mapped right now. This isn't strictly // necessary since they'd be deleted in the destructor anyway. But if we // have to do a lot of cleanup the dialogs would stay open for that time, // which doesn't look neat. { // Play safe and transfer ownership, and let the dtor do the delete. const std::auto_ptr temp (about_dialog_); } { const std::auto_ptr temp (pref_dialog_); } } void MainWindow::on_style_changed(const Glib::RefPtr&) { FileBuffer::pango_context_changed(window_->get_pango_context()); } bool MainWindow::on_delete_event(GdkEventAny*) { return !confirm_quit_request(); } void MainWindow::on_cut() { if (const Glib::RefPtr buffer = textview_->get_buffer()) buffer->cut_clipboard(textview_->get_clipboard(selection_clipboard), textview_->get_editable()); } void MainWindow::on_copy() { if (const Glib::RefPtr buffer = textview_->get_buffer()) buffer->copy_clipboard(textview_->get_clipboard(selection_clipboard)); } void MainWindow::on_paste() { if (const Glib::RefPtr buffer = textview_->get_buffer()) buffer->paste_clipboard(textview_->get_clipboard(selection_clipboard), textview_->get_editable()); } void MainWindow::on_erase() { if (const Glib::RefPtr buffer = textview_->get_buffer()) buffer->erase_selection(true, textview_->get_editable()); } void MainWindow::on_quit() { if (confirm_quit_request()) window_->hide(); } bool MainWindow::confirm_quit_request() { if (filetree_->get_modified_count() == 0) return true; Gtk::MessageDialog dialog (*window_, _("Some files haven\342\200\231t been saved yet.\nQuit anyway?"), false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_NONE, true); dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL); dialog.add_button(Gtk::Stock::QUIT, Gtk::RESPONSE_OK); return (dialog.run() == Gtk::RESPONSE_OK); } void MainWindow::on_find_files() { if (filetree_->get_modified_count() > 0) { Gtk::MessageDialog dialog (*window_, _("Some files haven\342\200\231t been saved yet.\nContinue anyway?"), false, Gtk::MESSAGE_WARNING, Gtk::BUTTONS_OK_CANCEL, true); if (dialog.run() != Gtk::RESPONSE_OK) return; } std::string folder = button_folder_->get_filename(); if (folder.empty()) folder = Glib::get_current_dir(); g_return_if_fail(Glib::path_is_absolute(folder)); undo_stack_clear(); BusyAction busy (*this); try { Pcre::Pattern pattern (Util::shell_pattern_to_regex(entry_pattern_->get_text()), Pcre::DOTALL); filetree_->find_files(folder, pattern, button_recursive_->get_active(), button_hidden_->get_active()); } catch (const Pcre::Error&) { Gtk::MessageDialog dialog (*window_, _("The file search pattern is invalid."), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dialog.run(); } catch (const FileTree::Error& error) { FileErrorDialog dialog (*window_, _("The following errors occurred during search:"), Gtk::MESSAGE_WARNING, error); dialog.run(); } statusline_->set_file_count(filetree_->get_file_count()); } void MainWindow::on_exec_search() { BusyAction busy (*this); const Glib::ustring regex = entry_regex_->get_text(); const bool caseless = button_caseless_->get_active(); const bool multiple = button_multiple_->get_active(); try { Pcre::Pattern pattern (regex, (caseless) ? Pcre::CASELESS : Pcre::CompileOptions(0)); filetree_->find_matches(pattern, multiple); } catch (const Pcre::Error& error) { Gtk::MessageDialog dialog (*window_, error.what(), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dialog.run(); const int offset = error.offset(); if (offset >= 0 && offset < entry_regex_->get_text_length()) { entry_regex_->grab_focus(); entry_regex_->select_region(offset, offset + 1); } return; } if (const FileBufferPtr buffer = FileBufferPtr::cast_static(textview_->get_buffer())) { statusline_->set_match_count(buffer->get_original_match_count()); statusline_->set_match_index(buffer->get_match_index()); } if (filetree_->get_match_count() > 0) { // Scrolling has to be post-poned after the redraw, otherwise we might // not end up where we want to. So do that by installing an idle handler. Glib::signal_idle().connect( sigc::mem_fun(*this, &MainWindow::after_exec_search), Glib::PRIORITY_HIGH_IDLE + 25); // slightly less than redraw (+20) } } bool MainWindow::after_exec_search() { filetree_->select_first_file(); on_go_next(true); return false; } void MainWindow::on_filetree_switch_buffer(FileInfoPtr fileinfo, int file_index) { const FileBufferPtr old_buffer = FileBufferPtr::cast_static(textview_->get_buffer()); if (fileinfo && fileinfo->buffer == old_buffer) return; if (old_buffer) { std::for_each(buffer_connections_.begin(), buffer_connections_.end(), std::mem_fun_ref(&sigc::connection::disconnect)); buffer_connections_.clear(); old_buffer->forget_current_match(); } if (fileinfo) { const FileBufferPtr buffer = fileinfo->buffer; g_return_if_fail(buffer); textview_->set_buffer(buffer); textview_->set_editable(!fileinfo->load_failed); textview_->set_cursor_visible(!fileinfo->load_failed); if (!fileinfo->load_failed) { buffer_connections_.push_back(buffer->signal_modified_changed(). connect(sigc::mem_fun(*this, &MainWindow::on_buffer_modified_changed))); buffer_connections_.push_back(buffer->signal_bound_state_changed. connect(sigc::mem_fun(*this, &MainWindow::on_bound_state_changed))); buffer_connections_.push_back(buffer->signal_preview_line_changed. connect(sigc::mem_fun(*this, &MainWindow::update_preview))); } set_title_filename(fileinfo->fullname); controller_.replace_file.set_enabled(buffer->get_match_count() > 0); controller_.save_file.set_enabled(buffer->get_modified()); controller_.edit_actions.set_enabled(!fileinfo->load_failed); statusline_->set_match_count(buffer->get_original_match_count()); statusline_->set_match_index(buffer->get_match_index()); statusline_->set_file_encoding(fileinfo->encoding); } else { textview_->set_buffer(FileBuffer::create()); textview_->set_editable(false); textview_->set_cursor_visible(false); window_->set_title(PACKAGE_NAME); controller_.replace_file.set_enabled(false); controller_.save_file.set_enabled(false); controller_.edit_actions.set_enabled(false); statusline_->set_match_count(0); statusline_->set_match_index(0); statusline_->set_file_encoding(""); } statusline_->set_file_index(file_index); update_preview(); } void MainWindow::on_bound_state_changed() { BoundState bound = filetree_->get_bound_state(); controller_.prev_file.set_enabled((bound & BOUND_FIRST) == 0); controller_.next_file.set_enabled((bound & BOUND_LAST) == 0); if (const FileBufferPtr buffer = FileBufferPtr::cast_static(textview_->get_buffer())) bound &= buffer->get_bound_state(); controller_.prev_match.set_enabled((bound & BOUND_FIRST) == 0); controller_.next_match.set_enabled((bound & BOUND_LAST) == 0); } void MainWindow::on_filetree_file_count_changed() { const int file_count = filetree_->get_file_count(); statusline_->set_file_count(file_count); controller_.find_matches.set_enabled(file_count > 0); } void MainWindow::on_filetree_match_count_changed() { controller_.replace_all.set_enabled(filetree_->get_match_count() > 0); if (const FileBufferPtr buffer = FileBufferPtr::cast_static(textview_->get_buffer())) controller_.replace_file.set_enabled(buffer->get_match_count() > 0); } void MainWindow::on_filetree_modified_count_changed() { controller_.save_all.set_enabled(filetree_->get_modified_count() > 0); } void MainWindow::on_buffer_modified_changed() { controller_.save_file.set_enabled(textview_->get_buffer()->get_modified()); } void MainWindow::on_go_next_file(bool move_forward) { filetree_->select_next_file(move_forward); on_go_next(move_forward); } void MainWindow::on_go_next(bool move_forward) { if (const FileBufferPtr buffer = FileBufferPtr::cast_static(textview_->get_buffer())) { if (const Glib::RefPtr mark = buffer->get_next_match(move_forward)) { textview_->scroll_to(mark, 0.125); statusline_->set_match_index(buffer->get_match_index()); return; } } if (filetree_->select_next_file(move_forward)) { on_go_next(move_forward); // recursive call } } void MainWindow::on_replace() { if (const FileBufferPtr buffer = FileBufferPtr::cast_static(textview_->get_buffer())) { buffer->replace_current_match(entry_substitution_->get_text()); on_go_next(true); } } void MainWindow::on_replace_file() { if (const FileBufferPtr buffer = FileBufferPtr::cast_static(textview_->get_buffer())) { buffer->replace_all_matches(entry_substitution_->get_text()); statusline_->set_match_index(0); } } void MainWindow::on_replace_all() { BusyAction busy (*this); filetree_->replace_all_matches(entry_substitution_->get_text()); statusline_->set_match_index(0); } void MainWindow::on_save_file() { try { filetree_->save_current_file(); } catch (const FileTree::Error& error) { const std::list& error_list = error.get_error_list(); g_assert(error_list.size() == 1); Gtk::MessageDialog dialog (*window_, error_list.front(), false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true); dialog.run(); } } void MainWindow::on_save_all() { try { filetree_->save_all_files(); } catch (const FileTree::Error& error) { FileErrorDialog dialog (*window_, _("The following errors occurred during save:"), Gtk::MESSAGE_ERROR, error); dialog.run(); } } void MainWindow::on_undo_stack_push(UndoActionPtr action) { undo_stack_->push(action); controller_.undo.set_enabled(true); } void MainWindow::on_undo() { BusyAction busy (*this); undo_stack_->undo_step(sigc::mem_fun(*this, &MainWindow::on_busy_action_pulse)); controller_.undo.set_enabled(!undo_stack_->empty()); } void MainWindow::undo_stack_clear() { controller_.undo.set_enabled(false); undo_stack_.reset(new UndoStack()); } void MainWindow::on_entry_pattern_changed() { controller_.find_files.set_enabled(entry_pattern_->get_text_length() > 0); } void MainWindow::update_preview() { if (const FileBufferPtr buffer = FileBufferPtr::cast_static(textview_->get_buffer())) { Glib::ustring preview; const int pos = buffer->get_line_preview(entry_substitution_->get_text(), preview); entry_preview_->set_text(preview); controller_.replace.set_enabled(pos >= 0); // Beware, strange code ahead! // // The goal is to scroll the preview entry so that it shows the entire // replaced text if possible. In order to do that we first move the cursor // to 0, forcing scrolling to the left boundary. Then we set the cursor to // the end of the replaced text, thus forcing the entry widget to scroll // again. The replacement should then be entirely visible provided that it // fits into the entry. // // The problem is that Gtk::Entry doesn't update its scroll position // immediately but in an idle handler, thus any calls to set_position() // but the last one have no effect at all. // // To workaround that, we install an idle handler that's executed just // after the entry updated its scroll position, but before redrawing is // done. entry_preview_->set_position(0); if (pos > 0) { using namespace sigc; Glib::signal_idle().connect( bind_return(bind(mem_fun(*entry_preview_, &Gtk::Editable::set_position), pos), false), Glib::PRIORITY_HIGH_IDLE + 17); // between scroll update (+ 15) and redraw (+ 20) } } } void MainWindow::set_title_filename(const std::string& filename) { Glib::ustring title = Glib::filename_display_basename(filename); title += " ("; title += Util::filename_short_display_name(Glib::path_get_dirname(filename)); title += ") \342\200\223 " PACKAGE_NAME; // U+2013 EN DASH window_->set_title(title); } void MainWindow::busy_action_enter() { g_return_if_fail(!busy_action_running_); controller_.match_actions.set_enabled(false); statusline_->pulse_start(); busy_action_running_ = true; busy_action_cancel_ = false; busy_action_iteration_ = 0; } void MainWindow::busy_action_leave() { g_return_if_fail(busy_action_running_); busy_action_running_ = false; statusline_->pulse_stop(); controller_.match_actions.set_enabled(true); } bool MainWindow::on_busy_action_pulse() { g_return_val_if_fail(busy_action_running_, true); if (!busy_action_cancel_ && (++busy_action_iteration_ % BUSY_GUI_UPDATE_INTERVAL) == 0) { statusline_->pulse(); const Glib::RefPtr context = Glib::MainContext::get_default(); do {} while (context->iteration(false) && !busy_action_cancel_); } return busy_action_cancel_; } void MainWindow::on_busy_action_cancel() { if (busy_action_running_) busy_action_cancel_ = true; } void MainWindow::on_about() { if (about_dialog_.get()) { about_dialog_->present(); } else { std::auto_ptr dialog (new Gtk::AboutDialog()); dialog->set_version(PACKAGE_VERSION); dialog->set_logo_icon_name(PACKAGE_TARNAME); dialog->set_comments(_("Search and replace using regular expressions")); dialog->set_copyright("Copyright \302\251 2002-2007 Daniel Elstner"); dialog->set_website("http://regexxer.sourceforge.net/"); dialog->set_authors(program_authors); dialog->set_translator_credits(_("translator-credits")); dialog->set_license(program_license); dialog->set_wrap_license(true); dialog->set_transient_for(*window_); dialog->show(); dialog->signal_response().connect(sigc::mem_fun(*this, &MainWindow::on_about_dialog_response)); about_dialog_ = dialog; } } void MainWindow::on_about_dialog_response(int) { // Play safe and transfer ownership, and let the dtor do the delete. const std::auto_ptr temp (about_dialog_); } void MainWindow::on_preferences() { if (pref_dialog_.get()) { pref_dialog_->get_dialog()->present(); } else { std::auto_ptr dialog (new PrefDialog(*window_)); dialog->get_dialog()->signal_hide() .connect(sigc::mem_fun(*this, &MainWindow::on_pref_dialog_hide)); dialog->get_dialog()->show(); pref_dialog_ = dialog; } } void MainWindow::on_pref_dialog_hide() { // Play safe and transfer ownership, and let the dtor do the delete. const std::auto_ptr temp (pref_dialog_); } void MainWindow::on_conf_value_changed(const Glib::ustring& key, const Gnome::Conf::Value& value) { if (value.get_type() == Gnome::Conf::VALUE_STRING) { if (key.raw() == conf_key_textview_font) { const Pango::FontDescription font (value.get_string()); textview_ ->modify_font(font); entry_preview_->modify_font(font); } else if (key.raw() == conf_key_toolbar_style) { toolbar_->set_toolbar_style(Util::enum_from_nick(value.get_string())); } } } } // namespace Regexxer