1 /*
2  * gnote
3  *
4  * Copyright (C) 2013-2014,2017,2019 Aurimas Cernius
5  *
6  * This program is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 
21 #include <glibmm/i18n.h>
22 #include <gtkmm/treestore.h>
23 
24 #include "debug.hpp"
25 #include "ignote.hpp"
26 #include "itagmanager.hpp"
27 #include "statisticswidget.hpp"
28 #include "notebooks/notebookmanager.hpp"
29 
30 
31 namespace statistics {
32 
33 class StatisticsModel
34   : public Gtk::TreeStore
35 {
36 public:
37   typedef Glib::RefPtr<StatisticsModel> Ptr;
create(gnote::IGnote & g,gnote::NoteManager & nm)38   static Ptr create(gnote::IGnote & g, gnote::NoteManager & nm)
39     {
40       return Ptr(new StatisticsModel(g, nm));
41     }
42 
update()43   void update()
44     {
45       if(m_active) {
46         build_stats();
47       }
48     }
49 
active(bool is_active)50   void active(bool is_active)
51     {
52       m_active = is_active;
53     }
54 private:
55   class StatisticsRecord
56     : public Gtk::TreeModelColumnRecord
57   {
58   public:
StatisticsRecord()59     StatisticsRecord()
60       {
61         add(m_stat);
62         add(m_value);
63       }
64   private:
65     Gtk::TreeModelColumn<Glib::ustring> m_stat;
66     Gtk::TreeModelColumn<Glib::ustring> m_value;
67   };
68   StatisticsRecord m_columns;
69 
StatisticsModel(gnote::IGnote & g,gnote::NoteManager & nm)70   StatisticsModel(gnote::IGnote & g, gnote::NoteManager & nm)
71     : m_gnote(g)
72     , m_note_manager(nm)
73     , m_active(false)
74     {
75       set_column_types(m_columns);
76       build_stats();
77       nm.signal_note_added.connect(sigc::mem_fun(*this, &StatisticsModel::on_note_list_changed));
78       nm.signal_note_deleted.connect(sigc::mem_fun(*this, &StatisticsModel::on_note_list_changed));
79       g.notebook_manager().signal_note_added_to_notebook()
80         .connect(sigc::mem_fun(*this, &StatisticsModel::on_notebook_note_list_changed));
81       g.notebook_manager().signal_note_removed_from_notebook()
82         .connect(sigc::mem_fun(*this, &StatisticsModel::on_notebook_note_list_changed));
83     }
84 
build_stats()85   void build_stats()
86     {
87       clear();
88       gnote::NoteBase::List notes = m_note_manager.get_notes();
89 
90       Gtk::TreeIter iter = append();
91       Glib::ustring stat = _("Total Notes:");
92       iter->set_value(0, stat);
93       iter->set_value(1, TO_STRING(notes.size()));
94 
95       Glib::RefPtr<Gtk::TreeModel> notebooks = m_gnote.notebook_manager().get_notebooks();
96       iter = append();
97       stat = _("Total Notebooks:");
98       iter->set_value(0, stat);
99       iter->set_value(1, TO_STRING(notebooks->children().size()));
100 
101       Gtk::TreeIter notebook = notebooks->children().begin();
102       std::map<gnote::notebooks::Notebook::Ptr, int> notebook_notes;
103       while(notebook) {
104         gnote::notebooks::Notebook::Ptr nbook;
105         notebook->get_value(0, nbook);
106         notebook_notes[nbook] = 0;
107         ++notebook;
108       }
109       gnote::Tag::Ptr template_tag = m_note_manager.tag_manager().get_or_create_system_tag(
110         gnote::ITagManager::TEMPLATE_NOTE_SYSTEM_TAG);
111       for(gnote::NoteBase::Ptr note : notes) {
112         for(std::map<gnote::notebooks::Notebook::Ptr, int>::iterator nb = notebook_notes.begin();
113             nb != notebook_notes.end(); ++nb) {
114           if(note->contains_tag(nb->first->get_tag()) && !note->contains_tag(template_tag)) {
115             ++nb->second;
116           }
117         }
118       }
119       std::map<Glib::ustring, int> notebook_stats;
120       for(std::map<gnote::notebooks::Notebook::Ptr, int>::iterator nb = notebook_notes.begin();
121           nb != notebook_notes.end(); ++nb) {
122         notebook_stats[nb->first->get_name()] = nb->second;
123       }
124       for(auto nb : notebook_stats) {
125         Gtk::TreeIter nb_stat = append(iter->children());
126         nb_stat->set_value(0, nb.first);
127         // TRANSLATORS: %1 is the format placeholder for the number of notes.
128         char *fmt = ngettext("%1 note", "%1 notes", nb.second);
129         nb_stat->set_value(1, Glib::ustring::compose(fmt, nb.second));
130       }
131 
132       DBG_OUT("Statistics updated");
133     }
134 
on_note_list_changed(const gnote::NoteBase::Ptr &)135   void on_note_list_changed(const gnote::NoteBase::Ptr &)
136     {
137       update();
138     }
139 
on_notebook_note_list_changed(const gnote::Note &,const gnote::notebooks::Notebook::Ptr &)140   void on_notebook_note_list_changed(const gnote::Note &, const gnote::notebooks::Notebook::Ptr &)
141     {
142       update();
143     }
144 
145   gnote::IGnote & m_gnote;
146   gnote::NoteManager & m_note_manager;
147   bool m_active;
148 };
149 
150 
StatisticsWidget(gnote::IGnote & g,gnote::NoteManager & nm)151 StatisticsWidget::StatisticsWidget(gnote::IGnote & g, gnote::NoteManager & nm)
152   : Gtk::TreeView(StatisticsModel::create(g, nm))
153 {
154   set_hexpand(true);
155   set_vexpand(true);
156   StatisticsModel::Ptr model = StatisticsModel::Ptr::cast_dynamic(get_model());
157   set_model(model);
158   set_headers_visible(false);
159 
160   Gtk::CellRendererText *renderer = manage(new Gtk::CellRendererText);
161   Gtk::TreeViewColumn *column = manage(new Gtk::TreeViewColumn("", *renderer));
162   column->set_cell_data_func(*renderer, sigc::mem_fun(*this, &StatisticsWidget::col1_data_func));
163   append_column(*column);
164 
165   renderer = manage(new Gtk::CellRendererText);
166   column = manage(new Gtk::TreeViewColumn("", *renderer));
167   column->set_cell_data_func(*renderer, sigc::mem_fun(*this, &StatisticsWidget::col2_data_func));
168   append_column(*column);
169 }
170 
get_name() const171 Glib::ustring StatisticsWidget::get_name() const
172 {
173   return _("Statistics");
174 }
175 
foreground()176 void StatisticsWidget::foreground()
177 {
178   gnote::EmbeddableWidget::foreground();
179   StatisticsModel::Ptr model = StatisticsModel::Ptr::cast_static(get_model());
180   model->active(true);
181   model->update();
182   expand_all();
183 }
184 
background()185 void StatisticsWidget::background()
186 {
187   gnote::EmbeddableWidget::background();
188   StatisticsModel::Ptr::cast_static(get_model())->active(false);
189 }
190 
col1_data_func(Gtk::CellRenderer * renderer,const Gtk::TreeIter & iter)191 void StatisticsWidget::col1_data_func(Gtk::CellRenderer *renderer, const Gtk::TreeIter & iter)
192 {
193   Glib::ustring val;
194   iter->get_value(0, val);
195   static_cast<Gtk::CellRendererText*>(renderer)->property_markup() = "<b>" + val + "</b>";
196 }
197 
col2_data_func(Gtk::CellRenderer * renderer,const Gtk::TreeIter & iter)198 void StatisticsWidget::col2_data_func(Gtk::CellRenderer *renderer, const Gtk::TreeIter & iter)
199 {
200   Glib::ustring val;
201   iter->get_value(1, val);
202   static_cast<Gtk::CellRendererText*>(renderer)->property_text() = val;
203 }
204 
205 }
206 
207