"Fossies" - the Fresh Open Source Software Archive 
Member "regexxer-0.10/src/statusline.cc" (6 Oct 2011, 8891 Bytes) of package /linux/privat/old/regexxer-0.10.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "statusline.cc" see the
Fossies "Dox" file reference documentation.
1 /*
2 * Copyright (c) 2002-2007 Daniel Elstner <daniel.kitta@gmail.com>
3 *
4 * This file is part of regexxer.
5 *
6 * regexxer 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 2 of the License, or
9 * (at your option) any later version.
10 *
11 * regexxer 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 regexxer; if not, write to the Free Software Foundation,
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 #include "statusline.h"
22 #include "stringutils.h"
23 #include "translation.h"
24
25 #include <gdk/gdkkeysyms.h>
26 #include <gtkmm.h>
27 #include <locale>
28 #include <sstream>
29 #include <stdexcept>
30
31 namespace Regexxer
32 {
33
34 /**** Regexxer::CounterBox *************************************************/
35
36 class CounterBox : public Gtk::Frame
37 {
38 public:
39 explicit CounterBox(const Glib::ustring& label);
40 virtual ~CounterBox();
41
42 void set_index(int index);
43 void set_count(int count);
44
45 private:
46 enum { MIN_RANGE = 100 };
47
48 Gtk::Label* label_index_;
49 Gtk::Label* label_count_;
50 int digits_range_;
51 int widest_digit_;
52 int second_widest_digit_;
53 std::wostringstream stringstream_;
54
55 Glib::ustring number_to_string(int number);
56
57 void recalculate_label_width();
58 void on_label_style_updated();
59 };
60
61 CounterBox::CounterBox(const Glib::ustring& label)
62 :
63 label_index_ (0),
64 label_count_ (0),
65 digits_range_ (MIN_RANGE),
66 widest_digit_ (0),
67 second_widest_digit_ (9)
68 {
69 using namespace Gtk;
70
71 set_shadow_type(SHADOW_ETCHED_IN);
72
73 Box *const paddingbox = new HBox(false, 0);
74 add(*manage(paddingbox));
75
76 Box *const box = new HBox(false, 0);
77 paddingbox->pack_start(*manage(box), PACK_SHRINK, 2);
78
79 box->pack_start(*manage(new Label(label + ' ')), PACK_SHRINK);
80
81 label_index_ = new Label("", 1.0, 0.5);
82 box->pack_start(*manage(label_index_), PACK_SHRINK);
83
84 box->pack_start(*manage(new Label("/")), PACK_SHRINK, 2);
85
86 label_count_ = new Label("", 0.0, 0.5);
87 box->pack_start(*manage(label_count_), PACK_SHRINK);
88
89 label_index_->set_single_line_mode(true);
90 label_count_->set_single_line_mode(true);
91
92 label_index_->signal_style_updated().connect(
93 sigc::mem_fun(*this, &CounterBox::on_label_style_updated));
94
95 try // don't abort if the user-specified locale doesn't exist
96 {
97 stringstream_.imbue(std::locale(""));
98 }
99 catch (const std::runtime_error& error)
100 {
101 g_warning("%s", error.what());
102 }
103
104 set_index(0);
105 set_count(0);
106
107 paddingbox->show_all();
108 }
109
110 CounterBox::~CounterBox()
111 {}
112
113 void CounterBox::set_index(int index)
114 {
115 label_index_->set_text(number_to_string(index));
116
117 // Work around a bug in GTK+ that causes right-aligned labels to be
118 // cut off at the end. Forcing resize seems to solve the problem.
119 check_resize();
120 }
121
122 void CounterBox::set_count(int count)
123 {
124 int range = digits_range_;
125
126 while (range <= count)
127 range *= 10;
128
129 while (range > MIN_RANGE && range / 10 > count)
130 range /= 10;
131
132 if (range != digits_range_)
133 {
134 digits_range_ = range;
135 recalculate_label_width();
136 }
137
138 label_count_->set_text(number_to_string(count));
139 }
140
141 Glib::ustring CounterBox::number_to_string(int number)
142 {
143 stringstream_.str(std::wstring());
144 stringstream_ << number;
145 return Util::wstring_to_utf8(stringstream_.str());
146 }
147
148 /*
149 * This tricky piece of code calculates the optimal label width for any
150 * number < digits_range_. It does assume the decimal system is used,
151 * but it relies neither on the string representation of the digits nor
152 * on the font of the label.
153 */
154 void CounterBox::recalculate_label_width()
155 {
156 int widest_number = 0;
157
158 if (widest_digit_ != 0)
159 {
160 // E.g. range 1000 becomes 222 if '2' is the widest digit of the font.
161 widest_number = ((digits_range_ - 1) / 9) * widest_digit_;
162 }
163 else // eeeks, 0 has to be special-cased
164 {
165 g_assert(second_widest_digit_ != 0);
166
167 // E.g. range 1000 becomes 900 if '9' is the 2nd-widest digit.
168 widest_number = (digits_range_ / 10) * second_widest_digit_;
169 }
170
171 int width = 0, height = 0, xpad = 0, ypad = 0;
172
173 const Glib::ustring text = number_to_string(widest_number);
174 label_index_->create_pango_layout(text)->get_pixel_size(width, height);
175
176 label_index_->get_padding(xpad, ypad);
177 label_index_->set_size_request(width + 2 * xpad, -1);
178
179 label_count_->get_padding(xpad, ypad);
180 label_count_->set_size_request(width + 2 * xpad, -1);
181 }
182
183 /*
184 * The code relies on both labels having the same style.
185 * I think that's a quite safe assumption to make ;)
186 */
187 void CounterBox::on_label_style_updated()
188 {
189 const Glib::RefPtr<Pango::Layout> layout = label_index_->create_pango_layout("");
190
191 widest_digit_ = 0;
192 second_widest_digit_ = 9;
193
194 int max_width = 0;
195 int second_max_width = 0;
196
197 int width = 0;
198 int height = 0;
199
200 for (int digit = 0; digit <= 9; ++digit)
201 {
202 layout->set_text(number_to_string(digit));
203 layout->get_pixel_size(width, height);
204
205 if (width > max_width)
206 {
207 max_width = width;
208 widest_digit_ = digit;
209 }
210 else if (width > second_max_width)
211 {
212 second_max_width = width;
213 second_widest_digit_ = digit;
214 }
215 }
216
217 recalculate_label_width();
218 }
219
220 /**** Regexxer::StatusLine *************************************************/
221
222 StatusLine::StatusLine()
223 :
224 Gtk::HBox(false, 3),
225 stop_button_ (0),
226 progressbar_ (0),
227 file_counter_ (0),
228 match_counter_ (0),
229 statusbar_ (0)
230 {
231 using namespace Gtk;
232
233 // The statusbar looks ugly if the stop button gets its default size,
234 // so let's reduce the button's size request to a reasonable amount.
235
236 std::string style = "GtkButton#regexxer-stop-button\n"
237 "{\n"
238 " padding-left: 0;"
239 " -GtkWidget-interior-focus: 0;\n"
240 " -GtkWidget-focus-padding: 0;\n"
241 "}";
242 Glib::RefPtr<Gtk::CssProvider> css = Gtk::CssProvider::create();
243 css->load_from_data(style);
244
245 stop_button_ = new Button(_("Stop"));
246 pack_start(*manage(stop_button_), PACK_SHRINK);
247 stop_button_->set_name("regexxer-stop-button");
248 stop_button_->get_style_context()->add_provider(css, 1);
249
250 progressbar_ = new ProgressBar();
251 pack_start(*manage(progressbar_), PACK_SHRINK);
252
253 file_counter_ = new CounterBox(_("File:"));
254 pack_start(*manage(file_counter_), PACK_SHRINK);
255
256 match_counter_ = new CounterBox(_("Match:"));
257 pack_start(*manage(match_counter_), PACK_SHRINK);
258
259 statusbar_ = new Statusbar();
260 pack_start(*manage(statusbar_), PACK_EXPAND_WIDGET);
261
262 stop_button_->set_sensitive(false);
263 stop_button_->signal_clicked().connect(signal_cancel_clicked.make_slot());
264
265 progressbar_->set_pulse_step(0.025);
266
267 stop_button_->get_accessible()->set_description(_("Cancels the running search"));
268
269 show_all_children();
270 }
271
272 StatusLine::~StatusLine()
273 {}
274
275 void StatusLine::set_file_index(int file_index)
276 {
277 file_counter_->set_index(file_index);
278 }
279
280 void StatusLine::set_file_count(int file_count)
281 {
282 file_counter_->set_count(file_count);
283 }
284
285 void StatusLine::set_match_index(int match_index)
286 {
287 match_counter_->set_index(match_index);
288 }
289
290 void StatusLine::set_match_count(int match_count)
291 {
292 match_counter_->set_count(match_count);
293 }
294
295 void StatusLine::set_file_encoding(const std::string& file_encoding)
296 {
297 statusbar_->pop();
298
299 const Glib::ustring encoding = file_encoding;
300 g_return_if_fail(encoding.is_ascii());
301
302 statusbar_->push(encoding);
303
304 // Work around a bug in GTK+ that causes right-aligned labels (note that
305 // the status bar text is right-aligned in RTL locales) to be cut off at
306 // the end. Forcing resize seems to solve the problem.
307 statusbar_->check_resize();
308 }
309
310 void StatusLine::pulse_start()
311 {
312 stop_button_->set_sensitive(true);
313 }
314
315 void StatusLine::pulse()
316 {
317 progressbar_->pulse();
318 }
319
320 void StatusLine::pulse_stop()
321 {
322 progressbar_->set_fraction(0.0);
323 stop_button_->set_sensitive(false);
324 }
325
326 void StatusLine::on_hierarchy_changed(Gtk::Widget* previous_toplevel)
327 {
328 if (Gtk::Window *const window = dynamic_cast<Gtk::Window*>(previous_toplevel))
329 {
330 stop_button_->remove_accelerator(
331 window->get_accel_group(), GDK_KEY_Escape, Gdk::ModifierType(0));
332 }
333
334 Gtk::HBox::on_hierarchy_changed(previous_toplevel);
335
336 if (Gtk::Window *const window = dynamic_cast<Gtk::Window*>(get_toplevel()))
337 {
338 stop_button_->add_accelerator(
339 "activate", window->get_accel_group(),
340 GDK_KEY_Escape, Gdk::ModifierType(0), Gtk::AccelFlags(0));
341 }
342 }
343
344 } // namespace Regexxer