From ea318d1431c89e647598c510c4245c6571aa5f46 Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Thu, 26 Jan 2012 23:32:43 -0600 Subject: Update to latest tqt3 automated conversion --- doc/html/designer-manual-3.html | 234 ++++++++++++++++++++-------------------- 1 file changed, 117 insertions(+), 117 deletions(-) (limited to 'doc/html/designer-manual-3.html') diff --git a/doc/html/designer-manual-3.html b/doc/html/designer-manual-3.html index c46a8a8cb..4570aee86 100644 --- a/doc/html/designer-manual-3.html +++ b/doc/html/designer-manual-3.html @@ -36,7 +36,7 @@ body { background: #ffffff; color: black; }

The Color Tool application

The colortool application is a multiplatform application that allows users to create, edit and save lists of colors. Each color has a user defined name and an RGB (Red, Green, Blue) value.

-

This application presents the user with a view of a set of colors and their names. We will provide two views (using a TQWidgetStack) which the user can switch between. The tabular view will show each color as a small square followed by its name and hex value. It will also provide the option of an indicator to show whether or not the color is one of the 216 standard web colors. The iconic view will show each color as a circular color swatch with the name of the color beneath.

+

This application presents the user with a view of a set of colors and their names. We will provide two views (using a TQWidgetStack) which the user can switch between. The tabular view will show each color as a small square followed by its name and hex value. It will also provide the option of an indicator to show whether or not the color is one of the 216 standard web colors. The iconic view will show each color as a circular color swatch with the name of the color beneath.

The application will read and write files in the format used by the X Consortium for the rgb.txt file. This will allow users to create their own color files and to load, edit and save rgb.txt format files.

We will provide a simple search option so that users can tquickly locate a color; this is particularly useful when hundreds or thousands of colors are shown. The search will be provided in a modeless dialog so that the user can conduct a search but still interact with the main form. We will also enable the user to add and delete colors, and to set some user options. To provide these facilities, we must create some modal dialogs.

Finally, we must ensure that the application loads user options at start up and saves user options at termination. We will also include the view and the size and position of the main window with these options, so that the application will always start with the size, position and view it had when the user last used it.

@@ -69,18 +69,18 @@ body { background: #ffffff; color: black; }

The New File dialog is used to create all the files that can be used in a TQt Designer project. This includes C++ source files, an automatically generated main.cpp file (if you are in a project), and a variety of forms based on pre-defined templates. (You can create your own templates too.)

-

For the colortool application we want to start with a main window form. When we create this form, TQt Designer will present a wizard which we can use to automatically create menu and toolbar options and automatically create the relevant signal/slot connections. For every menu option or toolbar button, TQt Designer will create a single TQAction (see the Actions and Action Groups sidebar).

+

For the colortool application we want to start with a main window form. When we create this form, TQt Designer will present a wizard which we can use to automatically create menu and toolbar options and automatically create the relevant signal/slot connections. For every menu option or toolbar button, TQt Designer will create a single TQAction (see the Actions and Action Groups sidebar).

Actions and Action Groups

An action is an operation that the user initiates through the user interface, for example, saving a file or changing some text's font weight to bold.

-

We often want the user to be able to perform an action using a variety of means. For example, to save a file we might want the user to be able to press Ctrl+S, or to click the Save toolbar button or to click the File|Save menu option. Although the means of invoking the action are all different, the underlying operation is the same and we don't want to duplicate the code that performs the operation. In TQt we can create an action (a TQAction object) which will call the appropriate function when the action is invoked. We can assign an accelerator, (e.g. Ctrl+S), to an action. We can also add an action to a menu and to a toolbar.

+

We often want the user to be able to perform an action using a variety of means. For example, to save a file we might want the user to be able to press Ctrl+S, or to click the Save toolbar button or to click the File|Save menu option. Although the means of invoking the action are all different, the underlying operation is the same and we don't want to duplicate the code that performs the operation. In TQt we can create an action (a TQAction object) which will call the appropriate function when the action is invoked. We can assign an accelerator, (e.g. Ctrl+S), to an action. We can also add an action to a menu and to a toolbar.

If the action has an on/off state, e.g. bold is on or off, when the user changes the state, for example by clicking a toolbar button, the state of everything associated with the action, e.g. menu items and toolbar buttons, is updated.

Some actions should operate together like radio buttons. For example, if we have left align, center align and right align actions, only one should be 'on' at any one time. An action group (a TQActionGroup object) is used to group a set of actions together. If the action group's exclusive property is TRUE then only one of the actions in the group can be on at any one time. If the user changes the state of an action in an action group where exclusive is TRUE, everything associated with the actions in the action group, e.g. menu items and toolbar buttons, is updated.

TQt Designer can create actions and action groups visually, assign accelerators to them, and associate them with menu items and toolbar buttons.

Creating the Main Window

We will use the Main Window Wizard to build a main window. The wizard allows us to create actions as well as a menu bar and a toolbar through which the user can invoke the actions. We will also create our own actions, menus and toolbar buttons, and add a main widget to the main window.

-

Click File|New to invoke the New File dialog, click "Main Window" to create a main window form, then click OK. A new TQMainWindow form will be created and the Main Window Wizard will pop up.

+

Click File|New to invoke the New File dialog, click "Main Window" to create a main window form, then click OK. A new TQMainWindow form will be created and the Main Window Wizard will pop up.

Using the Main Window Wizard

  1. The Choose available menus and toolbars page appears first. It presents three categories of default actions, File Actions, Edit Actions and Help Actions. For each category you can choose to have TQt Designer create menu items, toolbar buttons, and signal/slots connections for the relevant actions. You can always add or delete actions, menu items, toolbar buttons, and connections later.

    We will accept the defaults for File Actions and for the Edit Actions, i.e. have menu items, toolbar buttons and the relevant connections created. In fact we'll be changing the Edit actions considerably later on, but it is still convenient to create them now. We won't have any Help Actions on the toolbar so uncheck the Help Action's Toolbar checkbox. Click Next to move on to the next wizard page.

    @@ -160,7 +160,7 @@ body { background: #ffffff; color: black; }

    All the actions in an action group are added to a toolbar in one go, simply by dragging the action group from the Action Editor and dropping it on the toolbar.

    Since toolbar buttons normally only show an image, all actions that are to be used in toolbars should have their iconSet property set to a suitable image.

    Toolbar buttons and separators (usually represented as indented vertical gray lines), can be dragged and dropped into new positions in the toolbar at any time. Separators can be inserted by right clicking a toolbar button and clicking Insert Separator. Toolbar buttons and separators can be deleted by right clicking them and then clicking Delete Item. Toolbars can be deleted by right clicking their toolbar handle and then clicking Delete Toolbar.

    -

    If you preview an application you'll find that all the toolbars can be dragged to different docking points (top, left, right and bottom of a TQMainWindow or subclass), or dragged out of the application as independent tool windows.

    +

    If you preview an application you'll find that all the toolbars can be dragged to different docking points (top, left, right and bottom of a TQMainWindow or subclass), or dragged out of the application as independent tool windows.

    Adding Widgets to the Toolbar

    @@ -205,7 +205,7 @@ body { background: #ffffff; color: black; }

    Click the viewActionGroup action group in the Action Editor, and drag it to the View menu; drop it on this menu (when the horizontal red line appears beneath the View menu). Because we dragged the action group, all its actions (in our case the viewTableAction and viewIconsAction) are added to the relevant menu. We'll also make the view actions available on the toolbar. Click the viewActionGroup once again, and drag it to the toolbar; drop it the right of the separator at the far right of the toolbar, and drop it on the toolbar's edge. (Again, a vertical red line will indicate the position.)

    Don't forget that you can preview to see things in action with Ctrl+T, and to click File|Save (or press Ctrl+S) regularly! If you preview now you will find that if you click the view toolbar buttons and menu options that both the toolbar buttons and the menu items automatically stay in sync.

    Creating the Main Widget

    -

    Most main-window style applications consist of a menu bar, a toolbar, a status bar and a central widget. We've already created a menu bar and toolbar, and since we've created a TQMainWindow (via the main window wizard), we also have a status bar. Widgets commonly used as an application's main widget are TQListView (which provides a tree view), TQTable and TQTextEdit. Since we want to provide our users with two different views of the same data, we'll use a TQWidgetStack as our main widget. The TQWidgetStack has no visual representation of its own; you place one or more widgets on each TQWidgetStack "page", as if each page was a form in its own right, and then provide the user with some mechanism for switching between pages. (This is similar in principle to using a TQTabWidget.) We want to provide our users with two views: a tabular view that lists colors and their names, and an icon-based view that shows color swatches. In our example we only place a single widget on each TQWidgetStack page; but this merely reflects the application's design -- we could have placed any number of widgets on each page.

    +

    Most main-window style applications consist of a menu bar, a toolbar, a status bar and a central widget. We've already created a menu bar and toolbar, and since we've created a TQMainWindow (via the main window wizard), we also have a status bar. Widgets commonly used as an application's main widget are TQListView (which provides a tree view), TQTable and TQTextEdit. Since we want to provide our users with two different views of the same data, we'll use a TQWidgetStack as our main widget. The TQWidgetStack has no visual representation of its own; you place one or more widgets on each TQWidgetStack "page", as if each page was a form in its own right, and then provide the user with some mechanism for switching between pages. (This is similar in principle to using a TQTabWidget.) We want to provide our users with two views: a tabular view that lists colors and their names, and an icon-based view that shows color swatches. In our example we only place a single widget on each TQWidgetStack page; but this merely reflects the application's design -- we could have placed any number of widgets on each page.

    Click the Toolbox's Containers button, then click WidgetStack. Click approximately in the middle of the form to place the widget stack. Change the widget stack's name property to "colorWidgetStack".

    @@ -263,16 +263,16 @@ body { background: #ffffff; color: black; }
    • class TQString;

    • class TQColor;

    Adding Includes

    -

    Our form will also need some included files. Includes may be added in the declaration, or (for preference) in the implementation. Right click "Includes (in Implementation)", then click Edit. Use the dialog that pops up to enter "qcolor.h" and "qstring.h". Since we're going to use the clipboard we'll need access to the global clipboard object via TQApplication, so also add "qapplication.h" and "qclipboard.h". We'll also be doing some drawing (e.g. the color swatches), so add "qpainter.h" too, then close the dialog.

    +

    Our form will also need some included files. Includes may be added in the declaration, or (for preference) in the implementation. Right click "Includes (in Implementation)", then click Edit. Use the dialog that pops up to enter "ntqcolor.h" and "ntqstring.h". Since we're going to use the clipboard we'll need access to the global clipboard object via TQApplication, so also add "ntqapplication.h" and "ntqclipboard.h". We'll also be doing some drawing (e.g. the color swatches), so add "ntqpainter.h" too, then close the dialog.

    When entering include files you can include double quotes or angle brackets if you wish; if you don't use either TQt Designer will put in double quotes automatically.

    You should now have added the following includes (in implementation):

    -
    • "qcolor.h"

      -
    • "qstring.h"

      -
    • "qapplication.h"

      -
    • "qclipboard.h"

      -
    • "qpainter.h"

      +
      • "ntqcolor.h"

        +
      • "ntqstring.h"

        +
      • "ntqapplication.h"

        +
      • "ntqclipboard.h"

        +
      • "ntqpainter.h"

      Signals and Slots Connections

      Most of the signals and slots connections were created automatically by the main window wizard when we created the main form. We have added some new actions since then, and we need to ensure that they are connected to slots so that we can code their behavior.

      @@ -315,15 +315,15 @@ body { background: #ffffff; color: black; } const int COL_NAME = 0; const int COL_HEX = 1; const int COL_WEB = 2; - const TQString WINDOWS_REGISTRY = "/TQtExamples"; - const TQString APP_KEY = "/ColorTool/"; + const TQString WINDOWS_REGISTRY = "/TQtExamples"; + const TQString APP_KEY = "/ColorTool/"; -

      We define some useful constants for our form since it's easier to remember "CLIP_AS_RGB" than "2". The two TQStrings are used by TQSettings when we come to load and save user preferences; they're explained when we cover loadOptions() and saveOptions(). Note that we can insert any valid C++ into a .ui.h file including constant declarations as we've done here and #includes, etc.

      +

      We define some useful constants for our form since it's easier to remember "CLIP_AS_RGB" than "2". The two TQStrings are used by TQSettings when we come to load and save user preferences; they're explained when we cover loadOptions() and saveOptions(). Note that we can insert any valid C++ into a .ui.h file including constant declarations as we've done here and #includes, etc.

      Since we're not subclassing if we want to have code executed during construction we must create an init() function; this will be called at the end of the form's constructor.

      init()

          void MainForm::init()
           {
      -        clipboard = TQApplication::clipboard();
      +        clipboard = TQApplication::clipboard();
               if ( clipboard->supportsSelection() )
                   clipboard->setSelectionMode( TRUE );
       
      @@ -340,7 +340,7 @@ body { background: #ffffff; color: black; }
       

      clearData()

          void MainForm::clearData( bool fillWithDefaults )
           {
      -        setCaption( "Color Tool" );
      +        setCaption( "Color Tool" );
       
               m_colors.clear();
               m_comments.clear();
      @@ -381,15 +381,15 @@ body { background: #ffffff; color: black; }
       
                   colorTable->setNumRows( m_colors.count() );
                   if ( ! m_colors.isEmpty() ) {
      -                TQPixmap pixmap( 22, 22 );
      +                TQPixmap pixmap( 22, 22 );
                       int row = 0;
                       TQMap<TQString,TQColor>::ConstIterator it;
                       for ( it = m_colors.constBegin(); it != m_colors.constEnd(); ++it ) {
      -                    TQColor color = it.data();
      -                    pixmap.fill( color );
      +                    TQColor color = it.data();
      +                    pixmap.fill( color );
                           colorTable->setText( row, COL_NAME, it.key() );
                           colorTable->setPixmap( row, COL_NAME, pixmap );
      -                    colorTable->setText( row, COL_HEX, color.name().upper() );
      +                    colorTable->setText( row, COL_HEX, color.name().upper() );
                           if ( m_show_web ) {
                               TQCheckTableItem *item = new TQCheckTableItem( colorTable, "" );
                               item->setChecked( isWebColor( color ) );
      @@ -422,17 +422,17 @@ body { background: #ffffff; color: black; }
           }
       

      This function is at the heart of the application. It visually presents the data to the user. If the table is "dirty" (e.g. if the user has added or deleted colors in the icon view, or has opened a color file) we will populate the table. We start by deleting the contents of every cell. Next we change the number of rows to equal the number of colors in the colors map. For each color we want to display a little square that shows the color, so we create a pixmap of the required size.

      -

      We now create an iterator for our colors map, and iterate over every color. The colors map has the user's color names as its keys, and TQColor instances as values. We retrieve the color and fill our pixmap with that color. We then set the "Name" column (column COL_NAME), to have the color's name (it.key()) and the pixmap we've just filled with that color. TQColor's name() function returns a string that is the hex representation of a color, e.g. "#12AB2F"; we retrieve this and set the second ("Hex") column to this value.

      +

      We now create an iterator for our colors map, and iterate over every color. The colors map has the user's color names as its keys, and TQColor instances as values. We retrieve the color and fill our pixmap with that color. We then set the "Name" column (column COL_NAME), to have the color's name (it.key()) and the pixmap we've just filled with that color. TQColor's name() function returns a string that is the hex representation of a color, e.g. "#12AB2F"; we retrieve this and set the second ("Hex") column to this value.

      If the user wants to see if which colors are web colors we create a TQCheckTableItem, and check it if it is a web color. (We'll cover isWebColor() shortly.) We then insert this TQCheckTableItem into the "Web" column.

      Having populated the table we call adjustColumn() to ensure that each column is just wide enough to show its widest entry, and show or hide the "Web" column depending on the user's preference.

      Finally we set m_table_dirty to FALSE, since it is now up-to-date.

      If the icon view is "dirty" we clear() it of any existing data. We then iterate over each color in our colors map. For each color we create a new TQIconViewItem; we label the item with the user's color name and provide a pixmap (generated by colorSwatch(), covered shortly) in the relevant color. Finally we set m_icons_dirty to "FALSE", since it is now up-to-date.

      isWebColor()

      -
          bool MainForm::isWebColor( TQColor color )
      +
          bool MainForm::isWebColor( TQColor color )
           {
      -        int r = color.red();
      -        int g = color.green();
      -        int b = color.blue();
      +        int r = color.red();
      +        int g = color.green();
      +        int b = color.blue();
       
               return ( ( r ==   0 || r ==  51 || r == 102 ||
                          r == 153 || r == 204 || r == 255 ) &&
      @@ -444,32 +444,32 @@ body { background: #ffffff; color: black; }
       

      The 216 web colors are those colors whose RGB (Red, Green, Blue) values are all in the set (0, 51, 102, 153, 204, 255).

      colorSwatch()

      -
          TQPixmap MainForm::colorSwatch( const TQColor color )
      +
          TQPixmap MainForm::colorSwatch( const TQColor color )
           {
      -        TQPixmap pixmap( 80, 80 );
      -        pixmap.fill( white );
      -        TQPainter painter;
      -        painter.begin( &pixmap );
      -        painter.setPen( NoPen );
      -        painter.setBrush( color );
      -        painter.drawEllipse( 0, 0, 80, 80 );
      -        painter.end();
      +        TQPixmap pixmap( 80, 80 );
      +        pixmap.fill( white );
      +        TQPainter painter;
      +        painter.begin( &pixmap );
      +        painter.setPen( NoPen );
      +        painter.setBrush( color );
      +        painter.drawEllipse( 0, 0, 80, 80 );
      +        painter.end();
               return pixmap;
           }
       
      -

      We create a pixmap of a suitable size and fill it with white. We then create a TQPainter which we'll use to paint on the pixmap. We don't want a pen because we don't want an outline around the shape we draw. We draw an ellipse (which will be circular since we draw in an 80 x 80 pixel square). We return the resultant pixmap.

      +

      We create a pixmap of a suitable size and fill it with white. We then create a TQPainter which we'll use to paint on the pixmap. We don't want a pen because we don't want an outline around the shape we draw. We draw an ellipse (which will be circular since we draw in an 80 x 80 pixel square). We return the resultant pixmap.

      Creating main.cpp

      Now that we've entered some of the code it would be nice to build and run the application to get a feel for the progress we've made. To do this we need to create a main() function. In TQt we typically create a small main.cpp file for the main() function. We can ask TQt Designer to create this file for us.

      Click File|New to invoke the New File dialog. Click "C++ Main-File", then click OK. The Configure Main-File dialog appears, listing the all the forms in the project. We've only got one form, "MainForm", so it is already highlighted. Click OK to create a main.cpp file that loads our MainForm.

      -
          #include <qapplication.h>
      +
          #include <ntqapplication.h>
           #include "mainform.h"
       
           int main( int argc, char ** argv )
           {
      -        TQApplication a( argc, argv );
      +        TQApplication a( argc, argv );
               MainForm *w = new MainForm;
               w->show();
      -        return a.exec();
      +        return a.exec();
           }
       

      When TQt Designer generates a main.cpp file it includes this line:

      @@ -487,7 +487,7 @@ body { background: #ffffff; color: black; }

      Now, whatever the user clicks to close the application, our fileExit() slot will be called. We'll code the fileExit() slot right now:

          void MainForm::fileExit()
           {
      -            TQApplication::exit( 0 );
      +            TQApplication::exit( 0 );
           }
       

      This ensures that our application will cleanly terminate. Later we'll revise this function to give the user the opportunity to save any unsaved data.

      @@ -525,15 +525,15 @@ body { background: #ffffff; color: black; }

      changedColor()

      This is a function that we need to write from scratch. Simply enter its code into TQt Designer's code editor and it will automatically appear in Object Explorer's Members tab (under Functions, public).

      By default any function that it typed directly into the code editor becomes a public function. To change this, right click the function's name in Object Explorer's Members list, and click Properties to invoke the Edit Functions dialog. This dialog can be used to change various attributes of the function, including changing it into a slot.

      -
          void MainForm::changedColor( const TQString& name )
      +
          void MainForm::changedColor( const TQString& name )
           {
      -        TQColor color = m_colors[name];
      -        int r = color.red();
      -        int g = color.green();
      -        int b = color.blue();
      +        TQColor color = m_colors[name];
      +        int r = color.red();
      +        int g = color.green();
      +        int b = color.blue();
               statusBar()->message( TQString( "%1 \"%2\" (%3,%4,%5)%6 {%7 %8 %9}" ).
      -                              arg( name ).
      -                              arg( color.name().upper() ).
      +                              arg( name ).
      +                              arg( color.name().upper() ).
                                     arg( r ).arg( g ).arg( b ).
                                     arg( isWebColor( color ) ? " web" : "" ).
                                     arg( r / 255.0, 1, 'f', 3 ).
      @@ -543,9 +543,9 @@ body { background: #ffffff; color: black; }
           }
       

      This function looks up the color name in the colors map and retrieves the color the name refers to. It then displays the name, hex value and whether the color is a web color in the status bar.

      -

      Note that TQMainWindow only creates a status bar if you actually use one. Since we haven't used one up until now we've had no problem, but if we were to try compiling we'd get an error because we're now using a status bar but haven't declared the relevant header. Click Object Explorer's Members tab and add a "qstatusbar.h" to the "Includes (In Implementation)" section. (Right click "Includes (In Implementation)", click New, enter "qstatusbar.h" then press Enter.)

      +

      Note that TQMainWindow only creates a status bar if you actually use one. Since we haven't used one up until now we've had no problem, but if we were to try compiling we'd get an error because we're now using a status bar but haven't declared the relevant header. Click Object Explorer's Members tab and add a "ntqstatusbar.h" to the "Includes (In Implementation)" section. (Right click "Includes (In Implementation)", click New, enter "ntqstatusbar.h" then press Enter.)

      You should now have added the following declaration to your includes (in implementation):

      -
      • "qstatusbar.h"

        +
        • "ntqstatusbar.h"

        Try saving (press Ctrl+S), making and running the application. Move to different colors and see the status bar indicating the color you are on. (If it doesn't build see the Troubleshooting section.)

        Changing Views

        Up to now we have not yet been able to see the icon view in action because there's been no code in place to switch views. We'll address this issue now.

        @@ -558,7 +558,7 @@ body { background: #ffffff; color: black; } colorWidgetStack->raiseWidget( iconsPage ); }
      -

      (If you're cutting and pasting the code don't forget to name the TQAction parameter "action".)

      +

      (If you're cutting and pasting the code don't forget to name the TQAction parameter "action".)

      Editing the Code: File Handling

      Since the X Consortium has already defined a file format for relating colors to color names we will use their format rather than creating one specially for the application. This has the advantage that we will be able to read and write rgb.txt, and that our format will be familiar to many users.

      fileNew()

      @@ -579,13 +579,13 @@ body { background: #ffffff; color: black; }
          bool MainForm::okToClear()
           {
               if ( m_changed ) {
      -            TQString msg;
      +            TQString msg;
                   if ( m_filename.isEmpty() )
                       msg = "Unnamed colors ";
                   else
                       msg = TQString( "Colors '%1'\n" ).arg( m_filename );
                   msg += TQString( "has been changed." );
      -            int ans = TQMessageBox::information(
      +            int ans = TQMessageBox::information(
                                   this,
                                   "Color Tool -- Unsaved Changes",
                                   msg, "&Save", "Cancel", "&Abandon",
      @@ -600,57 +600,57 @@ body { background: #ffffff; color: black; }
           }
       

      If the data has changed (m_changed is TRUE), we present the user with a message box offering the option of saving their data, or cancelling the current operation (e.g. not loading a new file, or not creating a new set of colors), or abandoning their changes and continuing. We make the Save button the default button (pressed by Enter) and the Cancel button the escape button (pressed by Esc).

      -

      Since we're using a TQMessageBox we need to include the relevant header. (Right click "Includes (in Implementation)", then click New. Type "qmessagebox.h" and press Enter.)

      +

      Since we're using a TQMessageBox we need to include the relevant header. (Right click "Includes (in Implementation)", then click New. Type "ntqmessagebox.h" and press Enter.)

      You should now have added the following declaration to your includes (in implementation):

      -
      • "qmessagebox.h"

        +
        • "ntqmessagebox.h"

        fileOpen()

            void MainForm::fileOpen()
             {
                 if ( ! okToClear() )
                     return;
         
        -        TQString filename = TQFileDialog::getOpenFileName(
        +        TQString filename = TQFileDialog::getOpenFileName(
                                         TQString::null, "Colors (*.txt)", this,
                                         "file open", "Color Tool -- File Open" );
        -        if ( ! filename.isEmpty() )
        +        if ( ! filename.isEmpty() )
                     load( filename );
                 else
                     statusBar()->message( "File Open abandoned", 2000 );
             }
         
        -

        If it isn't okay to clear the data (i.e. the user has unsaved changes and clicked Cancel in the message box popped up by okToClear()), we simply return. Otherwise we ask the user for a filename using one of TQFileDialog's static functions, and if we got the filename we attempt to load the file.

        -

        Since we're using a TQFileDialog we need to include the relevant header. (Right click "Includes (in Implementation)", then click New. Type "qfiledialog.h" and press Enter.)

        +

        If it isn't okay to clear the data (i.e. the user has unsaved changes and clicked Cancel in the message box popped up by okToClear()), we simply return. Otherwise we ask the user for a filename using one of TQFileDialog's static functions, and if we got the filename we attempt to load the file.

        +

        Since we're using a TQFileDialog we need to include the relevant header. (Right click "Includes (in Implementation)", then click New. Type "ntqfiledialog.h" and press Enter.)

        You should now have added the following declaration to your includes (in implementation):

        -
        • "qfiledialog.h"

          +
          • "ntqfiledialog.h"

          load()

          -
              void MainForm::load( const TQString& filename )
          +
              void MainForm::load( const TQString& filename )
               {
                   clearData( FALSE );
                   m_filename = filename;
          -        TQRegExp regex( "^\\s*(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\S+.*)$" );
          -        TQFile file( filename );
          -        if ( file.open( IO_ReadOnly ) ) {
          +        TQRegExp regex( "^\\s*(\\d+)\\s+(\\d+)\\s+(\\d+)\\s+(\\S+.*)$" );
          +        TQFile file( filename );
          +        if ( file.open( IO_ReadOnly ) ) {
                       statusBar()->message( TQString( "Loading '%1'..." ).
                                             arg( filename ) );
          -            TQTextStream stream( &file );
          -            TQString line;
          -            while ( ! stream.eof() ) {
          -                line = stream.readLine();
          -                if ( regex.search( line ) == -1 )
          +            TQTextStream stream( &file );
          +            TQString line;
          +            while ( ! stream.eof() ) {
          +                line = stream.readLine();
          +                if ( regex.search( line ) == -1 )
                               m_comments += line;
                           else
          -                    m_colors[regex.cap( 4 )] = TQColor(
          -                                                regex.cap( 1 ).toInt(),
          -                                                regex.cap( 2 ).toInt(),
          -                                                regex.cap( 3 ).toInt() );
          +                    m_colors[regex.cap( 4 )] = TQColor(
          +                                                regex.cap( 1 ).toInt(),
          +                                                regex.cap( 2 ).toInt(),
          +                                                regex.cap( 3 ).toInt() );
                       }
          -            file.close();
          +            file.close();
                       m_filename = filename;
          -            setCaption( TQString( "Color Tool -- %1" ).arg( m_filename ) );
          +            setCaption( TQString( "Color Tool -- %1" ).arg( m_filename ) );
                       statusBar()->message( TQString( "Loaded '%1'" ).
                                               arg( m_filename ), 3000 );
          -            TQWidget *visible = colorWidgetStack->visibleWidget();
          -            m_icons_dirty = ! ( m_table_dirty = ( visible == tablePage ) );
          +            TQWidget *visible = colorWidgetStack->visibleWidget();
          +            m_icons_dirty = ! ( m_table_dirty = ( visible == tablePage ) );
                       populate();
                       m_icons_dirty = ! ( m_table_dirty = ( visible != tablePage ) );
                       m_changed = FALSE;
          @@ -672,12 +672,12 @@ RED WHITESPACE GREEN WHITESPACE BLUE WHITESPACE NAME
           

          The file may also include comment lines; these begin with '!' for example.

          There are numerous approaches we could have taken to parsing these files, but we've opted for a simple regular expression (regex). The regex is more "liberal" regarding the whitespace in the input than the format demands.

          -

          If a line matches the regex we create a new entry in the m_colors TQMap, setting its text to be the name of the color (regex.cap( 4 )), and its value to be a new TQColor created from the red, green and blue values. Lines that don't match the regex are treated as comments and are stored in the m_comments string list. (When we save the file we write all the comments out first even if they appeared in the middle of the file.)

          +

          If a line matches the regex we create a new entry in the m_colors TQMap, setting its text to be the name of the color (regex.cap( 4 )), and its value to be a new TQColor created from the red, green and blue values. Lines that don't match the regex are treated as comments and are stored in the m_comments string list. (When we save the file we write all the comments out first even if they appeared in the middle of the file.)

          Once we've populated the m_colors map we mark the visible view as "dirty" and call populate() to update it. We then mark the visible view as not dirty and the non-visible view as dirty. This ensures that when user changes the view, the view they switch to will be updated. We could have simply marked both views as dirty and updated them both, but it is more efficient to update "lazily", after all the user may only ever use one view, so why waste their time updating the other one.

          -

          Since we're using TQFile and TQRegExp we need to include the relevant headers. (Right click "Includes (in Implementation)", then click New. Type "qfile.h" and press Enter. Repeat this process to add "qregexp.h".)

          +

          Since we're using TQFile and TQRegExp we need to include the relevant headers. (Right click "Includes (in Implementation)", then click New. Type "ntqfile.h" and press Enter. Repeat this process to add "ntqregexp.h".)

          You should now have added the following declarations to your includes (in implementation):

          -
          • "qfile.h"

            -
          • "qregexp.h"

            +
            • "ntqfile.h"

              +
            • "ntqregexp.h"

            The Regular Expression

            The regex we've used can be broken up into the following pieces:

            @@ -688,18 +688,18 @@ Captures: cap(1) cap(2) cap(3) cap(4)

          Piece A says the regex must match from the beginning of the string, and piece F says the regex must match to the end of the string: so the regex must match the whole string or not match at all. The 'B' piece matches zero or more whitespaces (i.e. any leading whitespace), and the D pieces match one or more whitespaces (i.e. the gaps between each number). The 'C' pieces match one or more digits, i.e. the numbers. Piece E matches one or more non-whitespace followed by anything else, i.e. the name of the color.

          The parentheses are used to capture the parts of the match that they enclose. The captured parts are numbered from 1.

          -

          For more information on regexes see the TQRegExp documentation.

          +

          For more information on regexes see the TQRegExp documentation.

    fileSaveAs()

        void MainForm::fileSaveAs()
         {
    -        TQString filename = TQFileDialog::getSaveFileName(
    +        TQString filename = TQFileDialog::getSaveFileName(
                                     TQString::null, "Colors (*.txt)", this,
                                     "file save as", "Color Tool -- File Save As" );
    -        if ( ! filename.isEmpty() ) {
    +        if ( ! filename.isEmpty() ) {
                 int ans = 0;
    -            if ( TQFile::exists( filename ) )
    -                ans = TQMessageBox::warning(
    +            if ( TQFile::exists( filename ) )
    +                ans = TQMessageBox::warning(
                                     this, "Color Tool -- Overwrite File",
                                     TQString( "Overwrite\n'%1'?" ).
                                         arg( filename ),
    @@ -722,22 +722,22 @@ Captures:        cap(1)      cap(2)      cap(3)      cap(4)
                 return;
             }
     
    -        TQFile file( m_filename );
    -        if ( file.open( IO_WriteOnly ) ) {
    -            TQTextStream stream( &file );
    +        TQFile file( m_filename );
    +        if ( file.open( IO_WriteOnly ) ) {
    +            TQTextStream stream( &file );
                 if ( ! m_comments.isEmpty() )
                     stream << m_comments.join( "\n" ) << "\n";
                 TQMap<TQString,TQColor>::ConstIterator it;
                 for ( it = m_colors.constBegin(); it != m_colors.constEnd(); ++it ) {
    -                TQColor color = it.data();
    +                TQColor color = it.data();
                     stream << TQString( "%1 %2 %3\t\t%4" ).
    -                            arg( color.red(), 3 ).
    -                            arg( color.green(), 3 ).
    -                            arg( color.blue(), 3 ).
    +                            arg( color.red(), 3 ).
    +                            arg( color.green(), 3 ).
    +                            arg( color.blue(), 3 ).
                                 arg( it.key() ) << "\n";
                 }
    -            file.close();
    -            setCaption( TQString( "Color Tool -- %1" ).arg( m_filename ) );
    +            file.close();
    +            setCaption( TQString( "Color Tool -- %1" ).arg( m_filename ) );
                 statusBar()->message( TQString( "Saved %1 colors to '%2'" ).
                                         arg( m_colors.count() ).
                                         arg( m_filename ), 3000 );
    @@ -755,7 +755,7 @@ Captures:        cap(1)      cap(2)      cap(3)      cap(4)
     
        void MainForm::fileExit()
         {
             if ( okToClear() ) {
    -            TQApplication::exit( 0 );
    +            TQApplication::exit( 0 );
             }
         }
     
    @@ -766,13 +766,13 @@ Captures: cap(1) cap(2) cap(3) cap(4)

    editCut()

        void MainForm::editCut()
         {
    -        TQString name;
    -        TQWidget *visible = colorWidgetStack->visibleWidget();
    -        statusBar()->message( TQString( "Deleting '%1'" ).arg( name ) );
    +        TQString name;
    +        TQWidget *visible = colorWidgetStack->visibleWidget();
    +        statusBar()->message( TQString( "Deleting '%1'" ).arg( name ) );
     
    -        if ( visible == tablePage && colorTable->numRows() ) {
    +        if ( visible == tablePage && colorTable->numRows() ) {
                 int row = colorTable->currentRow();
    -            name = colorTable->text( row, 0 );
    +            name = colorTable->text( row, 0 );
                 colorTable->removeRow( colorTable->currentRow() );
                 if ( row < colorTable->numRows() )
                     colorTable->setCurrentCell( row, 0 );
    @@ -780,9 +780,9 @@ Captures:        cap(1)      cap(2)      cap(3)      cap(4)
                     colorTable->setCurrentCell( colorTable->numRows() - 1, 0 );
                 m_icons_dirty = TRUE;
             }
    -        else if ( visible == iconsPage && colorIconView->currentItem() ) {
    +        else if ( visible == iconsPage && colorIconView->currentItem() ) {
                 TQIconViewItem *item = colorIconView->currentItem();
    -            name = item->text();
    +            name = item->text();
                 if ( colorIconView->count() == 1 )
                     colorIconView->clear();
                 else {
    @@ -797,40 +797,40 @@ Captures:        cap(1)      cap(2)      cap(3)      cap(4)
                 m_table_dirty = TRUE;
             }
     
    -        if ( ! name.isNull() ) {
    -            m_colors.remove( name );
    +        if ( ! name.isNull() ) {
    +            m_colors.remove( name );
                 m_changed = TRUE;
    -            statusBar()->message( TQString( "Deleted '%1'" ).arg( name ), 5000 );
    +            statusBar()->message( TQString( "Deleted '%1'" ).arg( name ), 5000 );
             }
             else
    -            statusBar()->message( TQString( "Failed to delete '%1'" ).arg( name ), 5000 );
    +            statusBar()->message( TQString( "Failed to delete '%1'" ).arg( name ), 5000 );
         }
     

    If the user is viewing the table view we delete the current row. We set the new current cell to be the one following the deleted row, or if the one we deleted was last, its predecessor. We mark the other view (the icon view) as dirty, to make sure that it is updated if the user switches views. Similarly, if the user is viewing the icon view, we make the next (or previous if there is no next) item current and delete the one they were on. We then mark the table view as dirty. If we deleted a color (i.e. there was a current color in one of the views), we remove it from the m_colors map and mark the data as changed.

    editCopy()

        void MainForm::editCopy()
         {
    -        TQString text;
    -        TQWidget *visible = colorWidgetStack->visibleWidget();
    +        TQString text;
    +        TQWidget *visible = colorWidgetStack->visibleWidget();
     
    -        if ( visible == tablePage && colorTable->numRows() ) {
    +        if ( visible == tablePage && colorTable->numRows() ) {
                 int row = colorTable->currentRow();
                 text = colorTable->text( row, 0 );
             }
    -        else if ( visible == iconsPage && colorIconView->currentItem() ) {
    +        else if ( visible == iconsPage && colorIconView->currentItem() ) {
                 TQIconViewItem *item = colorIconView->currentItem();
                 text = item->text();
             }
    -        if ( ! text.isNull() ) {
    -            TQColor color = m_colors[text];
    +        if ( ! text.isNull() ) {
    +            TQColor color = m_colors[text];
                 switch ( m_clip_as ) {
    -                case CLIP_AS_HEX: text = color.name(); break;
    +                case CLIP_AS_HEX: text = color.name(); break;
                     case CLIP_AS_NAME: break;
                     case CLIP_AS_RGB:
                             text = TQString( "%1,%2,%3" ).
    -                            arg( color.red() ).
    -                            arg( color.green() ).
    -                            arg( color.blue() );
    +                            arg( color.red() ).
    +                            arg( color.green() ).
    +                            arg( color.blue() );
                             break;
                 }
                 clipboard->setText( text );
    @@ -838,7 +838,7 @@ Captures:        cap(1)      cap(2)      cap(3)      cap(4)
             }
         }
     
    -

    In this function we retrieve the name of the color from the current table row (or current icon, depending on the view). We then set a TQString to the text we want to copy into the clipboard and copy it.

    +

    In this function we retrieve the name of the color from the current table row (or current icon, depending on the view). We then set a TQString to the text we want to copy into the clipboard and copy it.

    Summary

    In this chapter we have created a standard main-window style application. We have implemented menus, a toolbar and a main widget (a TQWidgetStack). We've also created signal and slot connections and implemented many custom slots. In the following chapter we will complete the application by implementing custom dialogs, and by making use of common dialogs where appropriate.

    -- cgit v1.2.1