"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