23
23
#include <config.h>
26
#include <boost/format.hpp>
26
#include <boost/bind.hpp>
28
27
#include <glibmm/i18n.h>
28
#include <gtkmm/alignment.h>
29
29
#include <gtkmm/image.h>
30
#include <gtkmm/linkbutton.h>
31
#include <gtkmm/main.h>
30
#include <gtkmm/separatormenuitem.h>
32
31
#include <gtkmm/stock.h>
33
#include <gtkmm/table.h>
34
#include <gtkmm/treestore.h>
36
#include "sharp/datetime.hpp"
37
#include "sharp/string.hpp"
38
#include "actionmanager.hpp"
39
33
#include "debug.hpp"
34
#include "iactionmanager.hpp"
36
#include "iconmanager.hpp"
41
37
#include "note.hpp"
42
38
#include "notemanager.hpp"
43
39
#include "notewindow.hpp"
44
40
#include "recentchanges.hpp"
45
#include "recenttreeview.hpp"
47
#include "tagmanager.hpp"
49
#include "notebooks/notebookmanager.hpp"
50
#include "notebooks/notebookstreeview.hpp"
41
#include "sharp/string.hpp"
55
bool NoteRecentChanges::s_static_inited = false;
56
Glib::RefPtr<Gdk::Pixbuf> NoteRecentChanges::s_note_icon;
57
Glib::RefPtr<Gdk::Pixbuf> NoteRecentChanges::s_all_notes_icon;
58
Glib::RefPtr<Gdk::Pixbuf> NoteRecentChanges::s_unfiled_notes_icon;
59
Glib::RefPtr<Gdk::Pixbuf> NoteRecentChanges::s_notebook_icon;
60
std::list<std::string> NoteRecentChanges::s_previous_searches;
61
NoteRecentChanges *NoteRecentChanges::s_instance = NULL;
65
NoteRecentChanges *NoteRecentChanges::get_instance()
71
NoteRecentChanges *NoteRecentChanges::get_instance(NoteManager& m)
74
s_instance = new NoteRecentChanges(m);
80
void NoteRecentChanges::_init_static()
85
s_note_icon = utils::get_icon ("note", 22);
86
s_all_notes_icon = utils::get_icon ("filter-note-all", 22);
87
s_unfiled_notes_icon = utils::get_icon ("filter-note-unfiled", 22);
88
s_notebook_icon = utils::get_icon ("notebook", 22);
89
s_static_inited = true;
92
46
NoteRecentChanges::NoteRecentChanges(NoteManager& m)
93
: utils::ForcedPresentWindow(_("Search All Notes"))
96
, m_find_combo(Glib::RefPtr<Gtk::TreeModel>::cast_static(Gtk::ListStore::create(m_find_combo_columns)), true)
97
, m_clear_search_button(Gtk::Stock::CLEAR)
47
: MainWindow(_("Notes"))
49
, m_search_notes_widget(m)
98
50
, m_content_vbox(false, 0)
99
, m_matches_column(NULL)
100
, m_no_matches_box(NULL)
102
52
, m_entry_changed_timeout(NULL)
103
, m_clickX(0), m_clickY(0)
53
, m_window_menu_search(NULL)
54
, m_window_menu_note(NULL)
55
, m_window_menu_default(NULL)
105
Gnote::obj().add_window(this);
107
// get_window()->set_icon_name("gnote");
108
57
set_default_size(450,400);
109
58
set_resizable(true);
111
add_accel_group(ActionManager::obj().get_ui()->get_accel_group());
113
m_menubar = create_menu_bar ();
115
Gtk::Label *label = manage(new Gtk::Label (_("_Search:"), true));
116
label->property_xalign() = 1;
118
label->set_mnemonic_widget(m_find_combo);
119
m_find_combo.set_entry_text_column(0);
120
m_find_combo.signal_changed()
121
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_entry_changed));
122
m_find_combo.get_entry()->set_activates_default(false);
123
m_find_combo.get_entry()->signal_activate()
124
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_entry_activated));
126
Glib::RefPtr<Gtk::ListStore> model
127
= Glib::RefPtr<Gtk::ListStore>::cast_dynamic(m_find_combo.get_model());
128
for(std::list<std::string>::const_iterator liter = s_previous_searches.begin();
129
liter != s_previous_searches.end(); ++liter) {
130
Gtk::TreeIter iter = model->append();
131
iter->set_value(0, *liter);
59
set_hide_titlebar_when_maximized(true);
60
if(Preferences::obj().get_schema_settings(Preferences::SCHEMA_GNOTE)->get_boolean(
61
Preferences::MAIN_WINDOW_MAXIMIZED)) {
134
m_clear_search_button.set_sensitive(false);
135
m_clear_search_button.signal_clicked()
136
.connect(sigc::mem_fun(*this, &NoteRecentChanges::clear_search_clicked));
137
m_clear_search_button.show ();
139
Gtk::Table *table = manage(new Gtk::Table (2, 3, false));
140
table->attach (*label, 0, 1, 0, 1, Gtk::SHRINK, (Gtk::AttachOptions)0, 0, 0);
141
table->attach (m_find_combo, 1, 2, 0, 1);
142
table->attach (m_clear_search_button,
144
Gtk::SHRINK, (Gtk::AttachOptions)0, 0, 0);
145
table->property_column_spacing() = 4;
148
Gtk::HBox *hbox = manage(new Gtk::HBox (false, 2));
149
hbox->pack_start (*table, true, true, 0);
153
Gtk::Widget *notebooksPane = Gtk::manage(make_notebooks_pane ());
154
notebooksPane->show ();
157
m_tree = manage(m_tree);
160
65
set_has_resize_grip(true);
163
// Update on changes to notes
164
m.signal_note_deleted.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_note_deleted));
165
m.signal_note_added.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_note_added));
166
m.signal_note_renamed.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_note_renamed));
167
m.signal_note_saved.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_note_saved));
169
// List all the current notes
172
m_matches_window.set_shadow_type(Gtk::SHADOW_IN);
174
m_matches_window.property_hscrollbar_policy() = Gtk::POLICY_AUTOMATIC;
175
m_matches_window.property_vscrollbar_policy() = Gtk::POLICY_AUTOMATIC;
176
m_matches_window.add (*m_tree);
177
m_matches_window.show ();
179
m_hpaned.set_position(150);
180
m_hpaned.add1 (*notebooksPane);
181
m_hpaned.add2 (m_matches_window);
186
Gtk::VBox *vbox = manage(new Gtk::VBox (false, 8));
187
vbox->set_border_width(6);
188
vbox->pack_start (*hbox, false, false, 0);
189
vbox->pack_start (m_hpaned, true, true, 0);
190
vbox->pack_start (m_status_bar, false, false, 0);
193
// Use another VBox to place the MenuBar
194
// right at thetop of the window.
195
m_content_vbox.pack_start (*manage(m_menubar), false, false, 0);
196
m_content_vbox.pack_start (*vbox, true, true, 0);
67
m_search_notes_widget.signal_open_note
68
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_open_note));
69
m_search_notes_widget.signal_open_note_new_window
70
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_open_note_new_window));
72
Gtk::Box *toolbar = make_toolbar();
73
m_content_vbox.pack_start(*toolbar, false, false, 0);
74
m_content_vbox.pack_start(m_embed_box, true, true, 0);
197
76
m_content_vbox.show ();
199
78
add (m_content_vbox);
200
79
signal_delete_event().connect(sigc::mem_fun(*this, &NoteRecentChanges::on_delete));
201
80
signal_key_press_event()
202
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_key_pressed)); // For Escape
204
// Watch when notes are added to notebooks so the search
205
// results will be updated immediately instead of waiting
206
// until the note's queue_save () kicks in.
207
notebooks::NotebookManager::instance().signal_note_added_to_notebook()
208
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_note_added_to_notebook));
209
notebooks::NotebookManager::instance().signal_note_removed_from_notebook()
210
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_note_removed_from_notebook));
212
// Set the focus chain for the top-most containers
213
std::vector<Gtk::Widget*> focus_chain;
214
focus_chain.push_back(hbox);
215
focus_chain.push_back(&m_hpaned);
216
vbox->set_focus_chain(focus_chain);
218
// Set focus chain for sub widgets of first top-most container
220
focus_chain.push_back(&m_find_combo);
221
focus_chain.push_back(&m_matches_window);
222
hbox->set_focus_chain(focus_chain);
224
// set focus chain for sub widgets of second top-most container
226
focus_chain.push_back(&m_matches_window);
227
focus_chain.push_back(notebooksPane);
228
m_hpaned.set_focus_chain(focus_chain);
230
// get back to the beginning of the focus chain
232
focus_chain.push_back(m_tree);
233
m_matches_window.set_focus_chain(focus_chain);
235
Gnote::obj().signal_quit.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_exiting_event));
81
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_key_pressed));
82
IGnote::obj().signal_quit
83
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_close_window));// to save size/pos
85
embed_widget(m_search_notes_widget);
87
IActionManager::obj().signal_main_window_search_actions_changed
88
.connect(boost::bind(sigc::mem_fun(*this, &NoteRecentChanges::on_main_window_actions_changed),
89
&m_window_menu_search));
90
IActionManager::obj().signal_main_window_note_actions_changed
91
.connect(boost::bind(sigc::mem_fun(*this, &NoteRecentChanges::on_main_window_actions_changed),
92
&m_window_menu_note));
240
96
NoteRecentChanges::~NoteRecentChanges()
98
while(m_embedded_widgets.size()) {
99
unembed_widget(**m_embedded_widgets.begin());
242
101
if(m_entry_changed_timeout) {
243
102
delete m_entry_changed_timeout;
245
Gnote::obj().remove_window(this);
249
Gtk::MenuBar *NoteRecentChanges::create_menu_bar ()
251
ActionManager &am(ActionManager::obj());
252
Gtk::MenuBar *menubar = dynamic_cast<Gtk::MenuBar*>(am.get_widget ("/MainWindowMenubar"));
254
am ["OpenNoteAction"]->signal_activate()
255
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_open_note));
256
am ["DeleteNoteAction"]->signal_activate()
257
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_delete_note));
258
// from notebook addin
259
am ["NewNotebookNoteAction"]->signal_activate()
260
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_new_notebook_note));
261
am ["OpenNotebookTemplateNoteAction"]->signal_activate()
262
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_open_notebook_template_note));
263
am ["NewNotebookAction"]->signal_activate()
264
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_new_notebook));
265
am ["DeleteNotebookAction"]->signal_activate()
266
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_delete_notebook));
267
// end notebook addin
268
am ["CloseWindowAction"]->signal_activate()
269
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_close_window));
270
if (Gnote::obj().tray_icon_showing() == false)
271
am ["CloseWindowAction"]->set_visible(false);
273
// Allow Escape to close the window as well as <Control>W
274
// Should be able to add Escape to the CloseAction. Can't do that
275
// until someone fixes AccelGroup.Connect:
276
// http://bugzilla.ximian.com/show_bug.cgi?id=76988)
278
// am.UI.AccelGroup.Connect ((uint) Gdk.Key.Escape,
280
// Gtk::AccelFlags.Mask,
286
Gtk::Widget *NoteRecentChanges::make_notebooks_pane()
288
m_notebooksTree = Gtk::manage(
289
new notebooks::NotebooksTreeView (notebooks::NotebookManager::instance()
290
.get_notebooks_with_special_items()));
292
m_notebooksTree->get_selection()->set_mode(Gtk::SELECTION_SINGLE);
293
m_notebooksTree->set_headers_visible(true);
294
m_notebooksTree->set_rules_hint(false);
296
Gtk::CellRenderer *renderer;
298
Gtk::TreeViewColumn *column = manage(new Gtk::TreeViewColumn ());
299
column->set_title(_("Notebooks"));
300
column->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
301
column->set_resizable(false);
303
renderer = manage(new Gtk::CellRendererPixbuf ());
304
column->pack_start (*renderer, false);
305
column->set_cell_data_func (*renderer,
306
sigc::mem_fun(*this, &NoteRecentChanges::notebook_pixbuf_cell_data_func));
308
Gtk::CellRendererText *text_renderer = manage(new Gtk::CellRendererText ());
309
text_renderer->property_editable() = true;
310
column->pack_start (*text_renderer, true);
311
column->set_cell_data_func (*text_renderer,
312
sigc::mem_fun(*this, &NoteRecentChanges::notebook_text_cell_data_func));
313
text_renderer->signal_edited().connect(sigc::mem_fun(*this, &NoteRecentChanges::on_notebook_row_edited));
315
m_notebooksTree->append_column (*column);
317
m_notebooksTree->signal_row_activated()
318
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_notebook_row_activated));
319
m_on_notebook_selection_changed_cid = m_notebooksTree->get_selection()->signal_changed()
320
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_notebook_selection_changed));
321
m_notebooksTree->signal_button_press_event()
322
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_notebooks_tree_button_pressed), false);
323
m_notebooksTree->signal_key_press_event()
324
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_notebooks_key_pressed));
326
m_notebooksTree->show ();
327
Gtk::ScrolledWindow *sw = new Gtk::ScrolledWindow ();
328
sw->property_hscrollbar_policy() = Gtk::POLICY_AUTOMATIC;
329
sw->property_vscrollbar_policy() = Gtk::POLICY_AUTOMATIC;
330
sw->set_shadow_type(Gtk::SHADOW_IN);
331
sw->add (*m_notebooksTree);
338
void NoteRecentChanges::make_recent_tree ()
340
m_targets.push_back(Gtk::TargetEntry ("STRING",
341
Gtk::TARGET_SAME_APP,
343
m_targets.push_back(Gtk::TargetEntry ("text/plain",
344
Gtk::TARGET_SAME_APP,
346
m_targets.push_back(Gtk::TargetEntry ("text/uri-list",
347
Gtk::TARGET_SAME_APP,
350
m_tree = Gtk::manage(new RecentTreeView ());
351
m_tree->set_headers_visible(true);
352
m_tree->set_rules_hint(true);
353
m_tree->signal_row_activated().connect(
354
sigc::mem_fun(*this, &NoteRecentChanges::on_row_activated));
355
m_tree->get_selection()->set_mode(Gtk::SELECTION_MULTIPLE);
356
m_tree->get_selection()->signal_changed().connect(
357
sigc::mem_fun(*this, &NoteRecentChanges::on_selection_changed));
358
m_tree->signal_button_press_event().connect(
359
sigc::mem_fun(*this, &NoteRecentChanges::on_treeview_button_pressed), false);
360
m_tree->signal_motion_notify_event().connect(
361
sigc::mem_fun(*this, &NoteRecentChanges::on_treeview_motion_notify), false);
362
m_tree->signal_button_release_event().connect(
363
sigc::mem_fun(*this, &NoteRecentChanges::on_treeview_button_released));
364
m_tree->signal_key_press_event().connect(
366
&NoteRecentChanges::on_treeview_key_pressed), false);
367
m_tree->signal_drag_data_get().connect(
368
sigc::mem_fun(*this, &NoteRecentChanges::on_treeview_drag_data_get));
370
m_tree->enable_model_drag_source(m_targets,
371
Gdk::BUTTON1_MASK | Gdk::BUTTON3_MASK, Gdk::ACTION_MOVE);
373
Gtk::CellRenderer *renderer;
375
Gtk::TreeViewColumn *title = manage(new Gtk::TreeViewColumn ());
376
title->set_title(_("Note"));
377
title->set_min_width(150);
378
title->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
379
title->set_expand(true);
380
title->set_resizable(true);
382
renderer = manage(new Gtk::CellRendererPixbuf ());
383
title->pack_start (*renderer, false);
384
title->add_attribute (*renderer, "pixbuf", 0 /* icon */);
386
renderer = manage(new Gtk::CellRendererText ());
387
static_cast<Gtk::CellRendererText*>(renderer)->property_ellipsize() = Pango::ELLIPSIZE_END;
388
title->pack_start (*renderer, true);
389
title->add_attribute (*renderer, "text", 1 /* title */);
390
title->set_sort_column(1); /* title */
391
title->set_sort_indicator(false);
392
title->set_reorderable(false);
393
title->set_sort_order(Gtk::SORT_ASCENDING);
395
m_tree->append_column (*title);
397
Gtk::TreeViewColumn *change = manage(new Gtk::TreeViewColumn ());
398
change->set_title(_("Last Changed"));
399
change->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
400
change->set_resizable(false);
402
renderer = manage(new Gtk::CellRendererText ());
403
renderer->property_xalign() = 1.0;
404
change->pack_start (*renderer, false);
405
change->add_attribute (*renderer, "text", 2 /* change date */);
406
change->set_sort_column(2); /* change date */
407
change->set_sort_indicator(false);
408
change->set_reorderable(false);
409
change->set_sort_order(Gtk::SORT_DESCENDING);
411
m_tree->append_column (*change);
414
void NoteRecentChanges::add_note(const Note::Ptr & note)
416
std::string nice_date =
417
utils::get_pretty_print_date(note->change_date(), true);
418
Gtk::TreeIter iter = m_store->append();
419
iter->set_value(m_column_types.icon, s_note_icon);
420
iter->set_value(m_column_types.title, note->get_title());
421
iter->set_value(m_column_types.change_date, nice_date);
422
iter->set_value(m_column_types.note, note);
425
void NoteRecentChanges::delete_note(const Note::Ptr & note)
427
Gtk::TreeModel::Children rows = m_store->children();
429
for (Gtk::TreeModel::iterator iter = rows.begin();
430
rows.end() != iter; iter++) {
431
if (note == iter->get_value(m_column_types.note)) {
432
m_store->erase(iter);
438
void NoteRecentChanges::rename_note(const Note::Ptr & note)
440
Gtk::TreeModel::Children rows = m_store->children();
442
for (Gtk::TreeModel::iterator iter = rows.begin();
443
rows.end() != iter; iter++) {
444
if (note == iter->get_value(m_column_types.note)) {
445
iter->set_value(m_column_types.title, note->get_title());
451
void NoteRecentChanges::update_results()
453
// Save the currently selected notes
454
Note::List selected_notes = get_selected_notes ();
456
int sort_column = 2; /* change date */
457
Gtk::SortType sort_type = Gtk::SORT_DESCENDING;
459
m_store_sort->get_sort_column_id (sort_column, sort_type);
461
m_store = Gtk::ListStore::create (m_column_types);
463
m_store_filter = Gtk::TreeModelFilter::create (m_store);
464
m_store_filter->set_visible_func(sigc::mem_fun(*this, &NoteRecentChanges::filter_notes));
465
m_store_sort = Gtk::TreeModelSort::create (m_store_filter);
466
m_store_sort->set_sort_func (1 /* title */,
467
sigc::mem_fun(*this, &NoteRecentChanges::compare_titles));
468
m_store_sort->set_sort_func (2 /* change date */,
469
sigc::mem_fun(*this, &NoteRecentChanges::compare_dates));
473
for(Note::List::const_iterator note_iter = m_manager.get_notes().begin();
474
note_iter != m_manager.get_notes().end(); ++note_iter) {
475
const Note::Ptr & note(*note_iter);
476
std::string nice_date =
477
utils::get_pretty_print_date (note->change_date(), true);
479
Gtk::TreeIter iter = m_store->append();
480
iter->set_value(0, s_note_icon); /* icon */
481
iter->set_value(1, note->get_title()); /* title */
482
iter->set_value(2, nice_date); /* change date */
483
iter->set_value(3, note); /* note */
487
m_tree->set_model(m_store_sort);
491
if (sort_column >= 0) {
492
// Set the sort column after loading data, since we
493
// don't want to resort on every append.
494
m_store_sort->set_sort_column(sort_column, sort_type);
497
// Restore the previous selection
498
if (!selected_notes.empty()) {
499
select_notes (selected_notes);
505
void NoteRecentChanges::select_notes(const Note::List & notes)
507
Gtk::TreeIter iter = m_store_sort->children().begin();
513
Note::Ptr iter_note = (*iter)[m_column_types.note];
514
if (find(notes.begin(), notes.end(), iter_note) != notes.end()) {
516
m_tree->get_selection()->select(iter);
517
//ScrollToIter (tree, iter);
522
void NoteRecentChanges::scroll_to_iter (Gtk::TreeView & tree, const Gtk::TreeIter & iter)
524
Gtk::TreePath path = tree.get_model()->get_path(iter);
526
tree.scroll_to_row (path);
530
void NoteRecentChanges::perform_search ()
532
// For some reason, the matches column must be rebuilt
533
// every time because otherwise, it's not sortable.
534
remove_matches_column ();
535
Search search(m_manager);
537
std::string text = get_search_text();
539
m_current_matches.clear ();
540
m_store_filter->refilter ();
541
update_total_note_count (m_store_sort->children().size());
542
if (m_tree->get_realized()) {
543
m_tree->scroll_to_point (0, 0);
547
text = sharp::string_to_lower(text);
549
m_current_matches.clear ();
551
// Search using the currently selected notebook
552
notebooks::Notebook::Ptr selected_notebook = get_selected_notebook ();
553
if (std::tr1::dynamic_pointer_cast<notebooks::SpecialNotebook>(selected_notebook)) {
554
selected_notebook = notebooks::Notebook::Ptr();
557
Search::ResultsPtr results = search.search_notes(text, false, selected_notebook);
558
// if no results found in current notebook ask user whether
559
// to search in all notebooks
560
if(results->size() == 0 && selected_notebook != NULL) {
561
no_matches_found_action();
564
for(Search::Results::const_reverse_iterator iter = results->rbegin();
565
iter != results->rend(); iter++) {
566
m_current_matches[iter->second->uri()] = iter->first;
569
add_matches_column ();
570
m_store_filter->refilter ();
571
m_tree->scroll_to_point (0, 0);
572
update_match_note_count (m_current_matches.size());
577
void NoteRecentChanges::add_matches_column ()
579
if (!m_matches_column) {
580
Gtk::CellRenderer *renderer;
582
m_matches_column = manage(new Gtk::TreeViewColumn ());
583
m_matches_column->set_title(_("Matches"));
584
m_matches_column->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
585
m_matches_column->set_resizable(false);
587
renderer = manage(new Gtk::CellRendererText ());
588
renderer->property_width() = 75;
589
m_matches_column->pack_start (*renderer, false);
590
m_matches_column->set_cell_data_func (
592
sigc::mem_fun(*this, &NoteRecentChanges::matches_column_data_func));
593
m_matches_column->set_sort_column(4);
594
m_matches_column->set_sort_indicator(true);
595
m_matches_column->set_reorderable(false);
596
m_matches_column->set_sort_order(Gtk::SORT_DESCENDING);
597
m_matches_column->set_clickable(true);
598
m_store_sort->set_sort_func(4 /* matches */,
599
sigc::mem_fun(*this, &NoteRecentChanges::compare_search_hits));
601
m_tree->append_column (*m_matches_column);
602
m_store_sort->set_sort_column(4, Gtk::SORT_DESCENDING);
607
void NoteRecentChanges::remove_matches_column ()
609
if (m_matches_column == NULL)
612
m_tree->remove_column (*m_matches_column);
613
m_matches_column = NULL;
615
m_store_sort->set_sort_column(2, Gtk::SORT_DESCENDING);
619
void NoteRecentChanges::matches_column_data_func(Gtk::CellRenderer * cell,
620
const Gtk::TreeIter & iter)
622
Gtk::CellRendererText *crt = dynamic_cast<Gtk::CellRendererText*>(cell);
626
std::string match_str = "";
628
Note::Ptr note = (*iter)[m_column_types.note];
631
std::map<std::string, int>::const_iterator miter
632
= m_current_matches.find(note->uri());
633
if (miter != m_current_matches.end()) {
634
match_count = miter->second;
635
if(match_count == INT_MAX) {
636
//TRANSLATORS: search found a match in note title
637
match_str = _("Title match");
639
else if (match_count > 0) {
641
fmt = ngettext("%1% match", "%1% matches", match_count);
642
match_str = str(boost::format(fmt) % match_count);
647
crt->property_text() = match_str;
651
void NoteRecentChanges::update_total_note_count (int total)
655
fmt = ngettext("Total: %1% note", "Total: %1% notes", total);
656
std::string status = str(boost::format (fmt) % total);
658
m_status_bar.push(status, 0);
660
catch(const std::exception & e)
662
ERR_OUT("exception: %s", e.what());
667
void NoteRecentChanges::update_match_note_count (int matches)
671
fmt = ngettext("Matches: %1% note", "Matches: %1% notes", matches);
672
std::string status = str(boost::format (fmt) % matches);
674
m_status_bar.push(status, 0);
676
catch(const std::exception & e)
678
ERR_OUT("exception: %s", e.what());
682
// called when no search results are found in the selected notebook
683
void NoteRecentChanges::no_matches_found_action()
685
m_hpaned.remove(m_matches_window);
686
if(!m_no_matches_box) {
687
Glib::ustring message = _("No results found in the selected notebook.\nClick here to search across all notes.");
688
Gtk::LinkButton *link_button = manage(new Gtk::LinkButton("", message));
689
link_button->signal_activate_link()
690
.connect(sigc::mem_fun(*this, &NoteRecentChanges::show_all_search_results));
691
link_button->set_tooltip_text(_("Click here to search across all notebooks"));
693
Gtk::Table *no_matches_found_table = manage(new Gtk::Table(1, 3, false));
694
no_matches_found_table->attach(*link_button, 1, 2, 0, 1,
695
Gtk::FILL | Gtk::SHRINK,
700
no_matches_found_table->set_col_spacings(4);
701
no_matches_found_table->show_all();
702
m_no_matches_box = manage(new Gtk::HBox(false, 0));
703
m_no_matches_box->pack_start(*no_matches_found_table, true, true, 0);
704
m_no_matches_box->show();
706
m_hpaned.add2(*m_no_matches_box);
709
void NoteRecentChanges::restore_matches_window()
711
if(m_no_matches_box && m_hpaned.get_child2() == m_no_matches_box) {
712
m_hpaned.remove(*m_no_matches_box);
713
m_hpaned.add2(m_matches_window);
718
bool NoteRecentChanges::show_all_search_results()
720
Gtk::TreeIter iter = m_notebooksTree->get_model()->children().begin();
721
m_notebooksTree->get_selection()->select(iter);
727
/// Filter out notes based on the current search string
728
/// and selected tags. Also prevent template notes from
731
bool NoteRecentChanges::filter_notes(const Gtk::TreeIter & iter)
733
Note::Ptr note = (*iter)[m_column_types.note];
737
// Don't show the template notes in the list
738
Tag::Ptr template_tag = TagManager::obj().get_or_create_system_tag (TagManager::TEMPLATE_NOTE_SYSTEM_TAG);
739
if (note->contains_tag (template_tag)) {
743
notebooks::Notebook::Ptr selected_notebook = get_selected_notebook ();
744
if (std::tr1::dynamic_pointer_cast<notebooks::UnfiledNotesNotebook>(selected_notebook)) {
745
// If the note belongs to a notebook, return false
746
// since the only notes that should be shown in this
747
// case are notes that are unfiled (not in a notebook).
748
if (notebooks::NotebookManager::instance().get_notebook_from_note (note))
752
bool passes_search_filter = filter_by_search (note);
753
if (passes_search_filter == false)
754
return false; // don't waste time checking tags if it's already false
756
bool passes_tag_filter = filter_by_tag (note);
758
// Must pass both filters to appear in the list
759
return passes_tag_filter && passes_search_filter;
763
#if 0 // TODO seems to be unused
764
bool NoteRecentChanges::filter_tags(const Gtk::TreeIter & iter)
766
Tag t = model.GetValue (iter, 0 /* note */) as Tag;
767
if(t.IsProperty || t.IsSystem)
775
// Return true if the specified note should be shown in the list
776
// based on the current selection of tags. If no tags are selected,
777
// all notes should be allowed.
779
bool NoteRecentChanges::filter_by_tag (const Note::Ptr & note)
781
if (m_selected_tags.empty())
784
// // FIXME: Ugh! NOT an O(1) operation. Is there a better way?
785
std::list<Tag::Ptr> tags;
786
note->get_tags(tags);
787
for(std::list<Tag::Ptr>::const_iterator iter = tags.begin();
788
iter != tags.end(); ++iter) {
789
if(m_selected_tags.find(*iter) != m_selected_tags.end()) {
798
// Return true if the specified note should be shown in the list
799
// based on the search string. If no search string is specified,
800
// all notes should be allowed.
802
bool NoteRecentChanges::filter_by_search(const Note::Ptr & note)
804
if (get_search_text().empty())
807
if (m_current_matches.empty())
810
return note && (m_current_matches.find(note->uri()) != m_current_matches.end());
814
void NoteRecentChanges::on_case_sensitive_toggled()
819
void NoteRecentChanges::on_note_added(const Note::Ptr & note)
821
restore_matches_window();
825
void NoteRecentChanges::on_note_deleted(const Note::Ptr & note)
827
restore_matches_window();
831
void NoteRecentChanges::on_note_renamed(const Note::Ptr & note,
834
restore_matches_window();
838
void NoteRecentChanges::on_note_saved(const Note::Ptr&)
840
restore_matches_window();
844
void NoteRecentChanges::on_treeview_drag_data_get(const Glib::RefPtr<Gdk::DragContext> &,
845
Gtk::SelectionData &selection_data,
848
Note::List selected_notes = get_selected_notes ();
849
if (selected_notes.empty()) {
853
std::vector<Glib::ustring> uris;
854
for(Note::List::const_iterator iter = selected_notes.begin();
855
iter != selected_notes.end(); ++iter) {
857
uris.push_back((*iter)->uri());
860
selection_data.set_uris(uris);
862
if (selected_notes.size() == 1) {
863
selection_data.set_text(selected_notes.front()->get_title());
866
selection_data.set_text(_("Notes"));
870
void NoteRecentChanges::on_notebook_row_edited(const Glib::ustring& /*tree_path*/,
871
const Glib::ustring& new_text)
873
if (notebooks::NotebookManager::instance().notebook_exists(new_text) ||
877
notebooks::Notebook::Ptr old_notebook = this->get_selected_notebook ();
878
if (std::tr1::dynamic_pointer_cast<notebooks::SpecialNotebook>(old_notebook)) {
881
notebooks::Notebook::Ptr new_notebook = notebooks::NotebookManager::instance()
882
.get_or_create_notebook (new_text);
883
DBG_OUT("Renaming notebook '{%s}' to '{%s}'", old_notebook->get_name().c_str(),
885
std::list<Note *> notes;
886
old_notebook->get_tag()->get_notes(notes);
887
for(std::list<Note *>::const_iterator note = notes.begin(); note != notes.end(); ++note) {
888
notebooks::NotebookManager::instance().move_note_to_notebook (
889
(*note)->shared_from_this(), new_notebook);
891
notebooks::NotebookManager::instance().delete_notebook (old_notebook);
893
if (notebooks::NotebookManager::instance().get_notebook_iter (new_notebook, iter)) {
894
m_notebooksTree->get_selection()->select(iter);
898
void NoteRecentChanges::on_selection_changed()
900
Note::List selected_notes = get_selected_notes ();
901
ActionManager &am(ActionManager::obj());
903
if (selected_notes.empty()) {
904
am ["OpenNoteAction"]->property_sensitive() = false;
905
am ["DeleteNoteAction"]->property_sensitive() = false;
907
else if (selected_notes.size()) {
908
am ["OpenNoteAction"]->property_sensitive() = true;
909
am ["DeleteNoteAction"]->property_sensitive() = true;
912
// Many notes are selected
913
am ["OpenNoteAction"]->property_sensitive() = false;
914
am ["DeleteNoteAction"]->property_sensitive() = true;
919
bool NoteRecentChanges::on_treeview_button_pressed(GdkEventButton *ev)
921
if (ev->window != m_tree->get_bin_window()->gobj()) {
925
Gtk::TreePath dest_path;
926
Gtk::TreeViewColumn *column = NULL;
929
m_tree->get_path_at_pos (ev->x, ev->y,
930
dest_path, column, unused, unused);
938
case GDK_2BUTTON_PRESS:
939
if (ev->button != 1 || (ev->state &
940
(Gdk::CONTROL_MASK | Gdk::SHIFT_MASK)) != 0) {
944
m_tree->get_selection()->unselect_all ();
945
m_tree->get_selection()->select(dest_path);
946
// apparently Gtk::TreeView::row_activated() require a dest_path
947
// while get_path_at_pos() can return a NULL pointer.
948
// See Gtkmm bug 586438
949
// https://bugzilla.gnome.org/show_bug.cgi?id=586438
950
gtk_tree_view_row_activated(m_tree->gobj(), dest_path.gobj(),
951
column?column->gobj():NULL);
953
case GDK_BUTTON_PRESS:
954
if (ev->button == 3) {
955
const Glib::RefPtr<Gtk::TreeSelection> selection
956
= m_tree->get_selection();
958
if(selection->get_selected_rows().size() <= 1) {
959
Gtk::TreeViewColumn * col = 0; // unused
961
int cell_x, cell_y; // unused
962
if (m_tree->get_path_at_pos(ev->x, ev->y, p, col,
964
selection->unselect_all();
965
selection->select(p);
968
Gtk::Menu *menu = dynamic_cast<Gtk::Menu*>(
969
ActionManager::obj().get_widget("/MainWindowContextMenu"));
970
popup_context_menu_at_location (menu, ev->x, ev->y);
972
// Return true so that the base handler won't
973
// run, which causes the selection to change to
974
// the row that was right-clicked.
979
if (m_tree->get_selection()->is_selected(dest_path)
980
&& (ev->state & (Gdk::CONTROL_MASK | Gdk::SHIFT_MASK)) == 0) {
981
if (column && (ev->button == 1)) {
982
Gtk::CellRenderer *renderer = column->get_first_cell();
983
Gdk::Rectangle background_area;
984
m_tree->get_background_area (dest_path, *column, background_area);
985
Gdk::Rectangle cell_area;
986
m_tree->get_cell_area (dest_path, *column, cell_area);
988
renderer->activate ((GdkEvent*)ev, *m_tree,
989
dest_path.to_string (),
990
background_area, cell_area,
991
Gtk::CELL_RENDERER_SELECTED);
993
Gtk::TreeIter iter = m_tree->get_model()->get_iter (dest_path);
995
m_tree->get_model()->row_changed(dest_path, iter);
1010
bool NoteRecentChanges::on_treeview_motion_notify(GdkEventMotion *ev)
1012
if ((ev->state & Gdk::BUTTON1_MASK) == 0) {
1015
else if (ev->window != m_tree->get_bin_window()->gobj()) {
1021
if (!m_tree->drag_check_threshold(m_clickX, m_clickY, ev->x, ev->y)) {
1025
Gtk::TreePath dest_path;
1026
Gtk::TreeViewColumn * col = NULL; // unused
1027
int cell_x, cell_y; // unused
1028
if (!m_tree->get_path_at_pos (ev->x, ev->y, dest_path, col, cell_x, cell_y)) {
1032
m_tree->drag_begin (Gtk::TargetList::create (m_targets),
1033
Gdk::ACTION_MOVE, 1, (GdkEvent*)ev);
1038
bool NoteRecentChanges::on_treeview_button_released(GdkEventButton *ev)
1040
if (!m_tree->drag_check_threshold(m_clickX, m_clickY,
1042
((ev->state & (Gdk::CONTROL_MASK | Gdk::SHIFT_MASK)) == 0) &&
1043
m_tree->get_selection()->count_selected_rows () > 1) {
1045
Gtk::TreePath dest_path;
1046
Gtk::TreeViewColumn * col = NULL; // unused
1047
int cell_x, cell_y; // unused
1048
m_tree->get_path_at_pos (ev->x, ev->y, dest_path, col, cell_x, cell_y);
1049
m_tree->get_selection()->unselect_all ();
1050
m_tree->get_selection()->select (dest_path);
1055
bool NoteRecentChanges::on_treeview_key_pressed(GdkEventKey * ev)
1057
switch (ev->keyval) {
1060
// Pop up the context menu if a note is selected
1061
Note::List selected_notes = get_selected_notes();
1062
if (!selected_notes.empty()) {
1063
ActionManager & manager = ActionManager::obj();
1064
Gtk::Menu * const menu
1065
= dynamic_cast<Gtk::Menu*>(manager.get_widget(
1066
"/MainWindowContextMenu"));
1067
popup_context_menu_at_location(menu, 0, 0);
1071
case GDK_KEY_Return:
1072
case GDK_KEY_KP_Enter:
1073
// Open all selected notes
1080
return false; // Let Escape be handled by the window.
1083
void NoteRecentChanges::popup_context_menu_at_location(Gtk::Menu *menu, int x, int y)
1087
// Set up the funtion to position the context menu
1088
// if we were called by the keyboard Gdk.Key.Menu.
1089
if ((x == 0) && (y == 0)) {
1090
menu->popup (sigc::mem_fun(*this, &NoteRecentChanges::position_context_menu),
1091
0, gtk_get_current_event_time());
1094
menu->popup (0, gtk_get_current_event_time());
1098
// This is needed for when the user opens
1099
// the context menu with the keyboard.
1100
void NoteRecentChanges::position_context_menu(int & x, int & y, bool & push_in)
1102
// Set default "return" values
1103
push_in = false; // not used
1107
Gtk::Widget * const focus_widget = this->get_focus();
1110
focus_widget->get_window()->get_origin(x, y);
1112
Gtk::TreeView * const tree = dynamic_cast<Gtk::TreeView*>(
1116
const Glib::RefPtr<Gdk::Window> tree_area
1117
= tree->get_bin_window();
1120
tree_area->get_origin(x, y);
1122
const Glib::RefPtr<Gtk::TreeSelection> selection
1123
= tree->get_selection();
1124
const std::vector<Gtk::TreePath> selected_rows
1125
= selection->get_selected_rows();
1126
if (selected_rows.empty())
1129
const Gtk::TreePath & dest_path = selected_rows.front();
1130
const std::vector<Gtk::TreeViewColumn *> columns
1131
= tree->get_columns();
1132
Gdk::Rectangle cell_rect;
1133
tree->get_cell_area (dest_path, *columns.front(), cell_rect);
1135
x += cell_rect.get_x();
1136
y += cell_rect.get_y();
1140
Note::List NoteRecentChanges::get_selected_notes()
1142
Note::List selected_notes;
1144
std::vector<Gtk::TreePath> selected_rows =
1145
m_tree->get_selection()->get_selected_rows ();
1146
for(std::vector<Gtk::TreePath>::const_iterator iter
1147
= selected_rows.begin(); iter != selected_rows.end(); ++iter) {
1148
Note::Ptr note = get_note (*iter);
1153
selected_notes.push_back(note);
1156
return selected_notes;
1159
Note::Ptr NoteRecentChanges::get_note(const Gtk::TreePath & p)
1161
Gtk::TreeIter iter = m_store_sort->get_iter(p);
1163
return (*iter)[m_column_types.note];
1168
void NoteRecentChanges::on_open_note()
1170
Note::List selected_notes = get_selected_notes ();
1171
for(Note::List::iterator iter = selected_notes.begin(); iter != selected_notes.end(); ++iter) {
1172
(*iter)->get_window()->present();
104
if(m_window_menu_search) {
105
delete m_window_menu_search;
107
if(m_window_menu_note) {
108
delete m_window_menu_note;
110
if(m_window_menu_default) {
111
delete m_window_menu_default;
115
Gtk::Box *NoteRecentChanges::make_toolbar()
117
Gtk::Box *toolbar = manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL));
118
toolbar->set_border_width(5);
119
m_all_notes_button = manage(new Gtk::Button);
120
m_all_notes_button->set_image(*manage(new Gtk::Image(Gtk::Stock::FIND, Gtk::ICON_SIZE_BUTTON)));
121
m_all_notes_button->set_always_show_image(true);
122
m_all_notes_button->set_label(_("All Notes"));
123
m_all_notes_button->signal_clicked().connect(sigc::mem_fun(*this, &NoteRecentChanges::present_search));
124
m_all_notes_button->show_all();
125
toolbar->pack_start(*m_all_notes_button, false, false);
127
Gtk::Button *button = manage(new Gtk::Button);
128
button->set_image(*manage(new Gtk::Image(IconManager::obj().get_icon(IconManager::NOTE_NEW, 24))));
129
button->set_always_show_image(true);
130
button->set_label(_("New"));
131
button->signal_clicked().connect(sigc::mem_fun(m_search_notes_widget, &SearchNotesWidget::new_note));
133
toolbar->pack_start(*button, false, false);
135
m_search_entry.set_activates_default(false);
136
m_search_entry.set_size_request(300);
137
m_search_entry.signal_changed()
138
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_entry_changed));
139
m_search_entry.signal_activate()
140
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_entry_activated));
141
Gtk::Alignment *alignment = manage(new Gtk::Alignment(Gtk::ALIGN_CENTER, Gtk::ALIGN_CENTER, 0));
142
alignment->add(m_search_entry);
143
alignment->show_all();
144
toolbar->pack_start(*alignment, true, true);
146
button = manage(new Gtk::Button);
147
button->set_image(*manage(new Gtk::Image(IconManager::obj().get_icon("emblem-system-symbolic", 24))));
148
button->set_always_show_image(true);
149
button->signal_clicked().connect(
150
boost::bind(sigc::mem_fun(*this, &NoteRecentChanges::on_show_window_menu), button));
152
toolbar->pack_end(*button, false, false);
158
void NoteRecentChanges::present_search()
160
utils::EmbeddableWidget *current = currently_embedded();
161
if(&m_search_notes_widget == dynamic_cast<SearchNotesWidget*>(current)) {
165
background_embedded(*current);
167
foreground_embedded(m_search_notes_widget);
170
void NoteRecentChanges::present_note(const Note::Ptr & note)
172
embed_widget(*note->get_window());
176
void NoteRecentChanges::new_note()
178
std::vector<Gtk::Widget*> current = m_embed_box.get_children();
179
SearchNotesWidget *search_wgt = dynamic_cast<SearchNotesWidget*>(current.size() > 0 ? current[0] : NULL);
181
search_wgt->new_note();
184
present_note(m_note_manager.create());
189
void NoteRecentChanges::on_open_note(const Note::Ptr & note)
194
void NoteRecentChanges::on_open_note_new_window(const Note::Ptr & note)
196
MainWindow & window = IGnote::obj().new_main_window();
198
window.present_note(note);
1176
201
void NoteRecentChanges::on_delete_note()
1178
Note::List selected_notes = get_selected_notes ();
1179
if (selected_notes.empty()) {
1183
noteutils::show_deletion_dialog(selected_notes, this);
203
m_search_notes_widget.delete_selected_notes();
1188
208
void NoteRecentChanges::on_close_window()
1191
// Disconnect external signal handlers to prevent bloweup
1192
manager.NoteDeleted -= OnNotesChanged;
1193
manager.NoteAdded -= OnNotesChanged;
1194
manager.NoteRenamed -= OnNoteRenamed;
1195
manager.NoteSaved -= OnNoteSaved;
1197
Notebooks.NotebookManager.NoteAddedToNotebook -= OnNoteAddedToNotebook;
1198
Notebooks.NotebookManager.NoteRemovedFromNotebook -= OnNoteRemovedFromNotebook;
1200
// The following code has to be done for the MenuBar to
1201
// appear properly the next time this window is opened.
1203
if(Gnote::obj().windowed()) {
1204
m_content_vbox.remove (*m_menubar);
210
Preferences::obj().get_schema_settings(Preferences::SCHEMA_GNOTE)->set_boolean(
211
Preferences::MAIN_WINDOW_MAXIMIZED,
212
get_window()->get_state() & Gdk::WINDOW_STATE_MAXIMIZED);
213
std::vector<Gtk::Widget*> current = m_embed_box.get_children();
214
for(std::vector<Gtk::Widget*>::iterator iter = current.begin();
215
iter != current.end(); ++iter) {
216
utils::EmbeddableWidget *widget = dynamic_cast<utils::EmbeddableWidget*>(*iter);
218
background_embedded(*widget);
1207
am ["OpenNoteAction"].Activated -= OnOpenNote;
1208
am ["DeleteNoteAction"].Activated -= OnDeleteNote;
1209
am ["NewNotebookAction"].Activated -= OnNewNotebook;
1210
am ["DeleteNotebookAction"].Activated -= OnDeleteNotebook;
1211
am ["NewNotebookNoteAction"].Activated -= OnNewNotebookNote;
1212
am ["OpenNotebookTemplateNoteAction"].Activated -= OnOpenNotebookTemplateNote;
1213
am ["CloseWindowAction"].Activated -= OnCloseWindow;
1218
// Tomboy.ExitingEvent -= OnExitingEvent;
1221
if(Gnote::obj().windowed()) {
1248
258
void NoteRecentChanges::on_show()
1250
260
// Select "All Notes" in the notebooks list
1251
select_all_notes_notebook ();
1253
m_find_combo.get_entry()->grab_focus ();
1254
utils::ForcedPresentWindow::on_show();
1258
int NoteRecentChanges::compare_titles(const Gtk::TreeIter & a, const Gtk::TreeIter & b)
1260
std::string title_a = (*a)[m_column_types.title];
1261
std::string title_b = (*b)[m_column_types.title];
1263
if (title_a.empty() || title_b.empty())
1266
return title_a.compare(title_b);
1269
int NoteRecentChanges::compare_dates(const Gtk::TreeIter & a, const Gtk::TreeIter & b)
1271
Note::Ptr note_a = (*a)[m_column_types.note];
1272
Note::Ptr note_b = (*b)[m_column_types.note];
1274
if (!note_a || !note_b) {
1278
return sharp::DateTime::compare (note_a->change_date(), note_b->change_date());
1282
int NoteRecentChanges::compare_search_hits(const Gtk::TreeIter & a, const Gtk::TreeIter & b)
1284
Note::Ptr note_a = (*a)[m_column_types.note];
1285
Note::Ptr note_b = (*b)[m_column_types.note];
1287
if (!note_a || !note_b) {
1293
std::map<std::string, int>::iterator iter_a = m_current_matches.find(note_a->uri());
1294
std::map<std::string, int>::iterator iter_b = m_current_matches.find(note_b->uri());
1295
bool has_matches_a = (iter_a != m_current_matches.end());
1296
bool has_matches_b = (iter_b != m_current_matches.end());
1298
if (!has_matches_a || !has_matches_b) {
1299
if (has_matches_a) {
1306
matches_a = iter_a->second;
1307
matches_b = iter_b->second;
1308
int result = matches_a - matches_b;
1310
// Do a secondary sort by note title in alphabetical order
1311
result = compare_titles (a, b);
1313
// Make sure to always sort alphabetically
1316
Gtk::SortType sort_type;
1317
if (m_store_sort->get_sort_column_id (sort_col_id,
1319
if (sort_type == Gtk::SORT_DESCENDING)
1320
result = -result; // reverse sign
1331
void NoteRecentChanges::on_row_activated(const Gtk::TreePath & p, Gtk::TreeViewColumn*)
1333
Gtk::TreeIter iter = m_store_sort->get_iter (p);
1337
Note::Ptr note = (*iter)[m_column_types.note];
1339
note->get_window()->present ();
1341
// Tell the new window to highlight the matches and
1342
// prepopulate the Firefox-style search
1343
if (!get_search_text().empty()) {
1344
NoteFindBar & find(note->get_window()->get_find_bar());
1346
find.property_visible() = true;
1347
find.set_search_text(get_search_text());
1351
void NoteRecentChanges::on_entry_activated()
1353
if (m_entry_changed_timeout) {
1354
m_entry_changed_timeout->cancel ();
1357
entry_changed_timeout();
261
m_search_notes_widget.select_all_notes_notebook();
263
if(m_embed_box.get_children().size() == 0 && m_embedded_widgets.size() > 0) {
264
foreground_embedded(**m_embedded_widgets.rbegin());
266
std::vector<Gtk::Widget*> embedded = m_embed_box.get_children();
267
if(embedded.size() == 1 && embedded.front() == &m_search_notes_widget) {
268
m_search_entry.grab_focus();
270
MainWindow::on_show();
273
void NoteRecentChanges::set_search_text(const std::string & value)
275
m_search_entry.set_text(value);
278
void NoteRecentChanges::embed_widget(utils::EmbeddableWidget & widget)
280
if(std::find(m_embedded_widgets.begin(), m_embedded_widgets.end(), &widget) == m_embedded_widgets.end()) {
282
m_embedded_widgets.push_back(&widget);
284
utils::EmbeddableWidget *current = currently_embedded();
285
if(current && current != &widget) {
286
background_embedded(*current);
288
foreground_embedded(widget);
291
void NoteRecentChanges::unembed_widget(utils::EmbeddableWidget & widget)
293
bool show_other = false;
294
std::list<utils::EmbeddableWidget*>::iterator iter = std::find(
295
m_embedded_widgets.begin(), m_embedded_widgets.end(), &widget);
296
if(iter != m_embedded_widgets.end()) {
297
if(is_foreground(**iter)) {
298
background_embedded(widget);
301
m_embedded_widgets.erase(iter);
305
if(m_embedded_widgets.size()) {
306
foreground_embedded(**m_embedded_widgets.rbegin());
308
else if(get_visible()) {
314
void NoteRecentChanges::foreground_embedded(utils::EmbeddableWidget & widget)
317
if(currently_embedded() == &widget) {
320
Gtk::Widget &wid = dynamic_cast<Gtk::Widget&>(widget);
321
m_embed_box.pack_start(wid, true, true, 0);
324
update_toolbar(widget);
325
on_embedded_name_changed(widget.get_name());
326
m_current_embedded_name_slot = widget.signal_name_changed
327
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_embedded_name_changed));
329
catch(std::bad_cast&) {
333
void NoteRecentChanges::background_embedded(utils::EmbeddableWidget & widget)
336
if(currently_embedded() != &widget) {
339
m_current_embedded_name_slot.disconnect();
340
Gtk::Widget &wid = dynamic_cast<Gtk::Widget&>(widget);
342
m_embed_box.remove(wid);
344
catch(std::bad_cast&) {
348
bool NoteRecentChanges::is_foreground(utils::EmbeddableWidget & widget)
350
std::vector<Gtk::Widget*> current = m_embed_box.get_children();
351
for(std::vector<Gtk::Widget*>::iterator iter = current.begin();
352
iter != current.end(); ++iter) {
353
if(dynamic_cast<utils::EmbeddableWidget*>(*iter) == &widget) {
361
utils::EmbeddableWidget *NoteRecentChanges::currently_embedded()
363
std::vector<Gtk::Widget*> children = m_embed_box.get_children();
364
return children.size() ? dynamic_cast<utils::EmbeddableWidget*>(children[0]) : NULL;
367
bool NoteRecentChanges::on_map_event(GdkEventAny *evt)
369
bool res = MainWindow::on_map_event(evt);
374
void NoteRecentChanges::on_embedded_name_changed(const std::string & name)
378
title = "[" + name + "] - ";
1360
384
void NoteRecentChanges::on_entry_changed()
1362
if (m_entry_changed_timeout == NULL) {
1363
m_entry_changed_timeout = new utils::InterruptableTimeout ();
386
if(m_entry_changed_timeout == NULL) {
387
m_entry_changed_timeout = new utils::InterruptableTimeout();
1364
388
m_entry_changed_timeout->signal_timeout
1365
389
.connect(sigc::mem_fun(*this, &NoteRecentChanges::entry_changed_timeout));
1368
if (get_search_text().empty()) {
1369
m_clear_search_button.set_sensitive(false);
392
std::string search_text = get_search_text();
393
if(search_text.empty()) {
394
m_search_notes_widget.perform_search(search_text);
1373
m_entry_changed_timeout->reset (500);
1374
m_clear_search_button.set_sensitive(true);
1377
restore_matches_window();
1380
// Called in after .5 seconds of typing inactivity, or on
1381
// explicit activate. Redo the search, and update the
397
m_entry_changed_timeout->reset(500);
401
void NoteRecentChanges::on_entry_activated()
403
if(m_entry_changed_timeout) {
404
m_entry_changed_timeout->cancel();
407
entry_changed_timeout();
1383
410
void NoteRecentChanges::entry_changed_timeout()
1385
if (get_search_text().empty())
1389
add_to_previous_searches (get_search_text());
1393
void NoteRecentChanges::add_to_previous_searches(const std::string & text)
1395
// Update previous searches, by adding a new term to the
1396
// list, or shuffling an existing term to the top...
1397
bool repeat = false;
1399
std::string lower = sharp::string_to_lower(text);
1400
for(std::list<std::string>::const_iterator iter = s_previous_searches.begin();
1401
iter != s_previous_searches.end(); ++iter) {
1402
if (sharp::string_to_lower(*iter) == lower) {
1408
s_previous_searches.push_front(text);
1410
= Glib::RefPtr<Gtk::ListStore>::cast_dynamic(m_find_combo.get_model())->prepend();
1411
iter->set_value(0, text);
1415
void NoteRecentChanges::clear_search_clicked()
1417
m_find_combo.get_entry()->set_text("");
1418
m_find_combo.get_entry()->grab_focus ();
1422
void NoteRecentChanges::notebook_pixbuf_cell_data_func(Gtk::CellRenderer * renderer,
1423
const Gtk::TreeIter & iter)
1425
notebooks::Notebook::Ptr notebook;
1426
iter->get_value(0, notebook);
1430
Gtk::CellRendererPixbuf *crp = dynamic_cast<Gtk::CellRendererPixbuf*>(renderer);
1431
if (std::tr1::dynamic_pointer_cast<notebooks::AllNotesNotebook>(notebook)) {
1432
crp->property_pixbuf() = s_all_notes_icon;
1434
else if (std::tr1::dynamic_pointer_cast<notebooks::UnfiledNotesNotebook>(notebook)) {
1435
crp->property_pixbuf() = s_unfiled_notes_icon;
1438
crp->property_pixbuf() = s_notebook_icon;
1442
void NoteRecentChanges::notebook_text_cell_data_func(Gtk::CellRenderer * renderer,
1443
const Gtk::TreeIter & iter)
1445
Gtk::CellRendererText *crt = dynamic_cast<Gtk::CellRendererText*>(renderer);
1446
crt->property_ellipsize() = Pango::ELLIPSIZE_END;
1447
notebooks::Notebook::Ptr notebook;
1448
iter->get_value(0, notebook);
1450
crt->property_text() = "";
1454
crt->property_text() = notebook->get_name();
1456
if (std::tr1::dynamic_pointer_cast<notebooks::SpecialNotebook>(notebook)) {
1457
// Bold the "Special" Notebooks
1458
crt->property_markup() = str(boost::format("<span weight=\"bold\">%1%</span>")
1459
% notebook->get_name());
1462
crt->property_text() = notebook->get_name();
1467
void NoteRecentChanges::on_notebook_selection_changed()
1469
restore_matches_window();
1470
notebooks::Notebook::Ptr notebook = get_selected_notebook ();
1471
ActionManager & am(ActionManager::obj());
1473
// Clear out the currently selected tags so that no notebook is selected
1474
m_selected_tags.clear ();
1477
// Select the "All Notes" item without causing
1478
// this handler to be called again
1479
m_on_notebook_selection_changed_cid.block();
1480
select_all_notes_notebook ();
1481
am["DeleteNotebookAction"]->set_sensitive(false);
1482
m_on_notebook_selection_changed_cid.unblock();
1485
m_selected_tags.clear ();
1486
if (notebook->get_tag()) {
1487
m_selected_tags.insert(notebook->get_tag());
1489
bool allow_edit = false;
1490
if (std::tr1::dynamic_pointer_cast<notebooks::SpecialNotebook>(notebook)) {
1491
am["DeleteNotebookAction"]->set_sensitive(false);
1494
am["DeleteNotebookAction"]->set_sensitive(true);
1498
std::vector<Gtk::CellRenderer*> renderers = m_notebooksTree->get_column(0)->get_cells();
1499
for (std::vector<Gtk::CellRenderer*>::iterator renderer = renderers.begin();
1500
renderer != renderers.end(); ++renderer) {
1501
Gtk::CellRendererText *text_rederer = dynamic_cast<Gtk::CellRendererText*>(*renderer);
1503
text_rederer->property_editable() = allow_edit;
1511
void NoteRecentChanges::on_new_notebook()
1513
notebooks::NotebookManager::prompt_create_new_notebook (this);
1516
void NoteRecentChanges::on_delete_notebook()
1518
notebooks::Notebook::Ptr notebook = get_selected_notebook ();
1522
notebooks::NotebookManager::prompt_delete_notebook (this, notebook);
1526
// Create a new note in the notebook when activated
1527
void NoteRecentChanges::on_notebook_row_activated(const Gtk::TreePath & ,
1528
Gtk::TreeViewColumn*)
1530
on_new_notebook_note();
1533
void NoteRecentChanges::on_new_notebook_note()
1535
notebooks::Notebook::Ptr notebook = get_selected_notebook ();
1536
if (!notebook || std::tr1::dynamic_pointer_cast<notebooks::SpecialNotebook>(notebook)) {
1537
// Just create a standard note (not in a notebook)
1538
ActionManager::obj()["NewNoteAction"]->activate ();
1542
// Look for the template note and create a new note
1543
Note::Ptr note = notebook->create_notebook_note ();
1544
note->get_window()->show ();
1547
void NoteRecentChanges::on_open_notebook_template_note()
1549
notebooks::Notebook::Ptr notebook = get_selected_notebook ();
1553
Note::Ptr templateNote = notebook->get_template_note ();
1555
return; // something seriously went wrong
1557
templateNote->get_window()->present ();
1560
notebooks::Notebook::Ptr NoteRecentChanges::get_selected_notebook ()
1564
Glib::RefPtr<Gtk::TreeSelection> selection = m_notebooksTree->get_selection();
1566
return notebooks::Notebook::Ptr();
1568
iter = selection->get_selected();
1570
return notebooks::Notebook::Ptr(); // Nothing selected
1573
notebooks::Notebook::Ptr notebook;
1574
iter->get_value(0, notebook);
1578
void NoteRecentChanges::select_all_notes_notebook ()
1580
Glib::RefPtr<Gtk::TreeModel> model = m_notebooksTree->get_model();
1581
DBG_ASSERT(model, "model is NULL");
1585
Gtk::TreeIter iter = model->children().begin();
1587
m_notebooksTree->get_selection()->select(iter);
1592
bool NoteRecentChanges::on_notebooks_tree_button_pressed(GdkEventButton *ev)
1594
if(ev->button == 3) {
1595
// third mouse button (right-click)
1596
Gtk::TreeViewColumn * col = 0; // unused
1598
int cell_x, cell_y; // unused
1599
const Glib::RefPtr<Gtk::TreeSelection> selection
1600
= m_notebooksTree->get_selection();
1602
if (m_notebooksTree->get_path_at_pos(ev->x, ev->y, p, col,
1604
selection->select(p);
1607
notebooks::Notebook::Ptr notebook = get_selected_notebook ();
1609
return true; // Don't pop open a submenu
1611
Gtk::Menu *menu = dynamic_cast<Gtk::Menu*>(ActionManager::obj().get_widget (
1612
"/NotebooksTreeContextMenu"));
1614
popup_context_menu_at_location (menu,
1622
bool NoteRecentChanges::on_notebooks_key_pressed(GdkEventKey * ev)
1624
switch (ev->keyval) {
1627
// Pop up the context menu if a notebook is selected
1628
notebooks::Notebook::Ptr notebook = get_selected_notebook ();
1629
if (!notebook || std::tr1::dynamic_pointer_cast<notebooks::SpecialNotebook>(notebook))
1630
break; // Don't pop open a submenu
1632
Gtk::Menu *menu = dynamic_cast<Gtk::Menu *>(ActionManager::obj().get_widget (
1633
"/NotebooksTreeContextMenu"));
1634
popup_context_menu_at_location (menu, 0, 0);
1642
return false; // Let Escape be handled by the window.
1645
void NoteRecentChanges::on_note_added_to_notebook (const Note & ,
1646
const notebooks::Notebook::Ptr & )
1648
restore_matches_window();
1652
void NoteRecentChanges::on_note_removed_from_notebook (const Note & ,
1653
const notebooks::Notebook::Ptr & )
1655
restore_matches_window();
412
std::string search_text = get_search_text();
413
if(search_text.empty()) {
417
m_search_notes_widget.perform_search(search_text);
1660
420
std::string NoteRecentChanges::get_search_text()
1662
// Entry may be null if search window closes
1663
// early (bug #544996).
1664
if (m_find_combo.get_entry() == NULL) {
1667
std::string text = m_find_combo.get_entry()->get_text();
422
std::string text = m_search_entry.get_text();
1668
423
text = sharp::string_trim(text);
1672
void NoteRecentChanges::set_search_text(const std::string & value)
1674
if (!value.empty()) {
1675
m_find_combo.get_entry()->set_text(value);
1679
/// Save the position and size of the RecentChanges window
1681
void NoteRecentChanges::save_position ()
1689
get_size(width, height);
1691
Glib::RefPtr<Gio::Settings> settings = Preferences::obj()
1692
.get_schema_settings(Preferences::SCHEMA_GNOTE);
1693
settings->set_int(Preferences::SEARCH_WINDOW_X_POS, x);
1694
settings->set_int(Preferences::SEARCH_WINDOW_Y_POS, y);
1695
settings->set_int(Preferences::SEARCH_WINDOW_WIDTH, width);
1696
settings->set_int(Preferences::SEARCH_WINDOW_HEIGHT, height);
1697
settings->set_int(Preferences::SEARCH_WINDOW_SPLITTER_POS, m_hpaned.get_position());
1701
void NoteRecentChanges::restore_position()
1703
Glib::RefPtr<Gio::Settings> settings = Preferences::obj()
1704
.get_schema_settings(Preferences::SCHEMA_GNOTE);
1705
int x = settings->get_int(Preferences::SEARCH_WINDOW_X_POS);
1706
int y = settings->get_int(Preferences::SEARCH_WINDOW_Y_POS);
1707
int width = settings->get_int(Preferences::SEARCH_WINDOW_WIDTH);
1708
int height = settings->get_int(Preferences::SEARCH_WINDOW_HEIGHT);
1709
int pos = settings->get_int(Preferences::SEARCH_WINDOW_SPLITTER_POS);
1711
if((width == 0) || (height == 0)) {
1715
set_default_size(width, height);
1718
m_hpaned.set_position(pos);
1723
void NoteRecentChanges::on_exiting_event()
427
void NoteRecentChanges::update_toolbar(utils::EmbeddableWidget & widget)
429
bool search = dynamic_cast<SearchNotesWidget*>(&widget) == &m_search_notes_widget;
430
m_all_notes_button->set_sensitive(!search);
431
m_search_entry.set_visible(search);
434
void NoteRecentChanges::on_show_window_menu(Gtk::Button *button)
436
std::vector<Gtk::MenuItem*> items;
437
if(dynamic_cast<SearchNotesWidget*>(currently_embedded()) == &m_search_notes_widget) {
438
if(!m_window_menu_search) {
439
m_window_menu_search = make_window_menu(button,
440
make_menu_items(items, IActionManager::obj().get_main_window_search_actions()));
442
utils::popup_menu(*m_window_menu_search, NULL);
444
else if(dynamic_cast<NoteWindow*>(currently_embedded())) {
445
if(!m_window_menu_note) {
446
m_window_menu_note = make_window_menu(button,
447
make_menu_items(items, IActionManager::obj().get_main_window_note_actions()));
449
utils::popup_menu(*m_window_menu_note, NULL);
452
if(!m_window_menu_default) {
453
m_window_menu_default = make_window_menu(button, items);
455
utils::popup_menu(*m_window_menu_default, NULL);
459
Gtk::Menu *NoteRecentChanges::make_window_menu(Gtk::Button *button, const std::vector<Gtk::MenuItem*> & items)
461
Gtk::Menu *menu = new Gtk::Menu;
462
for(std::vector<Gtk::MenuItem*>::const_iterator iter = items.begin(); iter != items.end(); ++iter) {
463
menu->append(**iter);
466
menu->append(*manage(new Gtk::SeparatorMenuItem));
468
Gtk::MenuItem *item = manage(new Gtk::MenuItem(_("_Close"), true));
469
item->signal_activate().connect(sigc::mem_fun(*this, &NoteRecentChanges::on_close_window));
471
menu->property_attach_widget() = button;
476
std::vector<Gtk::MenuItem*> & NoteRecentChanges::make_menu_items(std::vector<Gtk::MenuItem*> & items,
477
const std::vector<Glib::RefPtr<Gtk::Action> > & actions)
479
for(std::vector<Glib::RefPtr<Gtk::Action> >::const_iterator iter = actions.begin(); iter != actions.end(); ++iter) {
480
Gtk::MenuItem *item = manage(new Gtk::MenuItem);
481
item->set_related_action(*iter);
482
items.push_back(item);
487
void NoteRecentChanges::on_main_window_actions_changed(Gtk::Menu **menu)