Listing 2: A GUI version of the wc program

/*
 * Paulo Pinto (pjmlp_pt@yahoo.com) (c) 2001
 * An GUI version of the wc program
 */
#include <gtk--/label.h>
#include <gtk--/fileselection.h>
#include <gnome--/main.h>
#include <gnome--/app.h>
#include <gnome--/stock.h>

#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cctype>

//Bring the slot binding command to global scope
using SigC::slot;

// Application
// A minimalist graphical view of wc
class GWCApp: public Gnome::App {
public:
  GWCApp ();
  virtual ~GWCApp ();

protected:
  gint delete_event_impl (GdkEventAny*);

  //Signal handlers:
  virtual void on_menu_open ();

  void process_file ();

private:
  bool count_words (const std::string &filename, int &words, 
    int &lines, int &bytes);
  void init_menus ();
  void init_toolbar ();

  Gtk::Label *m_text;
  Gtk::FileSelection *m_filesel;
};

// The program entry point.
// Just create a GWCApp instance and
// launch it.
// Please note that in ANSI C++ the
// return is optional
int main (int argc, char *argv [])
{
  // Initialize the framework
  Gnome::Main kit ("gwc", "0.0.1", argc, argv);
  GWCApp app;

  // Make the window appear
  app.show ();

  // Enter into the event loop
  kit.run ();
}



GWCApp::GWCApp ():
  Gnome::App ("gwc", "GWC")
{
  // Create the text label for showing the word count
  m_text = new Gtk::Label ("No file counted");

  // Set the window contents. Please note that
  // m_text must be deleted explicitly.
  // It is deleted in GWCApp::~GWCApp ()
  set_contents (*m_text);

  // Create the dialog box for opening files
  // We don't need to create it here but this
  // is just for ilustrive purposes.
  m_filesel = manage (new Gtk::FileSelection ("Open File"));

  // Connect the ok_button to file_ok_sel function
  m_filesel->get_ok_button()->clicked.connect(slot(this, 
    &GWCApp::process_file));

  // Connect the cancel_button to hide the window
  m_filesel->get_cancel_button()->clicked.connect
    (m_filesel->hide.slot());
  
  init_menus ();
  init_toolbar ();
}


GWCApp::~GWCApp ()
{
  // Delete the label. We don't need to delete
  // the file selection because it is handled
  // by manage.
  delete m_text;
}

// Creates the application menus
void GWCApp::init_menus ()
{
  // Create a file menu using helper functios.
  // There are other ways of building menus but this
  // is the easiest.
  using namespace Gnome;
  using namespace Gtk::Menu_Helpers;
  
  // Entries for the file submenu
  UI::Info file_menu[] = { MenuItems::Open (slot (this, 
    &GWCApp::on_menu_open)),
               UI::Separator(),
               MenuItems::Exit(Gtk::Main::quit.slot ())
  };

  // This is the for the menu toolbar
  UI::SubTree menus[] = { Menus::File(file_menu) };
  
  //  Create and attach the menus to the
  // application window
  create_menus(menus);
}



// Creates the application toolbar
void GWCApp::init_toolbar ()
{
  // Create a toolbar using helper functios.
  using namespace Gnome;

  UI::Info toolbar[] = {UI::Item(UI::Icon(GNOME_STOCK_PIXMAP_OPEN),
                                "Open", slot(this, 
                                  &GWCApp::on_menu_open),
                                "Open a file"),
                        UI::Separator (),
                        UI::Item(UI::Icon(GNOME_STOCK_PIXMAP_EXIT),
                                 "Exit", Gtk::Main::quit.slot (),
                                 "Exit the application")
                       };
  
  //  Create and attach the toolbar to the
  // application window
  create_toolbar(toolbar);
}



//  Called when the user presses the 'X' mark
// on the window.
//  Redefining this method is another way of
// receiving the 'delete' signal.
gint GWCApp::delete_event_impl(GdkEventAny*)
{ 
  Gtk::Main::quit();
  return FALSE; 
}


//  Called when the user selects the
// File->Open option
void GWCApp::on_menu_open ()
{
  m_filesel->set_modal (true);
  m_filesel->show ();
}

//  Called when the user presses the
// Ok button on the FileSelection dialog
void GWCApp::process_file ()
{
  m_filesel->hide ();
  std::string filename = m_filesel->get_filename ();
  int words, lines, bytes;
  std::ostringstream msg;

  // Clear and force a redraw, or else
  // the older string will appear
  m_text->set_text ("");
  draw (0);

  if (!count_words (filename, words, lines, bytes)) {
    msg << "Couldn't open " << filename;
    Gnome::Dialogs::error (msg.str ());
  }
  else {
    msg << "The file " << filename;
    msg << ", has " << lines << " lines, " << words << " words and ";        
    msg << bytes << " bytes." ;

    m_text->set_text (msg.str ());
  }
}

// Counts all the words, lines and bytes.
// This isn't the most eficient way to do it, but
// it servers the purpose of the example.
bool GWCApp::count_words (const std::string &filename, int &words, 
  int &lines, int &bytes)
{
  std::ifstream in (filename.c_str ());
  if (!in)
     return false;

  words = 0;
  lines = 0;
  bytes = 0;
  char ch;
  while (!in.eof ()) {
    // Advance the file pointer to the next
    // word
    do {
      in.get (ch);
      if (!in.eof ()){
        bytes++;

        // Ok, now changing for the next line
        if (ch == '\n')
          lines++;
      }
    } while (!in.eof () && isspace (ch));

    // Advance the file pointer to the next
    // white space
    if (!in.eof ()) {
      words++;
      do {
        in.get (ch);
        if (!in.eof ())
          bytes++;
      } while (!in.eof () && !isspace (ch));
    }
  }

  return true;
}
— End of Listing —