diff options
Diffstat (limited to 'src/dialogs')
-rw-r--r-- | src/dialogs/qcolordialog.cpp | 1659 | ||||
-rw-r--r-- | src/dialogs/qcolordialog.h | 93 | ||||
-rw-r--r-- | src/dialogs/qdialog.cpp | 1178 | ||||
-rw-r--r-- | src/dialogs/qdialog.h | 141 | ||||
-rw-r--r-- | src/dialogs/qerrormessage.cpp | 270 | ||||
-rw-r--r-- | src/dialogs/qerrormessage.h | 89 | ||||
-rw-r--r-- | src/dialogs/qfiledialog.cpp | 6461 | ||||
-rw-r--r-- | src/dialogs/qfiledialog.h | 347 | ||||
-rw-r--r-- | src/dialogs/qfontdialog.cpp | 831 | ||||
-rw-r--r-- | src/dialogs/qfontdialog.h | 112 | ||||
-rw-r--r-- | src/dialogs/qinputdialog.cpp | 532 | ||||
-rw-r--r-- | src/dialogs/qinputdialog.h | 107 | ||||
-rw-r--r-- | src/dialogs/qmessagebox.cpp | 1632 | ||||
-rw-r--r-- | src/dialogs/qmessagebox.h | 223 | ||||
-rw-r--r-- | src/dialogs/qprintdialog.cpp | 1672 | ||||
-rw-r--r-- | src/dialogs/qprintdialog.h | 103 | ||||
-rw-r--r-- | src/dialogs/qprogressdialog.cpp | 826 | ||||
-rw-r--r-- | src/dialogs/qprogressdialog.h | 141 | ||||
-rw-r--r-- | src/dialogs/qsemimodal.h | 66 | ||||
-rw-r--r-- | src/dialogs/qt_dialogs.pri | 33 | ||||
-rw-r--r-- | src/dialogs/qtabdialog.cpp | 1145 | ||||
-rw-r--r-- | src/dialogs/qtabdialog.h | 146 | ||||
-rw-r--r-- | src/dialogs/qwizard.cpp | 917 | ||||
-rw-r--r-- | src/dialogs/qwizard.h | 142 |
24 files changed, 18866 insertions, 0 deletions
diff --git a/src/dialogs/qcolordialog.cpp b/src/dialogs/qcolordialog.cpp new file mode 100644 index 0000000..44bf70e --- /dev/null +++ b/src/dialogs/qcolordialog.cpp @@ -0,0 +1,1659 @@ +/**************************************************************************** +** +** Implementation of QColorDialog class +** +** Created : 990222 +** +** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qcolordialog.h" + +#ifndef QT_NO_COLORDIALOG + +#include "qpainter.h" +#include "qlayout.h" +#include "qlabel.h" +#include "qpushbutton.h" +#include "qlineedit.h" +#include "qimage.h" +#include "qpixmap.h" +#include "qdrawutil.h" +#include "qvalidator.h" +#include "qdragobject.h" +#include "qgridview.h" +#include "qapplication.h" +#include "qstyle.h" +#include "qsettings.h" +#include "qpopupmenu.h" + +#ifdef Q_WS_MAC +QRgb macGetRgba( QRgb initial, bool *ok, QWidget *parent, const char* name ); +QColor macGetColor( const QColor& initial, QWidget *parent, const char *name ); +#endif + +//////////// QWellArray BEGIN + +struct QWellArrayData; + +class QWellArray : public QGridView +{ + Q_OBJECT + Q_PROPERTY( int selectedColumn READ selectedColumn ) + Q_PROPERTY( int selectedRow READ selectedRow ) + +public: + QWellArray( QWidget* parent=0, const char* name=0, bool popup = FALSE ); + + ~QWellArray() {} + QString cellContent( int row, int col ) const; + // ### Paul !!! virtual void setCellContent( int row, int col, const QString &); + + int selectedColumn() const { return selCol; } + int selectedRow() const { return selRow; } + + virtual void setCurrent( int row, int col ); + virtual void setSelected( int row, int col ); + + QSize sizeHint() const; + + virtual void setCellBrush( int row, int col, const QBrush & ); + QBrush cellBrush( int row, int col ); + +signals: + void selected( int row, int col ); + +protected: + void dimensionChange( int oldRows, int oldCols ); + + virtual void paintCell( QPainter *, int row, int col ); + virtual void paintCellContents( QPainter *, int row, int col, const QRect& ); + + void mousePressEvent( QMouseEvent* ); + void mouseReleaseEvent( QMouseEvent* ); + void mouseMoveEvent( QMouseEvent* ); + void keyPressEvent( QKeyEvent* ); + void focusInEvent( QFocusEvent* ); + void focusOutEvent( QFocusEvent* ); + +private: + int curRow; + int curCol; + int selRow; + int selCol; + bool smallStyle; + QWellArrayData *d; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QWellArray( const QWellArray & ); + QWellArray& operator=( const QWellArray & ); +#endif +}; + + + +// non-interface ... + + + +struct QWellArrayData { + QBrush *brush; +}; + +/*! + \internal + \class QWellArray qwellarray_p.h + \brief The QWellArray class provides a well array. + + + \ingroup advanced +*/ + +QWellArray::QWellArray( QWidget *parent, const char * name, bool popup ) + : QGridView( parent, name, + (popup ? (WStyle_Customize|WStyle_Tool|WStyle_NoBorder) : 0 ) ) +{ + d = 0; + setFocusPolicy( StrongFocus ); + setVScrollBarMode(AlwaysOff); + setHScrollBarMode(AlwaysOff); + viewport()->setBackgroundMode( PaletteBackground ); + setNumCols( 7 ); + setNumRows( 7 ); + setCellWidth( 24 ); + setCellHeight( 21 ); + smallStyle = popup; + + if ( popup ) { + setCellWidth( 18 ); + setCellHeight( 18 ); + setFrameStyle(QFrame::StyledPanel | QFrame::Raised); + setMargin( 1 ); + setLineWidth( 2 ); + } else { + setFrameStyle( QFrame::NoFrame ); + } + curCol = 0; + curRow = 0; + selCol = -1; + selRow = -1; + + if ( smallStyle ) + setMouseTracking( TRUE ); +} + + +QSize QWellArray::sizeHint() const +{ + constPolish(); + QSize s = gridSize().boundedTo( QSize(640, 480 ) ); + return QSize( s.width() + 2*frameWidth(), s.height() + 2*frameWidth() ); +} + + +void QWellArray::paintCell( QPainter* p, int row, int col ) +{ + int w = cellWidth(); // width of cell in pixels + int h = cellHeight(); // height of cell in pixels + int b = 1; + + if ( !smallStyle ) + b = 3; + + const QColorGroup & g = colorGroup(); + p->setPen( QPen( black, 0, SolidLine ) ); + if ( !smallStyle && row ==selRow && col == selCol && + style().styleHint(QStyle::SH_GUIStyle) != MotifStyle) { + int n = 2; + p->drawRect( n, n, w-2*n, h-2*n ); + } + + style().drawPrimitive(QStyle::PE_Panel, p, QRect(b, b, w-2*b, h-2*b), g, + QStyle::Style_Enabled | QStyle::Style_Sunken); + + int t = 0; + if (style().styleHint(QStyle::SH_GUIStyle) == MotifStyle) + t = ( row == selRow && col == selCol ) ? 2 : 0; + b += 2 + t; + + if ( (row == curRow) && (col == curCol) ) { + if ( smallStyle ) { + p->setPen ( white ); + p->drawRect( 1, 1, w-2, h-2 ); + p->setPen ( black ); + p->drawRect( 0, 0, w, h ); + p->drawRect( 2, 2, w-4, h-4 ); + b = 3; + } else if ( hasFocus() ) { + style().drawPrimitive(QStyle::PE_FocusRect, p, QRect(0, 0, w, h), g); + } + } + paintCellContents( p, row, col, QRect(b, b, w - 2*b, h - 2*b) ); +} + +/*! + Reimplement this function to change the contents of the well array. + */ +void QWellArray::paintCellContents( QPainter *p, int row, int col, const QRect &r ) +{ + + if ( d ) { + p->fillRect( r, d->brush[row*numCols()+col] ); + } else { + p->fillRect( r, white ); + p->setPen( black ); + p->drawLine( r.topLeft(), r.bottomRight() ); + p->drawLine( r.topRight(), r.bottomLeft() ); + } +} + + +/*\reimp +*/ +void QWellArray::mousePressEvent( QMouseEvent* e ) +{ + // The current cell marker is set to the cell the mouse is pressed + // in. + QPoint pos = e->pos(); + setCurrent( rowAt( pos.y() ), columnAt( pos.x() ) ); +} + +/*\reimp +*/ +void QWellArray::mouseReleaseEvent( QMouseEvent* ) +{ + // The current cell marker is set to the cell the mouse is clicked + // in. + setSelected( curRow, curCol ); +} + + +/*\reimp +*/ +void QWellArray::mouseMoveEvent( QMouseEvent* e ) +{ + // The current cell marker is set to the cell the mouse is + // clicked in. + if ( smallStyle ) { + QPoint pos = e->pos(); + setCurrent( rowAt( pos.y() ), columnAt( pos.x() ) ); + } +} + +/* + Sets the cell currently having the focus. This is not necessarily + the same as the currently selected cell. +*/ + +void QWellArray::setCurrent( int row, int col ) +{ + + if ( (curRow == row) && (curCol == col) ) + return; + + if ( row < 0 || col < 0 ) + row = col = -1; + + int oldRow = curRow; + int oldCol = curCol; + + curRow = row; + curCol = col; + + updateCell( oldRow, oldCol ); + updateCell( curRow, curCol ); +} + + +/*! + Sets the currently selected cell to \a row, \a col. If \a row or \a + col are less than zero, the current cell is unselected. + + Does not set the position of the focus indicator. +*/ + +void QWellArray::setSelected( int row, int col ) +{ + if ( (selRow == row) && (selCol == col) ) + return; + + int oldRow = selRow; + int oldCol = selCol; + + if ( row < 0 || col < 0 ) + row = col = -1; + + selCol = col; + selRow = row; + + updateCell( oldRow, oldCol ); + updateCell( selRow, selCol ); + if ( row >= 0 ) + emit selected( row, col ); + + if ( isVisible() && ::qt_cast<QPopupMenu*>(parentWidget()) ) + parentWidget()->close(); +} + + + +/*!\reimp +*/ +void QWellArray::focusInEvent( QFocusEvent* ) +{ + updateCell( curRow, curCol ); +} + + +/*! + Sets the size of the well array to be \a rows cells by \a cols. + Resets any brush information set by setCellBrush(). + */ +void QWellArray::dimensionChange( int, int ) +{ + if ( d ) { + if ( d->brush ) + delete[] d->brush; + delete d; + d = 0; + } +} + +void QWellArray::setCellBrush( int row, int col, const QBrush &b ) +{ + if ( !d ) { + d = new QWellArrayData; + int i = numRows()*numCols(); + d->brush = new QBrush[i]; + } + if ( row >= 0 && row < numRows() && col >= 0 && col < numCols() ) + d->brush[row*numCols()+col] = b; +#ifdef QT_CHECK_RANGE + else + qWarning( "QWellArray::setCellBrush( %d, %d ) out of range", row, col ); +#endif +} + + + +/*! + Returns the brush set for the cell at \a row, \a col. If no brush is set, + \c NoBrush is returned. +*/ + +QBrush QWellArray::cellBrush( int row, int col ) +{ + if ( d && row >= 0 && row < numRows() && col >= 0 && col < numCols() ) + return d->brush[row*numCols()+col]; + return NoBrush; +} + + + +/*!\reimp +*/ + +void QWellArray::focusOutEvent( QFocusEvent* ) +{ + updateCell( curRow, curCol ); +} + +/*\reimp +*/ +void QWellArray::keyPressEvent( QKeyEvent* e ) +{ + switch( e->key() ) { // Look at the key code + case Key_Left: // If 'left arrow'-key, + if( curCol > 0 ) // and cr't not in leftmost col + setCurrent( curRow, curCol - 1); // set cr't to next left column + break; + case Key_Right: // Correspondingly... + if( curCol < numCols()-1 ) + setCurrent( curRow, curCol + 1); + break; + case Key_Up: + if( curRow > 0 ) + setCurrent( curRow - 1, curCol); + else if ( smallStyle ) + focusNextPrevChild( FALSE ); + break; + case Key_Down: + if( curRow < numRows()-1 ) + setCurrent( curRow + 1, curCol); + else if ( smallStyle ) + focusNextPrevChild( TRUE ); + break; + case Key_Space: + case Key_Return: + case Key_Enter: + setSelected( curRow, curCol ); + break; + default: // If not an interesting key, + e->ignore(); // we don't accept the event + return; + } + +} + +//////////// QWellArray END + +static bool initrgb = FALSE; +static QRgb stdrgb[6*8]; +static QRgb cusrgb[2*8]; +static bool customSet = FALSE; + + +static void initRGB() +{ + if ( initrgb ) + return; + initrgb = TRUE; + int i = 0; + for ( int g = 0; g < 4; g++ ) + for ( int r = 0; r < 4; r++ ) + for ( int b = 0; b < 3; b++ ) + stdrgb[i++] = qRgb( r*255/3, g*255/3, b*255/2 ); + + for ( i = 0; i < 2*8; i++ ) + cusrgb[i] = qRgb(0xff,0xff,0xff); +} + +/*! + Returns the number of custom colors supported by QColorDialog. All + color dialogs share the same custom colors. +*/ +int QColorDialog::customCount() +{ + return 2*8; +} + +/*! + Returns custom color number \a i as a QRgb. +*/ +QRgb QColorDialog::customColor( int i ) +{ + initRGB(); + if ( i < 0 || i >= customCount() ) { +#ifdef QT_CHECK_RANGE + qWarning( "QColorDialog::customColor() index %d out of range", i ); +#endif + i = 0; + } + return cusrgb[i]; +} + +/*! + Sets custom color number \a i to the QRgb value \a c. +*/ +void QColorDialog::setCustomColor( int i, QRgb c ) +{ + initRGB(); + if ( i < 0 || i >= customCount() ) { +#ifdef QT_CHECK_RANGE + qWarning( "QColorDialog::setCustomColor() index %d out of range", i ); +#endif + return; + } + customSet = TRUE; + cusrgb[i] = c; +} + +/*! + Sets standard color number \a i to the QRgb value \a c. +*/ + +void QColorDialog::setStandardColor( int i, QRgb c ) +{ + initRGB(); + if ( i < 0 || i >= 6*8 ) { +#ifdef QT_CHECK_RANGE + qWarning( "QColorDialog::setStandardColor() index %d out of range", i ); +#endif + return; + } + stdrgb[i] = c; +} + +static inline void rgb2hsv( QRgb rgb, int&h, int&s, int&v ) +{ + QColor c; + c.setRgb( rgb ); + c.getHsv(h,s,v); +} + +class QColorWell : public QWellArray +{ +public: + QColorWell( QWidget *parent, int r, int c, QRgb *vals ) + :QWellArray( parent, "" ), values( vals ), mousePressed( FALSE ), oldCurrent( -1, -1 ) + { setNumRows(r), setNumCols(c); setSizePolicy( QSizePolicy( QSizePolicy::Minimum, QSizePolicy::Minimum) ); } + +protected: + void paintCellContents( QPainter *, int row, int col, const QRect& ); + void mousePressEvent( QMouseEvent *e ); + void mouseMoveEvent( QMouseEvent *e ); + void mouseReleaseEvent( QMouseEvent *e ); +#ifndef QT_NO_DRAGANDDROP + void dragEnterEvent( QDragEnterEvent *e ); + void dragLeaveEvent( QDragLeaveEvent *e ); + void dragMoveEvent( QDragMoveEvent *e ); + void dropEvent( QDropEvent *e ); +#endif + +private: + QRgb *values; + bool mousePressed; + QPoint pressPos; + QPoint oldCurrent; + +}; + +void QColorWell::paintCellContents( QPainter *p, int row, int col, const QRect &r ) +{ + int i = row + col*numRows(); + p->fillRect( r, QColor( values[i] ) ); +} + +void QColorWell::mousePressEvent( QMouseEvent *e ) +{ + oldCurrent = QPoint( selectedRow(), selectedColumn() ); + QWellArray::mousePressEvent( e ); + mousePressed = TRUE; + pressPos = e->pos(); +} + +void QColorWell::mouseMoveEvent( QMouseEvent *e ) +{ + QWellArray::mouseMoveEvent( e ); +#ifndef QT_NO_DRAGANDDROP + if ( !mousePressed ) + return; + if ( ( pressPos - e->pos() ).manhattanLength() > QApplication::startDragDistance() ) { + setCurrent( oldCurrent.x(), oldCurrent.y() ); + int i = rowAt(pressPos.y()) + columnAt(pressPos.x()) * numRows(); + QColor col( values[ i ] ); + QColorDrag *drg = new QColorDrag( col, this ); + QPixmap pix( cellWidth(), cellHeight() ); + pix.fill( col ); + QPainter p( &pix ); + p.drawRect( 0, 0, pix.width(), pix.height() ); + p.end(); + drg->setPixmap( pix ); + mousePressed = FALSE; + drg->dragCopy(); + } +#endif +} + +#ifndef QT_NO_DRAGANDDROP +void QColorWell::dragEnterEvent( QDragEnterEvent *e ) +{ + setFocus(); + if ( QColorDrag::canDecode( e ) ) + e->accept(); + else + e->ignore(); +} + +void QColorWell::dragLeaveEvent( QDragLeaveEvent * ) +{ + if ( hasFocus() ) + parentWidget()->setFocus(); +} + +void QColorWell::dragMoveEvent( QDragMoveEvent *e ) +{ + if ( QColorDrag::canDecode( e ) ) { + setCurrent( rowAt( e->pos().y() ), columnAt( e->pos().x() ) ); + e->accept(); + } else + e->ignore(); +} + +void QColorWell::dropEvent( QDropEvent *e ) +{ + if ( QColorDrag::canDecode( e ) ) { + int i = rowAt( e->pos().y() ) + columnAt( e->pos().x() ) * numRows(); + QColor col; + QColorDrag::decode( e, col ); + values[ i ] = col.rgb(); + repaintContents( FALSE ); + e->accept(); + } else { + e->ignore(); + } +} + +#endif // QT_NO_DRAGANDDROP + +void QColorWell::mouseReleaseEvent( QMouseEvent *e ) +{ + if ( !mousePressed ) + return; + QWellArray::mouseReleaseEvent( e ); + mousePressed = FALSE; +} + +class QColorPicker : public QFrame +{ + Q_OBJECT +public: + QColorPicker(QWidget* parent=0, const char* name=0); + ~QColorPicker(); + +public slots: + void setCol( int h, int s ); + +signals: + void newCol( int h, int s ); + +protected: + QSize sizeHint() const; + void drawContents(QPainter* p); + void mouseMoveEvent( QMouseEvent * ); + void mousePressEvent( QMouseEvent * ); + +private: + int hue; + int sat; + + QPoint colPt(); + int huePt( const QPoint &pt ); + int satPt( const QPoint &pt ); + void setCol( const QPoint &pt ); + + QPixmap *pix; +}; + +static int pWidth = 200; +static int pHeight = 200; + +class QColorLuminancePicker : public QWidget +{ + Q_OBJECT +public: + QColorLuminancePicker(QWidget* parent=0, const char* name=0); + ~QColorLuminancePicker(); + +public slots: + void setCol( int h, int s, int v ); + void setCol( int h, int s ); + +signals: + void newHsv( int h, int s, int v ); + +protected: + void paintEvent( QPaintEvent*); + void mouseMoveEvent( QMouseEvent * ); + void mousePressEvent( QMouseEvent * ); + +private: + enum { foff = 3, coff = 4 }; //frame and contents offset + int val; + int hue; + int sat; + + int y2val( int y ); + int val2y( int val ); + void setVal( int v ); + + QPixmap *pix; +}; + + +int QColorLuminancePicker::y2val( int y ) +{ + int d = height() - 2*coff - 1; + return 255 - (y - coff)*255/d; +} + +int QColorLuminancePicker::val2y( int v ) +{ + int d = height() - 2*coff - 1; + return coff + (255-v)*d/255; +} + +QColorLuminancePicker::QColorLuminancePicker(QWidget* parent, + const char* name) + :QWidget( parent, name ) +{ + hue = 100; val = 100; sat = 100; + pix = 0; + // setBackgroundMode( NoBackground ); +} + +QColorLuminancePicker::~QColorLuminancePicker() +{ + delete pix; +} + +void QColorLuminancePicker::mouseMoveEvent( QMouseEvent *m ) +{ + setVal( y2val(m->y()) ); +} +void QColorLuminancePicker::mousePressEvent( QMouseEvent *m ) +{ + setVal( y2val(m->y()) ); +} + +void QColorLuminancePicker::setVal( int v ) +{ + if ( val == v ) + return; + val = QMAX( 0, QMIN(v,255)); + delete pix; pix=0; + repaint( FALSE ); //### + emit newHsv( hue, sat, val ); +} + +//receives from a hue,sat chooser and relays. +void QColorLuminancePicker::setCol( int h, int s ) +{ + setCol( h, s, val ); + emit newHsv( h, s, val ); +} + +void QColorLuminancePicker::paintEvent( QPaintEvent * ) +{ + int w = width() - 5; + + QRect r( 0, foff, w, height() - 2*foff ); + int wi = r.width() - 2; + int hi = r.height() - 2; + if ( !pix || pix->height() != hi || pix->width() != wi ) { + delete pix; + QImage img( wi, hi, 32 ); + int y; + for ( y = 0; y < hi; y++ ) { + QColor c( hue, sat, y2val(y+coff), QColor::Hsv ); + QRgb r = c.rgb(); + int x; + for ( x = 0; x < wi; x++ ) + img.setPixel( x, y, r ); + } + pix = new QPixmap; + pix->convertFromImage(img); + } + QPainter p(this); + p.drawPixmap( 1, coff, *pix ); + const QColorGroup &g = colorGroup(); + qDrawShadePanel( &p, r, g, TRUE ); + p.setPen( g.foreground() ); + p.setBrush( g.foreground() ); + QPointArray a; + int y = val2y(val); + a.setPoints( 3, w, y, w+5, y+5, w+5, y-5 ); + erase( w, 0, 5, height() ); + p.drawPolygon( a ); +} + +void QColorLuminancePicker::setCol( int h, int s , int v ) +{ + val = v; + hue = h; + sat = s; + delete pix; pix=0; + repaint( FALSE );//#### +} + +QPoint QColorPicker::colPt() +{ return QPoint( (360-hue)*(pWidth-1)/360, (255-sat)*(pHeight-1)/255 ); } +int QColorPicker::huePt( const QPoint &pt ) +{ return 360 - pt.x()*360/(pWidth-1); } +int QColorPicker::satPt( const QPoint &pt ) +{ return 255 - pt.y()*255/(pHeight-1) ; } +void QColorPicker::setCol( const QPoint &pt ) +{ setCol( huePt(pt), satPt(pt) ); } + +QColorPicker::QColorPicker(QWidget* parent, const char* name ) + : QFrame( parent, name ) +{ + hue = 0; sat = 0; + setCol( 150, 255 ); + + QImage img( pWidth, pHeight, 32 ); + int x,y; + for ( y = 0; y < pHeight; y++ ) + for ( x = 0; x < pWidth; x++ ) { + QPoint p( x, y ); + img.setPixel( x, y, QColor(huePt(p), satPt(p), + 200, QColor::Hsv).rgb() ); + } + pix = new QPixmap; + pix->convertFromImage(img); + setBackgroundMode( NoBackground ); + setSizePolicy( QSizePolicy( QSizePolicy::Fixed, QSizePolicy::Fixed ) ); +} + +QColorPicker::~QColorPicker() +{ + delete pix; +} + +QSize QColorPicker::sizeHint() const +{ + return QSize( pWidth + 2*frameWidth(), pHeight + 2*frameWidth() ); +} + +void QColorPicker::setCol( int h, int s ) +{ + int nhue = QMIN( QMAX(0,h), 360 ); + int nsat = QMIN( QMAX(0,s), 255); + if ( nhue == hue && nsat == sat ) + return; + QRect r( colPt(), QSize(20,20) ); + hue = nhue; sat = nsat; + r = r.unite( QRect( colPt(), QSize(20,20) ) ); + r.moveBy( contentsRect().x()-9, contentsRect().y()-9 ); + // update( r ); + repaint( r, FALSE ); +} + +void QColorPicker::mouseMoveEvent( QMouseEvent *m ) +{ + QPoint p = m->pos() - contentsRect().topLeft(); + setCol( p ); + emit newCol( hue, sat ); +} + +void QColorPicker::mousePressEvent( QMouseEvent *m ) +{ + QPoint p = m->pos() - contentsRect().topLeft(); + setCol( p ); + emit newCol( hue, sat ); +} + +void QColorPicker::drawContents(QPainter* p) +{ + QRect r = contentsRect(); + + p->drawPixmap( r.topLeft(), *pix ); + QPoint pt = colPt() + r.topLeft(); + p->setPen( QPen(black) ); + + p->fillRect( pt.x()-9, pt.y(), 20, 2, black ); + p->fillRect( pt.x(), pt.y()-9, 2, 20, black ); + +} + +class QColorShowLabel; + + + +class QColIntValidator: public QIntValidator +{ +public: + QColIntValidator( int bottom, int top, + QWidget * parent, const char *name = 0 ) + :QIntValidator( bottom, top, parent, name ) {} + + QValidator::State validate( QString &, int & ) const; +}; + +QValidator::State QColIntValidator::validate( QString &s, int &pos ) const +{ + State state = QIntValidator::validate(s,pos); + if ( state == Valid ) { + long int val = s.toLong(); + // This is not a general solution, assumes that top() > 0 and + // bottom >= 0 + if ( val < 0 ) { + s = "0"; + pos = 1; + } else if ( val > top() ) { + s.setNum( top() ); + pos = s.length(); + } + } + return state; +} + + + +class QColNumLineEdit : public QLineEdit +{ +public: + QColNumLineEdit( QWidget *parent, const char* name=0 ) + : QLineEdit( parent, name ) { setMaxLength( 3 );} + QSize sizeHint() const { + return QSize( fontMetrics().width( "999" ) + 2 * ( margin() + frameWidth() ), + QLineEdit::sizeHint().height() ); } + void setNum( int i ) { + QString s; + s.setNum(i); + bool block = signalsBlocked(); + blockSignals(TRUE); + setText( s ); + blockSignals(block); + } + int val() const { return text().toInt(); } +}; + + +class QColorShower : public QWidget +{ + Q_OBJECT +public: + QColorShower( QWidget *parent, const char *name=0 ); + + //things that don't emit signals + void setHsv( int h, int s, int v ); + + int currentAlpha() const { return alphaEd->val(); } + void setCurrentAlpha( int a ) { alphaEd->setNum( a ); } + void showAlpha( bool b ); + + + QRgb currentColor() const { return curCol; } + +public slots: + void setRgb( QRgb rgb ); + +signals: + void newCol( QRgb rgb ); +private slots: + void rgbEd(); + void hsvEd(); +private: + void showCurrentColor(); + int hue, sat, val; + QRgb curCol; + QColNumLineEdit *hEd; + QColNumLineEdit *sEd; + QColNumLineEdit *vEd; + QColNumLineEdit *rEd; + QColNumLineEdit *gEd; + QColNumLineEdit *bEd; + QColNumLineEdit *alphaEd; + QLabel *alphaLab; + QColorShowLabel *lab; + bool rgbOriginal; +}; + +class QColorShowLabel : public QFrame +{ + Q_OBJECT + +public: + QColorShowLabel( QWidget *parent ) : QFrame( parent, "qt_colorshow_lbl" ) { + setFrameStyle( QFrame::Panel|QFrame::Sunken ); + setBackgroundMode( PaletteBackground ); + setAcceptDrops( TRUE ); + mousePressed = FALSE; + } + void setColor( QColor c ) { col = c; } + +signals: + void colorDropped( QRgb ); + +protected: + void drawContents( QPainter *p ); + void mousePressEvent( QMouseEvent *e ); + void mouseMoveEvent( QMouseEvent *e ); + void mouseReleaseEvent( QMouseEvent *e ); +#ifndef QT_NO_DRAGANDDROP + void dragEnterEvent( QDragEnterEvent *e ); + void dragLeaveEvent( QDragLeaveEvent *e ); + void dropEvent( QDropEvent *e ); +#endif + +private: + QColor col; + bool mousePressed; + QPoint pressPos; + +}; + +void QColorShowLabel::drawContents( QPainter *p ) +{ + p->fillRect( contentsRect(), col ); +} + +void QColorShower::showAlpha( bool b ) +{ + if ( b ) { + alphaLab->show(); + alphaEd->show(); + } else { + alphaLab->hide(); + alphaEd->hide(); + } +} + +void QColorShowLabel::mousePressEvent( QMouseEvent *e ) +{ + mousePressed = TRUE; + pressPos = e->pos(); +} + +void QColorShowLabel::mouseMoveEvent( QMouseEvent *e ) +{ +#ifndef QT_NO_DRAGANDDROP + if ( !mousePressed ) + return; + if ( ( pressPos - e->pos() ).manhattanLength() > QApplication::startDragDistance() ) { + QColorDrag *drg = new QColorDrag( col, this ); + QPixmap pix( 30, 20 ); + pix.fill( col ); + QPainter p( &pix ); + p.drawRect( 0, 0, pix.width(), pix.height() ); + p.end(); + drg->setPixmap( pix ); + mousePressed = FALSE; + drg->dragCopy(); + } +#endif +} + +#ifndef QT_NO_DRAGANDDROP +void QColorShowLabel::dragEnterEvent( QDragEnterEvent *e ) +{ + if ( QColorDrag::canDecode( e ) ) + e->accept(); + else + e->ignore(); +} + +void QColorShowLabel::dragLeaveEvent( QDragLeaveEvent * ) +{ +} + +void QColorShowLabel::dropEvent( QDropEvent *e ) +{ + if ( QColorDrag::canDecode( e ) ) { + QColorDrag::decode( e, col ); + repaint( FALSE ); + emit colorDropped( col.rgb() ); + e->accept(); + } else { + e->ignore(); + } +} +#endif // QT_NO_DRAGANDDROP + +void QColorShowLabel::mouseReleaseEvent( QMouseEvent * ) +{ + if ( !mousePressed ) + return; + mousePressed = FALSE; +} + +QColorShower::QColorShower( QWidget *parent, const char *name ) + :QWidget( parent, name) +{ + curCol = qRgb( -1, -1, -1 ); + QColIntValidator *val256 = new QColIntValidator( 0, 255, this ); + QColIntValidator *val360 = new QColIntValidator( 0, 360, this ); + + QGridLayout *gl = new QGridLayout( this, 1, 1, 6 ); + lab = new QColorShowLabel( this ); + lab->setMinimumWidth( 60 ); //### + gl->addMultiCellWidget(lab, 0,-1,0,0); + connect( lab, SIGNAL( colorDropped(QRgb) ), + this, SIGNAL( newCol(QRgb) ) ); + connect( lab, SIGNAL( colorDropped(QRgb) ), + this, SLOT( setRgb(QRgb) ) ); + + hEd = new QColNumLineEdit( this, "qt_hue_edit" ); + hEd->setValidator( val360 ); + QLabel *l = new QLabel( hEd, QColorDialog::tr("Hu&e:"), this, "qt_hue_lbl" ); + l->setAlignment( AlignRight|AlignVCenter ); + gl->addWidget( l, 0, 1 ); + gl->addWidget( hEd, 0, 2 ); + + sEd = new QColNumLineEdit( this, "qt_sat_edit" ); + sEd->setValidator( val256 ); + l = new QLabel( sEd, QColorDialog::tr("&Sat:"), this, "qt_sat_lbl" ); + l->setAlignment( AlignRight|AlignVCenter ); + gl->addWidget( l, 1, 1 ); + gl->addWidget( sEd, 1, 2 ); + + vEd = new QColNumLineEdit( this, "qt_val_edit" ); + vEd->setValidator( val256 ); + l = new QLabel( vEd, QColorDialog::tr("&Val:"), this, "qt_val_lbl" ); + l->setAlignment( AlignRight|AlignVCenter ); + gl->addWidget( l, 2, 1 ); + gl->addWidget( vEd, 2, 2 ); + + rEd = new QColNumLineEdit( this, "qt_red_edit" ); + rEd->setValidator( val256 ); + l = new QLabel( rEd, QColorDialog::tr("&Red:"), this, "qt_red_lbl" ); + l->setAlignment( AlignRight|AlignVCenter ); + gl->addWidget( l, 0, 3 ); + gl->addWidget( rEd, 0, 4 ); + + gEd = new QColNumLineEdit( this, "qt_grn_edit" ); + gEd->setValidator( val256 ); + l = new QLabel( gEd, QColorDialog::tr("&Green:"), this, "qt_grn_lbl" ); + l->setAlignment( AlignRight|AlignVCenter ); + gl->addWidget( l, 1, 3 ); + gl->addWidget( gEd, 1, 4 ); + + bEd = new QColNumLineEdit( this, "qt_blue_edit" ); + bEd->setValidator( val256 ); + l = new QLabel( bEd, QColorDialog::tr("Bl&ue:"), this, "qt_blue_lbl" ); + l->setAlignment( AlignRight|AlignVCenter ); + gl->addWidget( l, 2, 3 ); + gl->addWidget( bEd, 2, 4 ); + + alphaEd = new QColNumLineEdit( this, "qt_aplha_edit" ); + alphaEd->setValidator( val256 ); + alphaLab = new QLabel( alphaEd, QColorDialog::tr("A&lpha channel:"), this, "qt_alpha_lbl" ); + alphaLab->setAlignment( AlignRight|AlignVCenter ); + gl->addMultiCellWidget( alphaLab, 3, 3, 1, 3 ); + gl->addWidget( alphaEd, 3, 4 ); + alphaEd->hide(); + alphaLab->hide(); + + connect( hEd, SIGNAL(textChanged(const QString&)), this, SLOT(hsvEd()) ); + connect( sEd, SIGNAL(textChanged(const QString&)), this, SLOT(hsvEd()) ); + connect( vEd, SIGNAL(textChanged(const QString&)), this, SLOT(hsvEd()) ); + + connect( rEd, SIGNAL(textChanged(const QString&)), this, SLOT(rgbEd()) ); + connect( gEd, SIGNAL(textChanged(const QString&)), this, SLOT(rgbEd()) ); + connect( bEd, SIGNAL(textChanged(const QString&)), this, SLOT(rgbEd()) ); + connect( alphaEd, SIGNAL(textChanged(const QString&)), this, SLOT(rgbEd()) ); +} + +void QColorShower::showCurrentColor() +{ + lab->setColor( currentColor() ); + lab->repaint(FALSE); //### +} + +void QColorShower::rgbEd() +{ + rgbOriginal = TRUE; + if ( alphaEd->isVisible() ) + curCol = qRgba( rEd->val(), gEd->val(), bEd->val(), currentAlpha() ); + else + curCol = qRgb( rEd->val(), gEd->val(), bEd->val() ); + + rgb2hsv(currentColor(), hue, sat, val ); + + hEd->setNum( hue ); + sEd->setNum( sat ); + vEd->setNum( val ); + + showCurrentColor(); + emit newCol( currentColor() ); +} + +void QColorShower::hsvEd() +{ + rgbOriginal = FALSE; + hue = hEd->val(); + sat = sEd->val(); + val = vEd->val(); + + curCol = QColor( hue, sat, val, QColor::Hsv ).rgb(); + + rEd->setNum( qRed(currentColor()) ); + gEd->setNum( qGreen(currentColor()) ); + bEd->setNum( qBlue(currentColor()) ); + + showCurrentColor(); + emit newCol( currentColor() ); +} + +void QColorShower::setRgb( QRgb rgb ) +{ + rgbOriginal = TRUE; + curCol = rgb; + + rgb2hsv( currentColor(), hue, sat, val ); + + hEd->setNum( hue ); + sEd->setNum( sat ); + vEd->setNum( val ); + + rEd->setNum( qRed(currentColor()) ); + gEd->setNum( qGreen(currentColor()) ); + bEd->setNum( qBlue(currentColor()) ); + + showCurrentColor(); +} + +void QColorShower::setHsv( int h, int s, int v ) +{ + rgbOriginal = FALSE; + hue = h; val = v; sat = s; //Range check### + curCol = QColor( hue, sat, val, QColor::Hsv ).rgb(); + + hEd->setNum( hue ); + sEd->setNum( sat ); + vEd->setNum( val ); + + rEd->setNum( qRed(currentColor()) ); + gEd->setNum( qGreen(currentColor()) ); + bEd->setNum( qBlue(currentColor()) ); + + showCurrentColor(); +} + +class QColorDialogPrivate : public QObject +{ +Q_OBJECT +public: + QColorDialogPrivate( QColorDialog *p ); + QRgb currentColor() const { return cs->currentColor(); } + void setCurrentColor( QRgb rgb ); + + int currentAlpha() const { return cs->currentAlpha(); } + void setCurrentAlpha( int a ) { cs->setCurrentAlpha( a ); } + void showAlpha( bool b ) { cs->showAlpha( b ); } + +public slots: + void addCustom(); + + void newHsv( int h, int s, int v ); + void newColorTypedIn( QRgb rgb ); + void newCustom( int, int ); + void newStandard( int, int ); +public: + QWellArray *custom; + QWellArray *standard; + + QColorPicker *cp; + QColorLuminancePicker *lp; + QColorShower *cs; + int nextCust; + bool compact; +}; + +//sets all widgets to display h,s,v +void QColorDialogPrivate::newHsv( int h, int s, int v ) +{ + cs->setHsv( h, s, v ); + cp->setCol( h, s ); + lp->setCol( h, s, v ); +} + +//sets all widgets to display rgb +void QColorDialogPrivate::setCurrentColor( QRgb rgb ) +{ + cs->setRgb( rgb ); + newColorTypedIn( rgb ); +} + +//sets all widgets exept cs to display rgb +void QColorDialogPrivate::newColorTypedIn( QRgb rgb ) +{ + int h, s, v; + rgb2hsv(rgb, h, s, v ); + cp->setCol( h, s ); + lp->setCol( h, s, v); +} + +void QColorDialogPrivate::newCustom( int r, int c ) +{ + int i = r+2*c; + setCurrentColor( cusrgb[i] ); + nextCust = i; + if (standard) + standard->setSelected(-1,-1); +} + +void QColorDialogPrivate::newStandard( int r, int c ) +{ + setCurrentColor( stdrgb[r+c*6] ); + if (custom) + custom->setSelected(-1,-1); +} + +QColorDialogPrivate::QColorDialogPrivate( QColorDialog *dialog ) : + QObject(dialog) +{ + compact = FALSE; + // small displays (e.g. PDAs cannot fit the full color dialog, + // so just use the color picker. + if ( qApp->desktop()->width() < 480 || qApp->desktop()->height() < 350 ) + compact = TRUE; + + nextCust = 0; + const int lumSpace = 3; + int border = 12; + if ( compact ) + border = 6; + QHBoxLayout *topLay = new QHBoxLayout( dialog, border, 6 ); + QVBoxLayout *leftLay = 0; + + if ( !compact ) + leftLay = new QVBoxLayout( topLay ); + + initRGB(); + + if ( !compact ) { + standard = new QColorWell( dialog, 6, 8, stdrgb ); + standard->setCellWidth( 28 ); + standard->setCellHeight( 24 ); + QLabel * lab = new QLabel( standard, + QColorDialog::tr( "&Basic colors"), dialog, "qt_basiccolors_lbl" ); + connect( standard, SIGNAL(selected(int,int)), SLOT(newStandard(int,int))); + leftLay->addWidget( lab ); + leftLay->addWidget( standard ); + + + leftLay->addStretch(); + + custom = new QColorWell( dialog, 2, 8, cusrgb ); + custom->setCellWidth( 28 ); + custom->setCellHeight( 24 ); + custom->setAcceptDrops( TRUE ); + + connect( custom, SIGNAL(selected(int,int)), SLOT(newCustom(int,int))); + lab = new QLabel( custom, QColorDialog::tr( "&Custom colors") , dialog, "qt_custcolors_lbl" ); + leftLay->addWidget( lab ); + leftLay->addWidget( custom ); + + QPushButton *custbut = + new QPushButton( QColorDialog::tr("&Define Custom Colors >>"), + dialog, "qt_def_custcolors_lbl" ); + custbut->setEnabled( FALSE ); + leftLay->addWidget( custbut ); + } else { + // better color picker size for small displays + pWidth = 150; + pHeight = 100; + + custom = 0; + standard = 0; + } + + QVBoxLayout *rightLay = new QVBoxLayout( topLay ); + + QHBoxLayout *pickLay = new QHBoxLayout( rightLay ); + + + QVBoxLayout *cLay = new QVBoxLayout( pickLay ); + cp = new QColorPicker( dialog, "qt_colorpicker" ); + cp->setFrameStyle( QFrame::Panel + QFrame::Sunken ); + cLay->addSpacing( lumSpace ); + cLay->addWidget( cp ); + cLay->addSpacing( lumSpace ); + + lp = new QColorLuminancePicker( dialog, "qt_luminance_picker" ); + lp->setFixedWidth( 20 ); //### + pickLay->addWidget( lp ); + + connect( cp, SIGNAL(newCol(int,int)), lp, SLOT(setCol(int,int)) ); + connect( lp, SIGNAL(newHsv(int,int,int)), this, SLOT(newHsv(int,int,int)) ); + + rightLay->addStretch(); + + cs = new QColorShower( dialog, "qt_colorshower" ); + connect( cs, SIGNAL(newCol(QRgb)), this, SLOT(newColorTypedIn(QRgb))); + rightLay->addWidget( cs ); + + QHBoxLayout *buttons; + if ( compact ) + buttons = new QHBoxLayout( rightLay ); + else + buttons = new QHBoxLayout( leftLay ); + + QPushButton *ok, *cancel; + ok = new QPushButton( QColorDialog::tr("OK"), dialog, "qt_ok_btn" ); + connect( ok, SIGNAL(clicked()), dialog, SLOT(accept()) ); + ok->setDefault(TRUE); + cancel = new QPushButton( QColorDialog::tr("Cancel"), dialog, "qt_cancel_btn" ); + connect( cancel, SIGNAL(clicked()), dialog, SLOT(reject()) ); + buttons->addWidget( ok ); + buttons->addWidget( cancel ); + buttons->addStretch(); + + if ( !compact ) { + QPushButton *addCusBt = new QPushButton( + QColorDialog::tr("&Add to Custom Colors"), + dialog, "qt_add_btn" ); + rightLay->addWidget( addCusBt ); + connect( addCusBt, SIGNAL(clicked()), this, SLOT(addCustom()) ); + } +} + +void QColorDialogPrivate::addCustom() +{ + cusrgb[nextCust] = cs->currentColor(); + if (custom) + custom->repaintContents( FALSE ); + nextCust = (nextCust+1) % 16; +} + + +/*! + \class QColorDialog qcolordialog.h + \brief The QColorDialog class provides a dialog widget for specifying colors. + \mainclass + \ingroup dialogs + \ingroup graphics + + The color dialog's function is to allow users to choose colors. + For example, you might use this in a drawing program to allow the + user to set the brush color. + + The static functions provide modal color dialogs. + \omit + If you require a modeless dialog, use the QColorDialog constructor. + \endomit + + The static getColor() function shows the dialog and allows the + user to specify a color. The getRgba() function does the same but + also allows the user to specify a color with an alpha channel + (transparency) value. + + The user can store customCount() different custom colors. The + custom colors are shared by all color dialogs, and remembered + during the execution of the program. Use setCustomColor() to set + the custom colors, and use customColor() to get them. + + \img qcolordlg-w.png +*/ + +/*! + Constructs a default color dialog with parent \a parent and called + \a name. If \a modal is TRUE the dialog will be modal. Use + setColor() to set an initial value. + + \sa getColor() +*/ + +QColorDialog::QColorDialog(QWidget* parent, const char* name, bool modal) : + QDialog(parent, name, modal, ( WType_Dialog | WStyle_Customize | WStyle_Title | + WStyle_DialogBorder | WStyle_SysMenu ) ) +{ + setSizeGripEnabled( FALSE ); + d = new QColorDialogPrivate( this ); + +#ifndef QT_NO_SETTINGS + if ( !customSet ) { + QSettings settings; + settings.insertSearchPath( QSettings::Windows, "/Trolltech" ); + for ( int i = 0; i < 2*8; ++i ) { + bool ok = FALSE; + QRgb rgb = (QRgb)settings.readNumEntry( "/Qt/customColors/" + QString::number( i ), 0, &ok ); + if ( ok ) + cusrgb[i] = rgb; + } + } +#endif +} + +/*! + Pops up a modal color dialog, lets the user choose a color, and + returns that color. The color is initially set to \a initial. The + dialog is a child of \a parent and is called \a name. It returns + an invalid (see QColor::isValid()) color if the user cancels the + dialog. All colors allocated by the dialog will be deallocated + before this function returns. +*/ + +QColor QColorDialog::getColor( const QColor& initial, QWidget *parent, + const char *name ) +{ +#if defined(Q_WS_MAC) + return macGetColor(initial, parent, name); +#endif + + int allocContext = QColor::enterAllocContext(); + QColorDialog *dlg = new QColorDialog( parent, name, TRUE ); //modal +#ifndef QT_NO_WIDGET_TOPEXTRA + dlg->setCaption( QColorDialog::tr( "Select color" ) ); +#endif + dlg->setColor( initial ); + dlg->selectColor( initial ); + int resultCode = dlg->exec(); + QColor::leaveAllocContext(); + QColor result; + if ( resultCode == QDialog::Accepted ) + result = dlg->color(); + QColor::destroyAllocContext(allocContext); + delete dlg; + return result; +} + + +/*! + Pops up a modal color dialog to allow the user to choose a color + and an alpha channel (transparency) value. The color+alpha is + initially set to \a initial. The dialog is a child of \a parent + and called \a name. + + If \a ok is non-null, \e *\a ok is set to TRUE if the user clicked + OK, and to FALSE if the user clicked Cancel. + + If the user clicks Cancel, the \a initial value is returned. +*/ + +QRgb QColorDialog::getRgba( QRgb initial, bool *ok, + QWidget *parent, const char* name ) +{ +#if defined(Q_WS_MAC) + return macGetRgba(initial, ok, parent, name); +#endif + + int allocContext = QColor::enterAllocContext(); + QColorDialog *dlg = new QColorDialog( parent, name, TRUE ); //modal + + Q_CHECK_PTR( dlg ); +#ifndef QT_NO_WIDGET_TOPEXTRA + dlg->setCaption( QColorDialog::tr( "Select color" ) ); +#endif + dlg->setColor( initial ); + dlg->selectColor( initial ); + dlg->setSelectedAlpha( qAlpha(initial) ); + int resultCode = dlg->exec(); + QColor::leaveAllocContext(); + QRgb result = initial; + if ( resultCode == QDialog::Accepted ) { + QRgb c = dlg->color().rgb(); + int alpha = dlg->selectedAlpha(); + result = qRgba( qRed(c), qGreen(c), qBlue(c), alpha ); + } + if ( ok ) + *ok = resultCode == QDialog::Accepted; + + QColor::destroyAllocContext(allocContext); + delete dlg; + return result; +} + + + + + +/*! + Returns the color currently selected in the dialog. + + \sa setColor() +*/ + +QColor QColorDialog::color() const +{ + return QColor(d->currentColor()); +} + + +/*! + Destroys the dialog and frees any memory it allocated. +*/ + +QColorDialog::~QColorDialog() +{ +#ifndef QT_NO_SETTINGS + if ( !customSet ) { + QSettings settings; + settings.insertSearchPath( QSettings::Windows, "/Trolltech" ); + for ( int i = 0; i < 2*8; ++i ) + settings.writeEntry( "/Qt/customColors/" + QString::number( i ), (int)cusrgb[i] ); + } +#endif +} + + +/*! + Sets the color shown in the dialog to \a c. + + \sa color() +*/ + +void QColorDialog::setColor( const QColor& c ) +{ + d->setCurrentColor( c.rgb() ); +} + + + + +/*! + Sets the initial alpha channel value to \a a, and shows the alpha + channel entry box. +*/ + +void QColorDialog::setSelectedAlpha( int a ) +{ + d->showAlpha( TRUE ); + d->setCurrentAlpha( a ); +} + + +/*! + Returns the value selected for the alpha channel. +*/ + +int QColorDialog::selectedAlpha() const +{ + return d->currentAlpha(); +} + +/*! + Sets focus to the corresponding button, if any. +*/ +bool QColorDialog::selectColor( const QColor& col ) +{ + QRgb color = col.rgb(); + int i = 0, j = 0; + // Check standard colors + if (d->standard) { + for ( i = 0; i < 6; i++ ) { + for ( j = 0; j < 8; j++ ) { + if ( color == stdrgb[i + j*6] ) { + d->newStandard( i, j ); + d->standard->setCurrent( i, j ); + d->standard->setSelected( i, j ); + d->standard->setFocus(); + return TRUE; + } + } + } + } + // Check custom colors + if (d->custom) { + for ( i = 0; i < 2; i++ ) { + for ( j = 0; j < 8; j++ ) { + if ( color == cusrgb[i + j*2] ) { + d->newCustom( i, j ); + d->custom->setCurrent( i, j ); + d->custom->setSelected( i, j ); + d->custom->setFocus(); + return TRUE; + } + } + } + } + return FALSE; +} + +#include "qcolordialog.moc" + +#endif diff --git a/src/dialogs/qcolordialog.h b/src/dialogs/qcolordialog.h new file mode 100644 index 0000000..9860dc8 --- /dev/null +++ b/src/dialogs/qcolordialog.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Definition of QColorDialog class +** +** Created : 990222 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QCOLORDIALOG_H +#define QCOLORDIALOG_H + +#ifndef QT_H +#include "qdialog.h" +#endif // QT_H + +#ifndef QT_NO_COLORDIALOG + +class QColorDialogPrivate; + +class Q_EXPORT QColorDialog : public QDialog +{ + Q_OBJECT + +public: + static QColor getColor( const QColor& init = white, QWidget* parent=0, const char* name=0 ); + static QRgb getRgba( QRgb, bool* ok = 0, + QWidget* parent=0, const char* name=0 ); + + static int customCount(); + static QRgb customColor( int ); + static void setCustomColor( int, QRgb ); + static void setStandardColor( int, QRgb ); + +private: + ~QColorDialog(); + QColorDialog( QWidget* parent=0, const char* name=0, bool modal=FALSE ); + + void setColor( const QColor& ); + QColor color() const; + + bool selectColor( const QColor& ); + + void setSelectedAlpha( int ); + int selectedAlpha() const; + + void showCustom( bool=TRUE ); + +private: // Disabled copy constructor and operator= + QColorDialogPrivate *d; + friend class QColorDialogPrivate; + friend class QColorShower; + +#if defined(Q_DISABLE_COPY) + QColorDialog( const QColorDialog & ); + QColorDialog& operator=( const QColorDialog & ); +#endif +}; + +#endif + +#endif //QCOLORDIALOG_H diff --git a/src/dialogs/qdialog.cpp b/src/dialogs/qdialog.cpp new file mode 100644 index 0000000..a80f509 --- /dev/null +++ b/src/dialogs/qdialog.cpp @@ -0,0 +1,1178 @@ +/**************************************************************************** +** +** Implementation of QDialog class +** +** Created : 950502 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qdialog.h" + +#ifndef QT_NO_DIALOG + +#include "qpushbutton.h" +#include "qfocusdata.h" +#include "qapplication.h" +#include "qobjectlist.h" +#include "qwidgetlist.h" +#include "qlayout.h" +#include "qsizegrip.h" +#include "qwhatsthis.h" +#include "qpopupmenu.h" +#include "qcursor.h" +#if defined(QT_ACCESSIBILITY_SUPPORT) +#include "qaccessible.h" +#endif +#if defined( Q_OS_TEMP ) +#include "qt_windows.h" +#endif + +/*! + \class QDialog + \brief The QDialog class is the base class of dialog windows. + + \ingroup dialogs + \ingroup abstractwidgets + \mainclass + + A dialog window is a top-level window mostly used for short-term + tasks and brief communications with the user. QDialogs may be + modal or modeless. QDialogs support \link #extensibility + extensibility\endlink and can provide a \link #return return + value\endlink. They can have \link #default default + buttons\endlink. QDialogs can also have a QSizeGrip in their + lower-right corner, using setSizeGripEnabled(). + + Note that QDialog uses the parent widget slightly differently from + other classes in Qt. A dialog is always a top-level widget, but if + it has a parent, its default location is centered on top of the + parent's top-level widget (if it is not top-level itself). It will + also share the parent's taskbar entry. + + \target modal + \section1 Modal Dialogs + + A <b>modal</b> dialog is a dialog that blocks input to other + visible windows in the same application. Users must finish + interacting with the dialog and close it before they can access + any other window in the application. Dialogs that are used to + request a file name from the user or that are used to set + application preferences are usually modal. + + The most common way to display a modal dialog is to call its + exec() function. When the user closes the dialog, exec() will + provide a useful \link #return return value\endlink. Typically we + connect a default button, e.g. "OK", to the accept() slot and a + "Cancel" button to the reject() slot, to get the dialog to close + and return the appropriate value. Alternatively you can connect to + the done() slot, passing it \c Accepted or \c Rejected. + + An alternative is to call setModal(TRUE), then show(). Unlike + exec(), show() returns control to the caller immediately. Calling + setModal(TRUE) is especially useful for progress dialogs, where + the user must have the ability to interact with the dialog, e.g. + to cancel a long running operation. If you use show() and + setModal(TRUE) together you must call + QApplication::processEvents() periodically during processing to + enable the user to interact with the dialog. (See \l + QProgressDialog.) + + \target modeless + \section1 Modeless Dialogs + + A <b>modeless</b> dialog is a dialog that operates + independently of other windows in the same application. Find and + replace dialogs in word-processors are often modeless to allow the + user to interact with both the application's main window and with + the dialog. + + Modeless dialogs are displayed using show(), which returns control + to the caller immediately. + + \target default + \section1 Default button + + A dialog's \e default button is the button that's pressed when the + user presses Enter (Return). This button is used to signify that + the user accepts the dialog's settings and wants to close the + dialog. Use QPushButton::setDefault(), QPushButton::isDefault() + and QPushButton::autoDefault() to set and control the dialog's + default button. + + \target escapekey + \section1 Escape Key + + If the user presses the Esc key in a dialog, QDialog::reject() + will be called. This will cause the window to close: the \link + QCloseEvent closeEvent \endlink cannot be \link + QCloseEvent::ignore() ignored \endlink. + + \target extensibility + \section1 Extensibility + + Extensibility is the ability to show the dialog in two ways: a + partial dialog that shows the most commonly used options, and a + full dialog that shows all the options. Typically an extensible + dialog will initially appear as a partial dialog, but with a + "More" toggle button. If the user presses the "More" button down, + the full dialog will appear. The extension widget will be resized + to its sizeHint(). If orientation is \c Horizontal the extension + widget's height() will be expanded to the height() of the dialog. + If the orientation is \c Vertical the extension widget's width() + will be expanded to the width() of the dialog. Extensibility is + controlled with setExtension(), setOrientation() and + showExtension(). + + \target return + \section1 Return value (modal dialogs) + + Modal dialogs are often used in situations where a return value is + required, e.g. to indicate whether the user pressed "OK" or + "Cancel". A dialog can be closed by calling the accept() or the + reject() slots, and exec() will return \c Accepted or \c Rejected + as appropriate. The exec() call returns the result of the dialog. + The result is also available from result() if the dialog has not + been destroyed. If the \c WDestructiveClose flag is set, the + dialog is deleted after exec() returns. + + \target examples + \section1 Examples + + A modal dialog. + + \quotefile network/networkprotocol/view.cpp + \skipto QFileDialog *dlg + \printuntil return + + A modeless dialog. After the show() call, control returns to the main + event loop. + \quotefile life/main.cpp + \skipto argv + \printuntil QApplication + \skipto scale + \printline + \skipto LifeDialog + \printuntil show + \skipto exec + \printuntil } + + \sa QTabDialog QWidget QProgressDialog + \link guibooks.html#fowler GUI Design Handbook: Dialogs, Standard\endlink +*/ + +/*! \enum QDialog::DialogCode + + The value returned by a modal dialog. + + \value Accepted + \value Rejected + +*/ + +/*! + \property QDialog::sizeGripEnabled + \brief whether the size grip is enabled + + A QSizeGrip is placed in the bottom right corner of the dialog when this + property is enabled. By default, the size grip is disabled. +*/ + +class QDialogPrivate : public Qt +{ +public: + + QDialogPrivate() + : mainDef(0), orientation(Horizontal),extension(0), doShowExtension(FALSE) +#ifndef QT_NO_SIZEGRIP + ,resizer(0) +#endif + { + } + + QPushButton* mainDef; + Orientation orientation; + QWidget* extension; + bool doShowExtension; + QSize size, min, max; +#ifndef QT_NO_SIZEGRIP + QSizeGrip* resizer; +#endif + QPoint lastRMBPress; + QPoint relPos; // relative position to the main window +}; + +/*! + Constructs a dialog called \a name, with parent \a parent. + + A dialog is always a top-level widget, but if it has a parent, its + default location is centered on top of the parent. It will also + share the parent's taskbar entry. + + The widget flags \a f are passed on to the QWidget constructor. + If, for example, you don't want a What's This button in the titlebar + of the dialog, pass WStyle_Customize | WStyle_NormalBorder | + WStyle_Title | WStyle_SysMenu in \a f. + + \warning In Qt 3.2, the \a modal flag is obsolete. There is now a + setModal() function that can be used for obtaining a modal behavior + when calling show(). This is rarely needed, because modal dialogs + are usually invoked using exec(), which ignores the \a modal flag. + + \sa QWidget::setWFlags() Qt::WidgetFlags +*/ + +QDialog::QDialog( QWidget *parent, const char *name, bool modal, WFlags f ) + : QWidget( parent, name, + (modal ? (f|WShowModal) : f) | WType_Dialog ), + rescode(0), did_move(0), has_relpos(0), did_resize(0), in_loop(0) +{ + d = new QDialogPrivate; +} + +/*! + Destroys the QDialog, deleting all its children. +*/ + +QDialog::~QDialog() +{ + // Need to hide() here, as our (to-be) overridden hide() + // will not be called in ~QWidget. + hide(); + delete d; +} + +/*! + \internal + This function is called by the push button \a pushButton when it + becomes the default button. If \a pushButton is 0, the dialogs + default default button becomes the default button. This is what a + push button calls when it loses focus. +*/ + +void QDialog::setDefault( QPushButton *pushButton ) +{ +#ifndef QT_NO_PUSHBUTTON + QObjectList *list = queryList( "QPushButton" ); + Q_ASSERT(list); + QObjectListIt it( *list ); + QPushButton *pb; + bool hasMain = FALSE; + while ( (pb = (QPushButton*)it.current()) ) { + ++it; + if ( pb->topLevelWidget() != this ) + continue; + if ( pb == d->mainDef ) + hasMain = TRUE; + if ( pb != pushButton ) + pb->setDefault( FALSE ); + } + if (!pushButton && hasMain) + d->mainDef->setDefault( TRUE ); + if (!hasMain) + d->mainDef = pushButton; + delete list; +#endif +} + +/*! + \internal + This function sets the default default pushbutton to \a pushButton. + This function is called by QPushButton::setDefault(). +*/ +void QDialog::setMainDefault( QPushButton *pushButton ) +{ +#ifndef QT_NO_PUSHBUTTON + d->mainDef = 0; + setDefault(pushButton); +#endif +} + +/*! + \internal + Hides the default button indicator. Called when non auto-default + push button get focus. + */ +void QDialog::hideDefault() +{ +#ifndef QT_NO_PUSHBUTTON + QObjectList *list = queryList( "QPushButton" ); + QObjectListIt it( *list ); + QPushButton *pb; + while ( (pb = (QPushButton*)it.current()) ) { + ++it; + pb->setDefault( FALSE ); + } + delete list; +#endif +} + +#ifdef Q_OS_TEMP +/*! + \internal + Hides special buttons which are rather shown in the titlebar + on WinCE, to conserve screen space. +*/ +# include "qmessagebox.h" +extern const char * mb_texts[]; // Defined in qmessagebox.cpp +void QDialog::hideSpecial() +{ + // "OK" buttons are hidden, and (Ok) shown on titlebar + // "Cancel" buttons are hidden, and (X) shown on titlebar + // "Help" buttons are hidden, and (?) shown on titlebar + bool showOK = FALSE, + showX = FALSE, + showQ = FALSE; + QObjectList *list = queryList( "QPushButton" ); + QObjectListIt it( *list ); + QPushButton *pb; + while ( (pb = (QPushButton*)it.current()) ) { + if ( !showOK && + pb->text() == qApp->translate( "QMessageBox", mb_texts[QMessageBox::Ok] ) ) { + pb->hide(); + showOK = TRUE; + } else if ( !showX && + pb->text() == qApp->translate( "QMessageBox", mb_texts[QMessageBox::Cancel] ) ) { + pb->hide(); + showX = TRUE; + } else if ( !showQ && + pb->text() == qApp->tr("Help") ) { + pb->hide(); + showQ = TRUE; + } + ++it; + } + delete list; + if ( showOK || showQ ) { + DWORD ext = GetWindowLong( winId(), GWL_EXSTYLE ); + ext |= showOK ? WS_EX_CAPTIONOKBTN : 0; + ext |= showQ ? WS_EX_CONTEXTHELP: 0; + SetWindowLong( winId(), GWL_EXSTYLE, ext ); + } + if ( !showX ) { + DWORD ext = GetWindowLong( winId(), GWL_STYLE ); + ext &= ~WS_SYSMENU; + SetWindowLong( winId(), GWL_STYLE, ext ); + } +} +#endif + +/*! + \fn int QDialog::result() const + + Returns the modal dialog's result code, \c Accepted or \c Rejected. + + Do not call this function if the dialog was constructed with the \c + WDestructiveClose flag. +*/ + +/*! + \fn void QDialog::setResult( int i ) + + Sets the modal dialog's result code to \a i. +*/ + + +/*! + Shows the dialog as a \link #modal modal \endlink dialog, + blocking until the user closes it. The function returns a \l + DialogCode result. + + Users cannot interact with any other window in the same + application until they close the dialog. + + \sa show(), result() +*/ + +int QDialog::exec() +{ + if ( in_loop ) { + qWarning( "QDialog::exec: Recursive call detected" ); + return -1; + } + + bool destructiveClose = testWFlags( WDestructiveClose ); + clearWFlags( WDestructiveClose ); + + bool wasShowModal = testWFlags( WShowModal ); + setWFlags( WShowModal ); + setResult( 0 ); + + show(); + + in_loop = TRUE; + qApp->enter_loop(); + + if ( !wasShowModal ) + clearWFlags( WShowModal ); + + int res = result(); + + if ( destructiveClose ) + delete this; + + return res; +} + + +/*! Closes the dialog and sets its result code to \a r. If this dialog + is shown with exec(), done() causes the local event loop to finish, + and exec() to return \a r. + + As with QWidget::close(), done() deletes the dialog if the \c + WDestructiveClose flag is set. If the dialog is the application's + main widget, the application terminates. If the dialog is the + last window closed, the QApplication::lastWindowClosed() signal is + emitted. + + \sa accept(), reject(), QApplication::mainWidget(), QApplication::quit() +*/ + +void QDialog::done( int r ) +{ + hide(); + setResult( r ); + + // emulate QWidget::close() + bool isMain = qApp->mainWidget() == this; + bool checkLastWindowClosed = isTopLevel() && !isPopup(); + if ( checkLastWindowClosed + && qApp->receivers(SIGNAL(lastWindowClosed())) ) { + /* if there is no non-withdrawn top level window left (except + the desktop, popups, or dialogs with parents), we emit the + lastWindowClosed signal */ + QWidgetList *list = qApp->topLevelWidgets(); + QWidget *widget = list->first(); + while ( widget ) { + if ( !widget->isHidden() + && !widget->isDesktop() + && !widget->isPopup() + && (!widget->isDialog() || !widget->parentWidget())) + break; + widget = list->next(); + } + delete list; + if ( widget == 0 ) + emit qApp->lastWindowClosed(); + } + if ( isMain ) + qApp->quit(); + else if ( testWFlags(WDestructiveClose) ) { + clearWFlags(WDestructiveClose); + deleteLater(); + } +} + +/*! + Hides the modal dialog and sets the result code to \c Accepted. + + \sa reject() done() +*/ + +void QDialog::accept() +{ + done( Accepted ); +} + +/*! + Hides the modal dialog and sets the result code to \c Rejected. + + \sa accept() done() +*/ + +void QDialog::reject() +{ + done( Rejected ); +} + +/*! \reimp */ +bool QDialog::eventFilter( QObject *o, QEvent *e ) +{ + return QWidget::eventFilter( o, e ); +} + +/***************************************************************************** + Event handlers + *****************************************************************************/ + +/*! \reimp */ +void QDialog::contextMenuEvent( QContextMenuEvent *e ) +{ +#if !defined(QT_NO_WHATSTHIS) && !defined(QT_NO_POPUPMENU) + QWidget* w = childAt( e->pos(), TRUE ); + if ( !w ) + return; + QString s; + while ( s.isEmpty() && w ) { + s = QWhatsThis::textFor( w, e->pos(), FALSE ); + if ( s.isEmpty() ) + w = w->parentWidget(TRUE); + } + if ( !s.isEmpty() ) { + QPopupMenu p(0,"qt_whats_this_menu"); + p.insertItem( tr("What's This?"), 42 ); + if ( p.exec( e->globalPos() ) >= 42 ) + QWhatsThis::display( s, w->mapToGlobal( w->rect().center() ), w ); + } +#endif +} + +/*! \reimp */ +void QDialog::keyPressEvent( QKeyEvent *e ) +{ + // Calls reject() if Escape is pressed. Simulates a button + // click for the default button if Enter is pressed. Move focus + // for the arrow keys. Ignore the rest. +#ifdef Q_OS_MAC + if(e->state() == ControlButton && e->key() == Key_Period) { + reject(); + } else +#endif + if ( e->state() == 0 || ( e->state() & Keypad && e->key() == Key_Enter ) ) { + switch ( e->key() ) { + case Key_Enter: + case Key_Return: { +#ifndef QT_NO_PUSHBUTTON + QObjectList *list = queryList( "QPushButton" ); + QObjectListIt it( *list ); + QPushButton *pb; + while ( (pb = (QPushButton*)it.current()) ) { + if ( pb->isDefault() && pb->isVisible() ) { + delete list; + if ( pb->isEnabled() ) { + emit pb->clicked(); + } + return; + } + ++it; + } + delete list; +#endif + } + break; + case Key_Escape: + reject(); + break; + case Key_Up: + case Key_Left: + if ( focusWidget() && + ( focusWidget()->focusPolicy() == QWidget::StrongFocus || + focusWidget()->focusPolicy() == QWidget::WheelFocus ) ) { + e->ignore(); + break; + } + // call ours, since c++ blocks us from calling the one + // belonging to focusWidget(). + QFocusEvent::setReason(QFocusEvent::Backtab); + focusNextPrevChild( FALSE ); + QFocusEvent::resetReason(); + break; + case Key_Down: + case Key_Right: + if ( focusWidget() && + ( focusWidget()->focusPolicy() == QWidget::StrongFocus || + focusWidget()->focusPolicy() == QWidget::WheelFocus ) ) { + e->ignore(); + break; + } + QFocusEvent::setReason(QFocusEvent::Tab); + focusNextPrevChild( TRUE ); + QFocusEvent::resetReason(); + break; + default: + e->ignore(); + return; + } + } else { + e->ignore(); + } +} + +/*! \reimp */ +void QDialog::closeEvent( QCloseEvent *e ) +{ +#ifndef QT_NO_WHATSTHIS + if ( isModal() && QWhatsThis::inWhatsThisMode() ) + QWhatsThis::leaveWhatsThisMode(); +#endif + if ( isShown() ) + reject(); + if ( isHidden() ) + e->accept(); +} + +#ifdef Q_OS_TEMP +/*! \internal + \reimp +*/ +bool QDialog::event( QEvent *e ) +{ + switch ( e->type() ) { + case QEvent::OkRequest: + case QEvent::HelpRequest: + { + QString bName = + (e->type() == QEvent::OkRequest) + ? qApp->translate( "QMessageBox", mb_texts[QMessageBox::Ok] ) + : qApp->tr( "Help" ); + + QObjectList *list = queryList( "QPushButton" ); + QObjectListIt it( *list ); + QPushButton *pb; + while ( (pb = (QPushButton*)it.current()) ) { + if ( pb->text() == bName ) { + delete list; + if ( pb->isEnabled() ) + emit pb->clicked(); + return pb->isEnabled(); + } + ++it; + } + delete list; + } + } + return QWidget::event( e ); +} +#endif + + +/***************************************************************************** + Geometry management. + *****************************************************************************/ + +#if defined(Q_WS_X11) +extern "C" { int XSetTransientForHint( Display *, unsigned long, unsigned long ); } +#include <private/qt_x11_p.h> +#undef FocusIn +// defined in qapplication_x11.cpp +extern Atom qt_net_wm_full_placement; +extern bool qt_net_supports(Atom atom); +#endif // Q_WS_X11 + +/*! + Shows the dialog as a \link #modeless modeless \endlink dialog. + Control returns immediately to the calling code. + + The dialog will be modal or modeless according to the value + of the \l modal property. + + \sa exec(), modal +*/ + +void QDialog::show() +{ + if ( testWState(WState_Visible) ) + return; + + uint state = windowState(); + + if ( !did_resize ) + adjustSize(); + if( !qt_net_supports( qt_net_wm_full_placement )) { + if ( has_relpos && !did_move ) { + adjustPositionInternal( parentWidget(), TRUE ); + } else if ( !did_move ) { + adjustPositionInternal( parentWidget() ); + } + } + + if (windowState() != state) + setWindowState(state); + +#if defined(Q_WS_X11) + if (!parentWidget() && testWFlags(WShowModal) + && qApp->mainWidget() && qApp->mainWidget()->isVisible() + && !qApp->mainWidget()->isMinimized()) { + // make sure the transient for hint is set properly for modal dialogs + x11SetWindowTransient( qApp->mainWidget()); + } +#endif // Q_WS_X11 + +#ifdef Q_OS_TEMP + hideSpecial(); +#endif + + QWidget::show(); + showExtension( d->doShowExtension ); +#ifndef QT_NO_PUSHBUTTON + QWidget *fw = focusWidget(); + QFocusData *fd = focusData(); + + /* + The following block is to handle a special case, and does not + really follow propper logic in concern of autoDefault and TAB + order. However, it's here to ease usage for the users. If a + dialog has a default QPushButton, and first widget in the TAB + order also is a QPushButton, then we give focus to the main + default QPushButton. This simplifies code for the developers, + and actually catches most cases... If not, then they simply + have to use [widget*]->setFocus() themselves... + */ + if ( !fw || fw->focusPolicy() == NoFocus ) { + fd->home(); // Skip main form + QWidget *first = fd->next(); // Get first main widget + if ( d->mainDef && + first != d->mainDef && + ::qt_cast<QPushButton*>(first) ) + d->mainDef->setFocus(); + } + + if ( !d->mainDef && isTopLevel() ) { + if ( !fw || fw->focusPolicy() == NoFocus ) { + focusNextPrevChild( TRUE ); + fw = focusWidget(); + } + if ( fw ) { + fd = focusData(); + QWidget *home = fd->home(); + QWidget *candidate = home; + Q_ASSERT( candidate == fw ); + do { + QPushButton *pb = ::qt_cast<QPushButton*>(candidate); + if ( pb && pb->autoDefault() ) { + pb->setDefault( TRUE ); + break; + } + candidate = fd->next(); + } while ( candidate != home ); + } + } + if ( fw ) { + QFocusEvent e( QEvent::FocusIn ); + QFocusEvent::setReason( QFocusEvent::Tab ); + QApplication::sendEvent( fw, &e ); + QFocusEvent::resetReason(); + } + +#endif +#if defined(QT_ACCESSIBILITY_SUPPORT) + QAccessible::updateAccessibility( this, 0, QAccessible::DialogStart ); +#endif +} + +/*! \internal */ +void QDialog::adjustPosition( QWidget* w) +{ + adjustPositionInternal( w ); +} + + +void QDialog::adjustPositionInternal( QWidget*w, bool useRelPos) +{ + /* need to make sure these events are already sent to be sure + our information below is correct --sam */ + QApplication::sendPostedEvents( this, QEvent::LayoutHint ); + QApplication::sendPostedEvents( this, QEvent::Resize ); + + // processing the events might call polish(), which is a nice place + // to restore geometries, so return if the dialog has been positioned + if ( did_move || has_relpos ) + return; + + QPoint p( 0, 0 ); + int extraw = 0, extrah = 0, scrn = 0; + if ( w ) + w = w->topLevelWidget(); + QRect desk; + if ( w ) { + // Use mapToGlobal rather than geometry() in case w might + // be embedded in another application + scrn = QApplication::desktop()->screenNumber( w->mapToGlobal( QPoint(0,0) ) ); + } else if ( QApplication::desktop()->isVirtualDesktop() ) { + scrn = QApplication::desktop()->screenNumber( QCursor::pos() ); + } else { + scrn = QApplication::desktop()->screenNumber( this ); + } + desk = QApplication::desktop()->availableGeometry( scrn ); + + QWidgetList *list = QApplication::topLevelWidgets(); + QWidgetListIt it( *list ); + while ( (extraw == 0 || extrah == 0) && + it.current() != 0 ) { + int framew, frameh; + QWidget * current = it.current(); + ++it; + if ( ! current->isVisible() ) + continue; + + framew = current->geometry().x() - current->x(); + frameh = current->geometry().y() - current->y(); + + extraw = QMAX( extraw, framew ); + extrah = QMAX( extrah, frameh ); + } + delete list; + + // sanity check for decoration frames. With embedding, we + // might get extraordinary values + if ( extraw == 0 || extrah == 0 || extraw >= 10 || extrah >= 40 ) { + extrah = 40; + extraw = 10; + } + + if ( useRelPos && w ) { + p = w->pos() + d->relPos; + } else { +#ifndef Q_OS_TEMP + if ( w ) { + // Use mapToGlobal rather than geometry() in case w might + // be embedded in another application + QPoint pp = w->mapToGlobal( QPoint(0,0) ); + p = QPoint( pp.x() + w->width()/2, + pp.y() + w->height()/ 2 ); + } else { + // p = middle of the desktop + p = QPoint( desk.x() + desk.width()/2, desk.y() + desk.height()/2 ); + } +#else + p = QPoint( desk.x() + desk.width()/2, desk.y() + desk.height()/2 ); +#endif + + // p = origin of this + p = QPoint( p.x()-width()/2 - extraw, + p.y()-height()/2 - extrah ); + } + + + if ( p.x() + extraw + width() > desk.x() + desk.width() ) + p.setX( desk.x() + desk.width() - width() - extraw ); + if ( p.x() < desk.x() ) + p.setX( desk.x() ); + + if ( p.y() + extrah + height() > desk.y() + desk.height() ) + p.setY( desk.y() + desk.height() - height() - extrah ); + if ( p.y() < desk.y() ) + p.setY( desk.y() ); + + move( p ); + did_move = !useRelPos; +} + + +/*! \reimp */ +void QDialog::hide() +{ + if ( isHidden() ) + return; + +#if defined(QT_ACCESSIBILITY_SUPPORT) + if ( isVisible() ) + QAccessible::updateAccessibility( this, 0, QAccessible::DialogEnd ); +#endif + + if ( parentWidget() && !did_move ) { + d->relPos = pos() - parentWidget()->topLevelWidget()->pos(); + has_relpos = 1; + } + + // Reimplemented to exit a modal when the dialog is hidden. + QWidget::hide(); + if ( in_loop ) { + in_loop = FALSE; + qApp->exit_loop(); + } +} + + +/***************************************************************************** + Detects any widget geometry changes done by the user. + *****************************************************************************/ + +/*! \reimp */ + +void QDialog::move( int x, int y ) +{ + did_move = TRUE; + QWidget::move( x, y ); +} + +/*! \reimp */ + +void QDialog::move( const QPoint &p ) +{ + did_move = TRUE; + QWidget::move( p ); +} + +/*! \reimp */ + +void QDialog::resize( int w, int h ) +{ + did_resize = TRUE; + QWidget::resize( w, h ); +} + +/*! \reimp */ + +void QDialog::resize( const QSize &s ) +{ + did_resize = TRUE; + QWidget::resize( s ); +} + +/*! \reimp */ + +void QDialog::setGeometry( int x, int y, int w, int h ) +{ + did_move = TRUE; + did_resize = TRUE; + QWidget::setGeometry( x, y, w, h ); +} + +/*! \reimp */ + +void QDialog::setGeometry( const QRect &r ) +{ + did_move = TRUE; + did_resize = TRUE; + QWidget::setGeometry( r ); +} + + +/*! + If \a orientation is \c Horizontal, the extension will be displayed + to the right of the dialog's main area. If \a orientation is \c + Vertical, the extension will be displayed below the dialog's main + area. + + \sa orientation(), setExtension() +*/ +void QDialog::setOrientation( Orientation orientation ) +{ + d->orientation = orientation; +} + +/*! + Returns the dialog's extension orientation. + + \sa setOrientation() +*/ +Qt::Orientation QDialog::orientation() const +{ + return d->orientation; +} + +/*! + Sets the widget, \a extension, to be the dialog's extension, + deleting any previous extension. The dialog takes ownership of the + extension. Note that if 0 is passed any existing extension will be + deleted. + + This function must only be called while the dialog is hidden. + + \sa showExtension(), setOrientation(), extension() + */ +void QDialog::setExtension( QWidget* extension ) +{ + delete d->extension; + d->extension = extension; + + if ( !extension ) + return; + + if ( extension->parentWidget() != this ) + extension->reparent( this, QPoint(0,0) ); + extension->hide(); +} + +/*! + Returns the dialog's extension or 0 if no extension has been + defined. + + \sa setExtension() + */ +QWidget* QDialog::extension() const +{ + return d->extension; +} + + +/*! + If \a showIt is TRUE, the dialog's extension is shown; otherwise the + extension is hidden. + + This slot is usually connected to the \l QButton::toggled() signal + of a QPushButton. + + A dialog with a visible extension is not resizeable. + + \sa show(), setExtension(), setOrientation() + */ +void QDialog::showExtension( bool showIt ) +{ + d->doShowExtension = showIt; + if ( !d->extension ) + return; + if ( !testWState(WState_Visible) ) + return; + if ( d->extension->isVisible() == showIt ) + return; + + if ( showIt ) { + d->size = size(); + d->min = minimumSize(); + d->max = maximumSize(); +#ifndef QT_NO_LAYOUT + if ( layout() ) + layout()->setEnabled( FALSE ); +#endif + QSize s( d->extension->sizeHint() + .expandedTo( d->extension->minimumSize() ) + .boundedTo( d->extension->maximumSize() ) ); + if ( d->orientation == Horizontal ) { + int h = QMAX( height(), s.height() ); + d->extension->setGeometry( width(), 0, s.width(), h ); + setFixedSize( width() + s.width(), h ); + } else { + int w = QMAX( width(), s.width() ); + d->extension->setGeometry( 0, height(), w, s.height() ); + setFixedSize( w, height() + s.height() ); + } + d->extension->show(); + } else { + d->extension->hide(); + // workaround for CDE window manager that won't shrink with (-1,-1) + setMinimumSize( d->min.expandedTo( QSize( 1, 1 ) ) ); + setMaximumSize( d->max ); + resize( d->size ); +#ifndef QT_NO_LAYOUT + if ( layout() ) + layout()->setEnabled( TRUE ); +#endif + } +} + + +/*! \reimp */ +QSize QDialog::sizeHint() const +{ + if ( d->extension ) + if ( d->orientation == Horizontal ) + return QSize( QWidget::sizeHint().width(), + QMAX( QWidget::sizeHint().height(),d->extension->sizeHint().height() ) ); + else + return QSize( QMAX( QWidget::sizeHint().width(), d->extension->sizeHint().width() ), + QWidget::sizeHint().height() ); + + return QWidget::sizeHint(); +} + + +/*! \reimp */ +QSize QDialog::minimumSizeHint() const +{ + if ( d->extension ) + if (d->orientation == Horizontal ) + return QSize( QWidget::minimumSizeHint().width(), + QMAX( QWidget::minimumSizeHint().height(), d->extension->minimumSizeHint().height() ) ); + else + return QSize( QMAX( QWidget::minimumSizeHint().width(), d->extension->minimumSizeHint().width() ), + QWidget::minimumSizeHint().height() ); + + return QWidget::minimumSizeHint(); +} + +/*! \property QDialog::modal + \brief whether show() should pop up the dialog as modal or modeless + + By default, this property is false and show() pops up the dialog as + modeless. + + exec() ignores the value of this property and always pops up the + dialog as modal. + + \sa show(), exec() +*/ + +void QDialog::setModal( bool modal ) +{ + if ( modal ) + setWFlags( WShowModal ); + else + clearWFlags( WShowModal ); +} + +bool QDialog::isModal() const +{ + return testWFlags( WShowModal ) != 0; +} + +bool QDialog::isSizeGripEnabled() const +{ +#ifndef QT_NO_SIZEGRIP + return !!d->resizer; +#else + return FALSE; +#endif +} + + +void QDialog::setSizeGripEnabled(bool enabled) +{ +#ifndef QT_NO_SIZEGRIP + if ( !enabled != !d->resizer ) { + if ( enabled ) { + d->resizer = new QSizeGrip( this, "QDialog::resizer" ); + // adjustSize() processes all events, which is suboptimal + d->resizer->resize( d->resizer->sizeHint() ); + if ( QApplication::reverseLayout() ) + d->resizer->move( rect().bottomLeft() -d->resizer->rect().bottomLeft() ); + else + d->resizer->move( rect().bottomRight() -d->resizer->rect().bottomRight() ); + d->resizer->raise(); + d->resizer->show(); + } else { + delete d->resizer; + d->resizer = 0; + } + } +#endif //QT_NO_SIZEGRIP +} + + + +/*! \reimp */ +void QDialog::resizeEvent( QResizeEvent * ) +{ +#ifndef QT_NO_SIZEGRIP + if ( d->resizer ) { + if ( QApplication::reverseLayout() ) + d->resizer->move( rect().bottomLeft() -d->resizer->rect().bottomLeft() ); + else + d->resizer->move( rect().bottomRight() -d->resizer->rect().bottomRight() ); + } +#endif +} + +#endif // QT_NO_DIALOG diff --git a/src/dialogs/qdialog.h b/src/dialogs/qdialog.h new file mode 100644 index 0000000..612b351 --- /dev/null +++ b/src/dialogs/qdialog.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Definition of QDialog class +** +** Created : 950502 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QDIALOG_H +#define QDIALOG_H + +#ifndef QT_H +#include "qwidget.h" +#endif // QT_H +#ifndef QT_NO_DIALOG +#if 0 +Q_OBJECT +#endif + +class QPushButton; +class QDialogPrivate; + +class Q_EXPORT QDialog : public QWidget +{ +friend class QPushButton; + Q_OBJECT + Q_PROPERTY( bool sizeGripEnabled READ isSizeGripEnabled WRITE setSizeGripEnabled ) + Q_PROPERTY( bool modal READ isModal WRITE setModal ) + +public: + Q_EXPLICIT QDialog( QWidget* parent=0, const char* name=0, bool modal=FALSE, + WFlags f=0 ); + ~QDialog(); + + enum DialogCode { Rejected, Accepted }; + + int result() const { return rescode; } + + void show(); + void hide(); + void move( int x, int y ); + void move( const QPoint &p ); + void resize( int w, int h ); + void resize( const QSize & ); + void setGeometry( int x, int y, int w, int h ); + void setGeometry( const QRect & ); + + void setOrientation( Orientation orientation ); + Orientation orientation() const; + + void setExtension( QWidget* extension ); + QWidget* extension() const; + + QSize sizeHint() const; + QSize minimumSizeHint() const; + + void setSizeGripEnabled( bool ); + bool isSizeGripEnabled() const; + + void setModal( bool modal ); + bool isModal() const; +#ifdef Q_OS_TEMP + bool event( QEvent * ); +#endif + +public slots: + int exec(); + +protected slots: + virtual void done( int ); + virtual void accept(); + virtual void reject(); + + void showExtension( bool ); + +protected: + void setResult( int r ) { rescode = r; } + void keyPressEvent( QKeyEvent * ); + void closeEvent( QCloseEvent * ); + void resizeEvent( QResizeEvent * ); + void contextMenuEvent( QContextMenuEvent * ); + bool eventFilter( QObject *, QEvent * ); + void adjustPosition( QWidget*); + +private: + void setDefault( QPushButton * ); + void setMainDefault( QPushButton * ); + void hideDefault(); +#ifdef Q_OS_TEMP + void hideSpecial(); +#endif + + int rescode; + uint did_move : 1; + uint has_relpos : 1; + uint did_resize : 1; + uint in_loop: 1; + void adjustPositionInternal( QWidget*, bool useRelPos = FALSE ); + QDialogPrivate* d; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QDialog( const QDialog & ); + QDialog &operator=( const QDialog & ); +#endif +}; + +#endif // QT_NO_DIALOG +#endif // QDIALOG_H diff --git a/src/dialogs/qerrormessage.cpp b/src/dialogs/qerrormessage.cpp new file mode 100644 index 0000000..4e4dc5a --- /dev/null +++ b/src/dialogs/qerrormessage.cpp @@ -0,0 +1,270 @@ +/**************************************************************************** +** +** Implementation of a nice qInstallMsgHandler() handler +** +** Created : 000527, after Kalle Dalheimer's birthday +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qerrormessage.h" + +#ifndef QT_NO_ERRORMESSAGE + +#include "qapplication.h" +#include "qcheckbox.h" +#include "qdict.h" +#include "qlabel.h" +#include "qlayout.h" +#include "qmessagebox.h" +#include "qpushbutton.h" +#include "qstringlist.h" +#include "qstylesheet.h" +#include "qtextview.h" + +#include <stdio.h> +#include <stdlib.h> + +class QErrorMessageTextView : public QTextView +{ +public: + QErrorMessageTextView( QWidget *parent, const char *name ) + : QTextView( parent, name ) { } + + virtual QSize minimumSizeHint() const; + virtual QSize sizeHint() const; +}; + +QSize QErrorMessageTextView::minimumSizeHint() const +{ + return QSize( 50, 50 ); +} + +QSize QErrorMessageTextView::sizeHint() const +{ + return QSize( 250, 75 ); +} + +/*! \class QErrorMessage + + \brief The QErrorMessage class provides an error message display dialog. + + \ingroup dialogs + \ingroup misc + +This is basically a QLabel and a "show this message again" checkbox which +remembers what not to show. + +There are two ways to use this class: +\list 1 +\i For production applications. In this context the class can be used to +display messages which you don't need the user to see more than once. To use +QErrorMessage like this, you create the dialog in the usual way and call the +message() slot, or connect signals to it. + +\i For developers. In this context the static qtHandler() installs +a message handler using qInstallMsgHandler() and creates a QErrorMessage +that displays qDebug(), qWarning() and qFatal() messages. +\endlist + +In both cases QErrorMessage will queue pending messages, and display +them (or not) in order, as soon as the user presses Enter or clicks OK +after seeing each message. + +\img qerrormessage.png + +\sa QMessageBox QStatusBar::message() +*/ + +static QErrorMessage * qtMessageHandler = 0; + +static void deleteStaticcQErrorMessage() // post-routine +{ + if ( qtMessageHandler ) { + delete qtMessageHandler; + qtMessageHandler = 0; + } +} + +static bool metFatal = FALSE; + +void jump( QtMsgType t, const char * m ) +{ + if ( !qtMessageHandler ) + return; + + QString rich; + + switch ( t ) { + case QtDebugMsg: + default: + rich = QErrorMessage::tr( "Debug Message:" ); + break; + case QtWarningMsg: + rich = QErrorMessage::tr( "Warning:" ); + break; + case QtFatalMsg: + rich = QErrorMessage::tr( "Fatal Error:" ); + } + rich = QString( "<p><b>%1</b></p>" ).arg( rich ); + rich += QStyleSheet::convertFromPlainText( m, + QStyleSheetItem::WhiteSpaceNormal ); + + // ### work around text engine quirk + if ( rich.endsWith("</p>") ) + rich.truncate( rich.length() - 4 ); + + if ( !metFatal ) { + qtMessageHandler->message( rich ); + metFatal = ( t == QtFatalMsg ); + } +} + + +/*! Constructs and installs an error handler window. + The parent \a parent and name \a name are passed on to the QDialog + constructor. +*/ + +QErrorMessage::QErrorMessage( QWidget * parent, const char * name ) + : QDialog( parent, name ) +{ + QGridLayout * grid = new QGridLayout( this, 3, 2, 11, 6 ); + icon = new QLabel( this, "qt_icon_lbl" ); +#ifndef QT_NO_MESSAGEBOX + icon->setPixmap( QMessageBox::standardIcon(QMessageBox::Information) ); +#endif + grid->addWidget( icon, 0, 0, AlignTop ); + errors = new QErrorMessageTextView( this, "errors" ); + grid->addWidget( errors, 0, 1 ); + again = new QCheckBox( tr( "&Show this message again" ), this, "again" ); + again->setChecked( TRUE ); + grid->addWidget( again, 1, 1, AlignTop + AlignAuto ); + ok = new QPushButton( tr( "&OK" ), this, "ok" ); + connect( ok, SIGNAL(clicked()), this, SLOT(accept()) ); + ok->setFocus(); + grid->addMultiCellWidget( ok, 2, 2, 0, 1, AlignCenter ); + grid->setColStretch( 1, 42 ); + grid->setRowStretch( 0, 42 ); + pending = new QStringList; + doNotShow = new QDict<int>; +} + + +/*! Destroys the object and frees any allocated resources. Notably, +the list of "do not show again" messages is deleted. */ + +QErrorMessage::~QErrorMessage() +{ + if ( this == qtMessageHandler ) { + qtMessageHandler = 0; + QtMsgHandler tmp = qInstallMsgHandler( 0 ); + // in case someone else has later stuck in another... + if ( tmp != jump ) + qInstallMsgHandler( tmp ); + } + + delete pending; + delete doNotShow; +} + + +/*! \reimp */ + +void QErrorMessage::done( int a ) +{ + int dummy = 0; + if ( !again->isChecked() ) + doNotShow->insert( errors->text(), &dummy ); + if ( !nextPending() ) { + QDialog::done( a ); + if ( this == qtMessageHandler && metFatal ) + exit( 1 ); + } +} + + +/*! Returns a pointer to a QErrorMessage object that outputs the +default Qt messages. This function creates such an object, if there +isn't one already. +*/ + +QErrorMessage * QErrorMessage::qtHandler() +{ + if ( !qtMessageHandler ) { + qtMessageHandler = new QErrorMessage( 0, "automatic message handler" ); + qAddPostRoutine( deleteStaticcQErrorMessage ); // clean up +#ifndef QT_NO_WIDGET_TOPEXTRA + if ( qApp->mainWidget() ) + qtMessageHandler->setCaption( qApp->mainWidget()->caption() ); +#endif + qInstallMsgHandler( jump ); + } + return qtMessageHandler; +} + + +/*! \internal */ + +bool QErrorMessage::nextPending() +{ + while ( !pending->isEmpty() ) { + QString p = *pending->begin(); + pending->remove( pending->begin() ); + if ( !p.isEmpty() && !doNotShow->find( p ) ) { + errors->setText( p ); + return TRUE; + } + } + return FALSE; +} + + +/*! Shows message \a m and returns immediately. If the user has requested + that \a m not be shown, this function does nothing. + + Normally, \a m is shown at once, but if there are pending messages, + \a m is queued for later display. +*/ + +void QErrorMessage::message( const QString & m ) +{ + if ( doNotShow->find( m ) ) + return; + pending->append( m ); + if ( !isVisible() && nextPending() ) + show(); +} + +#endif // QT_NO_ERRORMESSAGE diff --git a/src/dialogs/qerrormessage.h b/src/dialogs/qerrormessage.h new file mode 100644 index 0000000..c1a7149 --- /dev/null +++ b/src/dialogs/qerrormessage.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Definition of a nice qInstallErrorMessage() handler +** +** Created : 000527, after Kalle Dalheimer's birthday +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QERRORMESSAGE_H +#define QERRORMESSAGE_H + +#ifndef QT_H +#include "qdialog.h" +#endif // QT_H + +#ifndef QT_NO_ERRORMESSAGE +class QPushButton; +class QCheckBox; +class QLabel; +class QTextView; +class QStringList; +template<class type> class QDict; + + +class Q_EXPORT QErrorMessage: public QDialog { + Q_OBJECT +public: + QErrorMessage( QWidget* parent, const char* name=0 ); + ~QErrorMessage(); + + static QErrorMessage * qtHandler(); + +public slots: + void message( const QString & ); + +protected: + void done( int ); + +private: + QPushButton * ok; + QCheckBox * again; + QTextView * errors; + QLabel * icon; + QStringList * pending; + QDict<int> * doNotShow; + + bool nextPending(); + +#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator= + QErrorMessage( const QErrorMessage & ); + QErrorMessage &operator=( const QErrorMessage & ); +#endif +}; + +#endif //QT_NO_ERRORMESSAGE + +#endif diff --git a/src/dialogs/qfiledialog.cpp b/src/dialogs/qfiledialog.cpp new file mode 100644 index 0000000..d696204 --- /dev/null +++ b/src/dialogs/qfiledialog.cpp @@ -0,0 +1,6461 @@ +/**************************************************************************** +** +** Implementation of QFileDialog class +** +** Created : 950429 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qplatformdefs.h" + +// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED. +#if defined(connect) +# undef connect +#endif + +// POSIX Large File Support redefines truncate -> truncate64 +#if defined(truncate) +# undef truncate +#endif + +#include "qfiledialog.h" + +#ifndef QT_NO_FILEDIALOG + +#include "private/qapplication_p.h" +#include "qapplication.h" +#include "qbitmap.h" +#include "qbuttongroup.h" +#include "qcheckbox.h" +#include "qcleanuphandler.h" +#include "qcombobox.h" +#include "qcstring.h" +#include "qcursor.h" +#include "qdragobject.h" +#include "qfile.h" +#include "qguardedptr.h" +#include "qhbox.h" +#include "qheader.h" +#include "qlabel.h" +#include "qlayout.h" +#include "qlibrary.h" +#include "qlineedit.h" +#include "qlistbox.h" +#include "qlistview.h" +#include "qmap.h" +#include "qmessagebox.h" +#include "qmime.h" +#include "qnetworkprotocol.h" +#include "qobjectlist.h" +#include "qpainter.h" +#include "qpopupmenu.h" +#include "qprogressbar.h" +#include "qptrvector.h" +#include "qpushbutton.h" +#include "qregexp.h" +#include "qsemimodal.h" +#include "qsplitter.h" +#include "qstrlist.h" +#include "qstyle.h" +#include "qtimer.h" +#include "qtoolbutton.h" +#include "qtooltip.h" +#include "qvbox.h" +#include "qwidgetstack.h" + +#ifdef Q_WS_WIN +#ifdef QT_THREAD_SUPPORT +# include <private/qmutexpool_p.h> +#endif // QT_THREAD_SUPPORT +#endif // Q_WS_WIN + +#if !defined(Q_OS_TEMP) +#include <time.h> +#else +#include <shellapi.h> +#endif +#include <stdlib.h> +#include <limits.h> +#include <ctype.h> + +#ifdef Q_WS_MAC +#include "qt_mac.h" +extern QString qt_mac_precomposeFileName(const QString &); // qglobal.cpp +#undef check +#endif + +/* XPM */ +static const char * const start_xpm[]={ + "16 15 8 1", + "a c #cec6bd", + "# c #000000", + "e c #ffff00", + "b c #999999", + "f c #cccccc", + "d c #dcdcdc", + "c c #ffffff", + ". c None", + ".....######aaaaa", + "...bb#cccc##aaaa", + "..bcc#cccc#d#aaa", + ".bcef#cccc#dd#aa", + ".bcfe#cccc#####a", + ".bcef#ccccccccc#", + "bbbbbbbbbbbbccc#", + "bccccccccccbbcc#", + "bcefefefefee#bc#", + ".bcefefefefef#c#", + ".bcfefefefefe#c#", + "..bcfefefefeeb##", + "..bbbbbbbbbbbbb#", + "...#############", + "................"}; + +/* XPM */ +static const char * const end_xpm[]={ + "16 15 9 1", + "d c #a0a0a0", + "c c #c3c3c3", + "# c #cec6bd", + ". c #000000", + "f c #ffff00", + "e c #999999", + "g c #cccccc", + "b c #ffffff", + "a c None", + "......####aaaaaa", + ".bbbb..###aaaaaa", + ".bbbb.c.##aaaaaa", + ".bbbb....ddeeeea", + ".bbbbbbb.bbbbbe.", + ".bbbbbbb.bcfgfe.", + "eeeeeeeeeeeeefe.", + "ebbbbbbbbbbeege.", + "ebfgfgfgfgff.ee.", + "aebfgfgfgfgfg.e.", + "aebgfgfgfgfgf.e.", + "aaebgfgfgfgffe..", + "aaeeeeeeeeeeeee.", + "aaa.............", + "aaaaaaaaaaaaaaaa"}; + +/* XPM */ +static const char* const open_xpm[]={ + "16 16 6 1", + ". c None", + "b c #ffff00", + "d c #000000", + "* c #999999", + "c c #cccccc", + "a c #ffffff", + "................", + "................", + "...*****........", + "..*aaaaa*.......", + ".*abcbcba******.", + ".*acbcbcaaaaaa*d", + ".*abcbcbcbcbcb*d", + "*************b*d", + "*aaaaaaaaaa**c*d", + "*abcbcbcbcbbd**d", + ".*abcbcbcbcbcd*d", + ".*acbcbcbcbcbd*d", + "..*acbcbcbcbb*dd", + "..*************d", + "...ddddddddddddd", + "................"}; + +/* XPM */ +static const char * const link_dir_xpm[]={ + "16 16 10 1", + "h c #808080", + "g c #a0a0a0", + "d c #000000", + "b c #ffff00", + "f c #303030", + "# c #999999", + "a c #cccccc", + "e c #585858", + "c c #ffffff", + ". c None", + "................", + "................", + "..#####.........", + ".#ababa#........", + "#abababa######..", + "#cccccccccccc#d.", + "#cbababababab#d.", + "#cabababababa#d.", + "#cbababdddddddd.", + "#cababadccccccd.", + "#cbababdcececcd.", + "#cababadcefdfcd.", + "#cbababdccgdhcd.", + "#######dccchccd.", + ".dddddddddddddd.", + "................"}; + +/* XPM */ +static const char * const link_file_xpm[]={ + "16 16 10 1", + "h c #808080", + "g c #a0a0a0", + "d c #c3c3c3", + ". c #7f7f7f", + "c c #000000", + "b c #bfbfbf", + "f c #303030", + "e c #585858", + "a c #ffffff", + "# c None", + "################", + "..........######", + ".aaaaaaaab.#####", + ".aaaaaaaaba.####", + ".aaaaaaaacccc###", + ".aaaaaaaaaabc###", + ".aaaaaaaaaabc###", + ".aaaaaaaaaadc###", + ".aaaaaaaaaadc###", + ".aaaacccccccc###", + ".aaaacaaaaaac###", + ".aaaacaeaeaac###", + ".aaaacaefcfac###", + ".aaaacaagchac###", + ".ddddcaaahaac###", + "ccccccccccccc###"}; + +/* XPM */ +static const char* const file_xpm[]={ + "16 16 5 1", + ". c #7f7f7f", + "# c None", + "c c #000000", + "b c #bfbfbf", + "a c #ffffff", + "################", + "..........######", + ".aaaaaaaab.#####", + ".aaaaaaaaba.####", + ".aaaaaaaacccc###", + ".aaaaaaaaaabc###", + ".aaaaaaaaaabc###", + ".aaaaaaaaaabc###", + ".aaaaaaaaaabc###", + ".aaaaaaaaaabc###", + ".aaaaaaaaaabc###", + ".aaaaaaaaaabc###", + ".aaaaaaaaaabc###", + ".aaaaaaaaaabc###", + ".bbbbbbbbbbbc###", + "ccccccccccccc###"}; + +/* XPM */ +static const char * const closed_xpm[]={ + "16 16 6 1", + ". c None", + "b c #ffff00", + "d c #000000", + "* c #999999", + "a c #cccccc", + "c c #ffffff", + "................", + "................", + "..*****.........", + ".*ababa*........", + "*abababa******..", + "*cccccccccccc*d.", + "*cbababababab*d.", + "*cabababababa*d.", + "*cbababababab*d.", + "*cabababababa*d.", + "*cbababababab*d.", + "*cabababababa*d.", + "*cbababababab*d.", + "**************d.", + ".dddddddddddddd.", + "................"}; + + +/* XPM */ +static const char* const cdtoparent_xpm[]={ + "15 13 3 1", + ". c None", + "* c #000000", + "a c #ffff99", + "..*****........", + ".*aaaaa*.......", + "***************", + "*aaaaaaaaaaaaa*", + "*aaaa*aaaaaaaa*", + "*aaa***aaaaaaa*", + "*aa*****aaaaaa*", + "*aaaa*aaaaaaaa*", + "*aaaa*aaaaaaaa*", + "*aaaa******aaa*", + "*aaaaaaaaaaaaa*", + "*aaaaaaaaaaaaa*", + "***************"}; + + +/* XPM */ +static const char* const newfolder_xpm[] = { + "15 14 4 1", + " c None", + ". c #000000", + "+ c #FFFF00", + "@ c #FFFFFF", + " . ", + " ", + " . ", + " . . ", + " .... . . . ", + " .+@+@. . . ", + ".......... . .", + ".@+@+@+@+@.. ", + ".+@+@+@+@+. . ", + ".@+@+@+@+@. . ", + ".+@+@+@+@+. ", + ".@+@+@+@+@. ", + ".+@+@+@+@+. ", + "........... "}; + +/* XPM */ +static const char* const detailedview_xpm[]={ + "14 11 3 1", + ". c None", + "* c #000000", + "a c #000099", + ".****.***.***.", + "..............", + "aaaaaaaaaaaaaa", + "..............", + ".****.***.***.", + "..............", + ".****.***.***.", + "..............", + ".****.***.***.", + "..............", + ".****.***.***."}; + +/* XPM */ +static const char* const previewinfoview_xpm[]={ + "13 13 4 1", + ". c #00007f", + "a c black", + "# c #cec6bd", + "b c #000000", + "..#####aaaaaa", + ".#.#bb#a#####", + "...####a#bbb#", + "#######a#####", + "#######a#bb##", + "..#####a#####", + ".#.#bb#a#bbb#", + "...####a#####", + "#######a#bb##", + "#######a#####", + "..#####a#bbb#", + ".#.#bb#a#####", + "...####aaaaaa"}; + +/* XPM */ +static const char* const previewcontentsview_xpm[]={ + "14 13 5 1", + ". c #00007f", + "a c black", + "c c #7f007f", + "# c #cec6bd", + "b c #000000", + "..#####aaaaaaa", + ".#.#bb#a#####a", + "...####a#ccc#a", + "#######a#ccc#a", + "#######a#####a", + "..#####a#bbb#a", + ".#.#bb#a#####a", + "...####a#bbb#a", + "#######a#####a", + "#######a#bbb#a", + "..#####a#####a", + ".#.#bb#a#####a", + "...####aaaaaaa"}; + +/* XPM */ +static const char* const mclistview_xpm[]={ + "15 11 4 1", + "* c None", + "b c #000000", + ". c #000099", + "a c #ffffff", + "...*****...****", + ".a.*bbb*.a.*bbb", + "...*****...****", + "***************", + "...*****...****", + ".a.*bbb*.a.*bbb", + "...*****...****", + "***************", + "...*****...****", + ".a.*bbb*.a.*bbb", + "...*****...****"}; + +/* XPM */ +static const char * const back_xpm [] = { + "13 11 3 1", + "a c #00ffff", + "# c #000000", + ". c None", + ".....#.......", + "....##.......", + "...#a#.......", + "..#aa########", + ".#aaaaaaaaaa#", + "#aaaaaaaaaaa#", + ".#aaaaaaaaaa#", + "..#aa########", + "...#a#.......", + "....##.......", + ".....#......."}; + +static QPixmap * openFolderIcon = 0; +static QPixmap * closedFolderIcon = 0; +static QPixmap * detailViewIcon = 0; +static QPixmap * multiColumnListViewIcon = 0; +static QPixmap * cdToParentIcon = 0; +static QPixmap * newFolderIcon = 0; +static QPixmap * fifteenTransparentPixels = 0; +static QPixmap * symLinkDirIcon = 0; +static QPixmap * symLinkFileIcon = 0; +static QPixmap * fileIcon = 0; +static QPixmap * startCopyIcon = 0; +static QPixmap * endCopyIcon = 0; +static QPixmap * previewContentsViewIcon = 0; +static QPixmap * previewInfoViewIcon = 0; +static QPixmap *goBackIcon = 0; +static QFileIconProvider * fileIconProvider = 0; +static int lastWidth = 0; +static int lastHeight = 0; +static QString * workingDirectory = 0; + +static bool bShowHiddenFiles = FALSE; +static int sortFilesBy = (int)QDir::Name; +static bool sortAscending = TRUE; +static bool detailViewMode = FALSE; + +static QCleanupHandler<QPixmap> qfd_cleanup_pixmap; +static QCleanupHandler<QString> qfd_cleanup_string; + +static QString toRootIfNotExists( const QString &path ) +{ + if ( !path.isEmpty() ) + return path; + + const QFileInfoList *drives = QDir::drives(); + Q_ASSERT( drives && !drives->isEmpty() ); + return drives->getFirst()->filePath(); +} + +static bool isDirectoryMode( int m ) +{ + return m == QFileDialog::Directory || m == QFileDialog::DirectoryOnly; +} + +static void updateLastSize( QFileDialog *that ) +{ + int extWidth = 0; + int extHeight = 0; + if ( that->extension() && that->extension()->isVisible() ) { + if ( that->orientation() == Qt::Vertical ) + extHeight = that->extension()->height(); + else + extWidth = that->extension()->width(); + } + lastWidth = that->width() - extWidth; + lastHeight = that->height() - extHeight; +} + +// Don't remove the lines below! +// +// resolving the W methods manually is needed, because Windows 95 doesn't include +// these methods in Shell32.lib (not even stubs!), so you'd get an unresolved symbol +// when Qt calls getEsistingDirectory(), etc. +#if defined(Q_WS_WIN) + +typedef UINT (WINAPI *PtrExtractIconEx)(LPCTSTR,int,HICON*,HICON*,UINT); +static PtrExtractIconEx ptrExtractIconEx = 0; + +static void resolveLibs() +{ +#ifndef Q_OS_TEMP + static bool triedResolve = FALSE; + + if ( !triedResolve ) { +#ifdef QT_THREAD_SUPPORT + // protect initialization + QMutexLocker locker( qt_global_mutexpool ? + qt_global_mutexpool->get( &triedResolve ) : 0 ); + // check triedResolve again, since another thread may have already + // done the initialization + if ( triedResolve ) { + // another thread did initialize the security function pointers, + // so we shouldn't do it again. + return; + } +#endif + triedResolve = TRUE; + if ( qt_winunicode ) { + QLibrary lib("shell32"); + lib.setAutoUnload( FALSE ); + ptrExtractIconEx = (PtrExtractIconEx) lib.resolve( "ExtractIconExW" ); + } + } +#endif +} +#ifdef Q_OS_TEMP +#define PtrExtractIconEx ExtractIconEx +#endif + +class QWindowsIconProvider : public QFileIconProvider +{ +public: + QWindowsIconProvider( QObject *parent=0, const char *name=0 ); + ~QWindowsIconProvider(); + + const QPixmap * pixmap( const QFileInfo &fi ); + +private: + QPixmap defaultFolder; + QPixmap defaultFile; + QPixmap defaultExe; + QPixmap pix; + int pixw, pixh; + QMap< QString, QPixmap > cache; + +}; +#endif + +static void makeVariables() { + if ( !openFolderIcon ) { + workingDirectory = new QString( ::toRootIfNotExists(QDir::currentDirPath()) ); + qfd_cleanup_string.add( &workingDirectory ); + + openFolderIcon = new QPixmap( (const char **)open_xpm); + qfd_cleanup_pixmap.add( &openFolderIcon ); + symLinkDirIcon = new QPixmap( (const char **)link_dir_xpm); + qfd_cleanup_pixmap.add( &symLinkDirIcon ); + symLinkFileIcon = new QPixmap( (const char **)link_file_xpm); + qfd_cleanup_pixmap.add( &symLinkFileIcon ); + fileIcon = new QPixmap( (const char **)file_xpm); + qfd_cleanup_pixmap.add( &fileIcon ); + closedFolderIcon = new QPixmap( (const char **)closed_xpm); + qfd_cleanup_pixmap.add( &closedFolderIcon ); + detailViewIcon = new QPixmap( (const char **)detailedview_xpm); + qfd_cleanup_pixmap.add( &detailViewIcon ); + multiColumnListViewIcon = new QPixmap( (const char **)mclistview_xpm); + qfd_cleanup_pixmap.add( &multiColumnListViewIcon ); + cdToParentIcon = new QPixmap( (const char **)cdtoparent_xpm); + qfd_cleanup_pixmap.add( &cdToParentIcon ); + newFolderIcon = new QPixmap( (const char **)newfolder_xpm); + qfd_cleanup_pixmap.add( &newFolderIcon ); + previewInfoViewIcon + = new QPixmap( (const char **)previewinfoview_xpm ); + qfd_cleanup_pixmap.add( &previewInfoViewIcon ); + previewContentsViewIcon + = new QPixmap( (const char **)previewcontentsview_xpm ); + qfd_cleanup_pixmap.add( &previewContentsViewIcon ); + startCopyIcon = new QPixmap( (const char **)start_xpm ); + qfd_cleanup_pixmap.add( &startCopyIcon ); + endCopyIcon = new QPixmap( (const char **)end_xpm ); + qfd_cleanup_pixmap.add( &endCopyIcon ); + goBackIcon = new QPixmap( (const char **)back_xpm ); + qfd_cleanup_pixmap.add( &goBackIcon ); + fifteenTransparentPixels = new QPixmap( closedFolderIcon->width(), 1 ); + qfd_cleanup_pixmap.add( &fifteenTransparentPixels ); + QBitmap m( fifteenTransparentPixels->width(), 1 ); + m.fill( Qt::color0 ); + fifteenTransparentPixels->setMask( m ); + bShowHiddenFiles = FALSE; + sortFilesBy = (int)QDir::Name; + detailViewMode = FALSE; +#if defined(Q_WS_WIN) + if ( !fileIconProvider ) + fileIconProvider = new QWindowsIconProvider( qApp ); +#endif + } +} + +/****************************************************************** + * + * Definitions of view classes + * + ******************************************************************/ + +class QRenameEdit : public QLineEdit +{ + Q_OBJECT + +public: + QRenameEdit( QWidget *parent ) + : QLineEdit( parent, "qt_rename_edit" ), doRenameAlreadyEmitted(FALSE) + { + connect( this, SIGNAL(returnPressed()), SLOT(slotReturnPressed()) ); + } + +protected: + void keyPressEvent( QKeyEvent *e ); + void focusOutEvent( QFocusEvent *e ); + +signals: + void cancelRename(); + void doRename(); + +private slots: + void slotReturnPressed(); + +private: + bool doRenameAlreadyEmitted; +}; + +class QFileListBox : public QListBox +{ + friend class QFileDialog; + + Q_OBJECT + +private: + QFileListBox( QWidget *parent, QFileDialog *d ); + + void clear(); + void show(); + void startRename( bool check = TRUE ); + void viewportMousePressEvent( QMouseEvent *e ); + void viewportMouseReleaseEvent( QMouseEvent *e ); + void viewportMouseDoubleClickEvent( QMouseEvent *e ); + void viewportMouseMoveEvent( QMouseEvent *e ); +#ifndef QT_NO_DRAGANDDROP + void viewportDragEnterEvent( QDragEnterEvent *e ); + void viewportDragMoveEvent( QDragMoveEvent *e ); + void viewportDragLeaveEvent( QDragLeaveEvent *e ); + void viewportDropEvent( QDropEvent *e ); + bool acceptDrop( const QPoint &pnt, QWidget *source ); + void setCurrentDropItem( const QPoint &pnt ); +#endif + void keyPressEvent( QKeyEvent *e ); + +private slots: + void rename(); + void cancelRename(); + void doubleClickTimeout(); + void changeDirDuringDrag(); + void dragObjDestroyed(); + void contentsMoved( int, int ); + +private: + QRenameEdit *lined; + QFileDialog *filedialog; + bool renaming; + QTimer* renameTimer; + QListBoxItem *renameItem, *dragItem; + QPoint pressPos, oldDragPos; + bool mousePressed; + int urls; + QString startDragDir; + QListBoxItem *currDropItem; + QTimer *changeDirTimer; + bool firstMousePressEvent; + QUrlOperator startDragUrl; + +}; + + +class QFileDialogQFileListView : public QListView +{ + Q_OBJECT + +public: + QFileDialogQFileListView( QWidget *parent, QFileDialog *d ); + + void clear(); + void startRename( bool check = TRUE ); + void setSorting( int column, bool increasing = TRUE ); + + QRenameEdit *lined; + bool renaming; + QListViewItem *renameItem; + +private: + void viewportMousePressEvent( QMouseEvent *e ); + void viewportMouseDoubleClickEvent( QMouseEvent *e ); + void keyPressEvent( QKeyEvent *e ); + void viewportMouseReleaseEvent( QMouseEvent *e ); + void viewportMouseMoveEvent( QMouseEvent *e ); +#ifndef QT_NO_DRAGANDDROP + void viewportDragEnterEvent( QDragEnterEvent *e ); + void viewportDragMoveEvent( QDragMoveEvent *e ); + void viewportDragLeaveEvent( QDragLeaveEvent *e ); + void viewportDropEvent( QDropEvent *e ); + bool acceptDrop( const QPoint &pnt, QWidget *source ); + void setCurrentDropItem( const QPoint &pnt ); +#endif + +private slots: + void rename(); + void cancelRename(); + void changeSortColumn2( int column ); + void doubleClickTimeout(); + void changeDirDuringDrag(); + void dragObjDestroyed(); + void contentsMoved( int, int ); + +private: + QFileDialog *filedialog; + QTimer* renameTimer; + QPoint pressPos, oldDragPos; + bool mousePressed; + int urls; + QString startDragDir; + QListViewItem *currDropItem, *dragItem; + QTimer *changeDirTimer; + bool firstMousePressEvent; + bool ascending; + int sortcolumn; + QUrlOperator startDragUrl; + +}; + +/**************************************************************************** + * + * Classes for copy progress dialog + * + ****************************************************************************/ + +class QFDProgressAnimation : public QWidget +{ + Q_OBJECT + +public: + QFDProgressAnimation( QWidget *parent ); + void start(); + +private slots: + void next(); + +protected: + void paintEvent( QPaintEvent *e ); + +private: + int step; + QTimer *timer; + +}; + +QFDProgressAnimation::QFDProgressAnimation( QWidget *parent ) + : QWidget( parent, "qt_progressanimation" ) +{ + setFixedSize( 300, 50 ); + step = -1; + next(); + timer = new QTimer( this ); + connect( timer, SIGNAL( timeout() ), + this, SLOT( next() ) ); +} + +void QFDProgressAnimation::start() +{ + timer->start( 150, FALSE ); +} + +void QFDProgressAnimation::next() +{ + ++step; + if ( step > 10 ) + step = 0; + repaint(); +} + +void QFDProgressAnimation::paintEvent( QPaintEvent * ) +{ + erase(); + + QPainter p; + p.begin( this ); + if ( step == 0 ) { + p.drawPixmap( 5, ( height() - startCopyIcon->height() ) / 2, + *startCopyIcon ); + p.drawPixmap( width() - 5 - openFolderIcon->width(), + ( height() - openFolderIcon->height() ) / 2 , *openFolderIcon ); + } else if ( step == 10 ) { + p.drawPixmap( 5, ( height() - openFolderIcon->height() ) / 2, + *openFolderIcon ); + p.drawPixmap( width() - 5 - endCopyIcon->width(), + ( height() - endCopyIcon->height() ) / 2 , *endCopyIcon ); + } else { + p.drawPixmap( 5, ( height() - openFolderIcon->height() ) / 2, + *openFolderIcon ); + p.drawPixmap( width() - 5 - openFolderIcon->width(), + ( height() - openFolderIcon->height() ) / 2 , *openFolderIcon ); + int x = 10 + openFolderIcon->width(); + int w = width() - 2 * x; + int s = w / 9; + p.drawPixmap( x + s * step, ( height() - fileIcon->height() ) / 2 - fileIcon->height(), + *fileIcon ); + } +} + + +class QFDProgressDialog : public QDialog +{ + Q_OBJECT + +public: + QFDProgressDialog( QWidget *parent, const QString &fn, int steps ); + + void setReadProgress( int p ); + void setWriteProgress( int p ); + void setWriteLabel( const QString &s ); + +signals: + void cancelled(); + +private: + QProgressBar *readBar; + QProgressBar *writeBar; + QLabel *writeLabel; + QFDProgressAnimation *animation; + +}; + +QFDProgressDialog::QFDProgressDialog( QWidget *parent, const QString &fn, int steps ) + : QDialog( parent, "", TRUE ) +{ +#ifndef QT_NO_WIDGET_TOPEXTRA + setCaption( QFileDialog::tr( "Copy or Move a File" ) ); +#endif + QVBoxLayout *layout = new QVBoxLayout( this ); + layout->setSpacing( 5 ); + layout->setMargin( 5 ); + + animation = new QFDProgressAnimation( this ); + layout->addWidget( animation ); + + layout->addWidget( new QLabel( QFileDialog::tr( "Read: %1" ).arg( fn ), + this, "qt_read_lbl" ) ); + readBar = new QProgressBar( steps, this, "qt_readbar" ); + readBar->reset(); + readBar->setProgress( 0 ); + layout->addWidget( readBar ); + writeLabel = new QLabel( QFileDialog::tr( "Write: %1" ).arg( QString::null ), + this, "qt_write_lbl" ); + layout->addWidget( writeLabel ); + writeBar = new QProgressBar( steps, this, "qt_writebar" ); + writeBar->reset(); + writeBar->setProgress( 0 ); + layout->addWidget( writeBar ); + + QPushButton *b = new QPushButton( QFileDialog::tr( "Cancel" ), this, + "qt_cancel_btn" ); + b->setFixedSize( b->sizeHint() ); + layout->addWidget( b ); + connect( b, SIGNAL( clicked() ), + this, SIGNAL( cancelled() ) ); + + animation->start(); +} + +void QFDProgressDialog::setReadProgress( int p ) +{ + readBar->setProgress( p ); +} + +void QFDProgressDialog::setWriteProgress( int p ) +{ + writeBar->setProgress( p ); +} + +void QFDProgressDialog::setWriteLabel( const QString &s ) +{ + writeLabel->setText( QFileDialog::tr( "Write: %1" ).arg( s ) ); +} + +/************************************************************************ + * + * Private QFileDialog members + * + ************************************************************************/ + +class QFileDialogPrivate { +public: + ~QFileDialogPrivate(); + + QStringList history; + + bool geometryDirty; + QComboBox * paths; + QComboBox * types; + QLabel * pathL; + QLabel * fileL; + QLabel * typeL; + + QVBoxLayout * topLevelLayout; + QHBoxLayout *buttonLayout, *leftLayout, *rightLayout; + QPtrList<QHBoxLayout> extraWidgetsLayouts; + QPtrList<QLabel> extraLabels; + QPtrList<QWidget> extraWidgets; + QPtrList<QWidget> extraButtons; + QPtrList<QButton> toolButtons; + + QWidgetStack * stack; + + QToolButton * cdToParent, *newFolder, * detailView, * mcView, + *previewInfo, *previewContents, *goBack; + QButtonGroup * modeButtons; + + QString currentFileName; + QListViewItem *last; + + QListBoxItem *lastEFSelected; + + struct File: public QListViewItem { + File( QFileDialogPrivate * dlgp, + const QUrlInfo * fi, QListViewItem * parent ) + : QListViewItem( parent, dlgp->last ), info( *fi ), d(dlgp), i( 0 ), hasMimePixmap( FALSE ) + { setup(); dlgp->last = this; } + File( QFileDialogPrivate * dlgp, + const QUrlInfo * fi, QListView * parent ) + : QListViewItem( parent, dlgp->last ), info( *fi ), d(dlgp), i( 0 ), hasMimePixmap( FALSE ) + { setup(); dlgp->last = this; } + File( QFileDialogPrivate * dlgp, + const QUrlInfo * fi, QListView * parent, QListViewItem * after ) + : QListViewItem( parent, after ), info( *fi ), d(dlgp), i( 0 ), hasMimePixmap( FALSE ) + { setup(); if ( !nextSibling() ) dlgp->last = this; } + ~File(); + + QString text( int column ) const; + const QPixmap * pixmap( int ) const; + + QUrlInfo info; + QFileDialogPrivate * d; + QListBoxItem *i; + bool hasMimePixmap; + }; + + class MCItem: public QListBoxItem { + public: + MCItem( QListBox *, QListViewItem * item ); + MCItem( QListBox *, QListViewItem * item, QListBoxItem *after ); + QString text() const; + const QPixmap *pixmap() const; + int height( const QListBox * ) const; + int width( const QListBox * ) const; + void paint( QPainter * ); + QListViewItem * i; + }; + + class UrlInfoList : public QPtrList<QUrlInfo> { + public: + UrlInfoList() { setAutoDelete( TRUE ); } + int compareItems( QPtrCollection::Item n1, QPtrCollection::Item n2 ) { + if ( !n1 || !n2 ) + return 0; + + QUrlInfo *i1 = ( QUrlInfo *)n1; + QUrlInfo *i2 = ( QUrlInfo *)n2; + + if ( i1->isDir() && !i2->isDir() ) + return -1; + if ( !i1->isDir() && i2->isDir() ) + return 1; + + if ( i1->name() == ".." ) + return -1; + if ( i2->name() == ".." ) + return 1; + + if ( sortFilesBy == QDir::Name ) { +#if defined(Q_OS_WIN32) + QString name1 = i1->name().lower(); + QString name2 = i2->name().lower(); + return name1.localeAwareCompare( name2 ); +#else + QString name1 = i1->name(); + QString name2 = i2->name(); + return name1.localeAwareCompare( name2 ); +#endif + } + if ( QUrlInfo::equal( *i1, *i2, sortFilesBy ) ) + return 0; + else if ( QUrlInfo::greaterThan( *i1, *i2, sortFilesBy ) ) + return 1; + else if ( QUrlInfo::lessThan( *i1, *i2, sortFilesBy ) ) + return -1; + // can't happen... + return 0; + } + QUrlInfo *operator[]( int i ) { + return at( i ); + } + }; + + UrlInfoList sortedList; + QPtrList<File> pendingItems; + + QFileListBox * moreFiles; + + QFileDialog::Mode mode; + + QString rw; + QString ro; + QString wo; + QString inaccessible; + + QString symLinkToFile; + QString file; + QString symLinkToDir; + QString dir; + QString symLinkToSpecial; + QString special; + QWidgetStack *preview; + bool infoPreview, contentsPreview; + QSplitter *splitter; + QUrlOperator url, oldUrl; + QWidget *infoPreviewWidget, *contentsPreviewWidget; + QFilePreview *infoPreviewer, *contentsPreviewer; + bool hadDotDot; + + bool ignoreNextKeyPress; + // ignores the next refresh operation in case the user forced a selection + bool ignoreNextRefresh; + QFDProgressDialog *progressDia; + bool checkForFilter; + bool ignoreStop; + + QTimer *mimeTypeTimer; + const QNetworkOperation *currListChildren; + + // this is similar to QUrl::encode but does encode "*" and + // doesn't encode whitespaces + static QString encodeFileName( const QString& fName ) { + + QString newStr; + QCString cName = fName.utf8(); + const QCString sChars( +#ifdef Q_WS_WIN + "#%" +#else + "<>#@\"&%$:,;?={}|^~[]\'`\\*" +#endif + ); + + int len = cName.length(); + if ( !len ) + return QString::null; + for ( int i = 0; i < len ;++i ) { + uchar inCh = (uchar)cName[ i ]; + if ( inCh >= 128 || sChars.contains(inCh) ) + { + newStr += QChar( '%' ); + ushort c = inCh / 16; + c += c > 9 ? 'A' - 10 : '0'; + newStr += (char)c; + c = inCh % 16; + c += c > 9 ? 'A' - 10 : '0'; + newStr += (char)c; + } else { + newStr += (char)inCh; + } + } + return newStr; + } + + static bool fileExists( const QUrlOperator &url, const QString& name ) + { + QUrl u( url, QFileDialogPrivate::encodeFileName(name) ); + if ( u.isLocalFile() ) { + QFileInfo f( u.path() ); + return f.exists(); + } else { + QNetworkProtocol *p = QNetworkProtocol::getNetworkProtocol( url.protocol() ); + if ( p && (p->supportedOperations()&QNetworkProtocol::OpListChildren) ) { + QUrlInfo ui( url, name ); + return ui.isValid(); + } + } + return TRUE; + } + +#ifndef Q_NO_CURSOR + bool cursorOverride; // Remember if the cursor was overridden or not. +#endif +#ifdef Q_WS_WIN + int oldPermissionLookup; +#endif +}; + +QFileDialogPrivate::~QFileDialogPrivate() +{ + delete modeButtons; +} + + + +/************************************************************************ + * + * Internal class QRenameEdit + * + ************************************************************************/ + +void QRenameEdit::keyPressEvent( QKeyEvent *e ) +{ + if ( e->key() == Key_Escape ) + emit cancelRename(); + else + QLineEdit::keyPressEvent( e ); + e->accept(); +} + +void QRenameEdit::focusOutEvent( QFocusEvent * ) +{ + if ( !doRenameAlreadyEmitted ) + emit doRename(); + else + doRenameAlreadyEmitted = FALSE; +} + +void QRenameEdit::slotReturnPressed() +{ + doRenameAlreadyEmitted = TRUE; + emit doRename(); +} + +/************************************************************************ + * + * Internal class QFileListBox + * + ************************************************************************/ + +QFileListBox::QFileListBox( QWidget *parent, QFileDialog *dlg ) + : QListBox( parent, "filelistbox" ), filedialog( dlg ), + renaming( FALSE ), renameItem( 0 ), mousePressed( FALSE ), + firstMousePressEvent( TRUE ) +{ + changeDirTimer = new QTimer( this ); + QVBox *box = new QVBox( viewport(), "qt_vbox" ); + box->setFrameStyle( QFrame::Box | QFrame::Plain ); + lined = new QRenameEdit( box ); + lined->setFixedHeight( lined->sizeHint().height() ); + box->hide(); + box->setBackgroundMode( PaletteBase ); + renameTimer = new QTimer( this ); + connect( lined, SIGNAL( doRename() ), + this, SLOT (rename() ) ); + connect( lined, SIGNAL( cancelRename() ), + this, SLOT( cancelRename() ) ); + connect( renameTimer, SIGNAL( timeout() ), + this, SLOT( doubleClickTimeout() ) ); + connect( changeDirTimer, SIGNAL( timeout() ), + this, SLOT( changeDirDuringDrag() ) ); + connect( this, SIGNAL( contentsMoving(int,int) ), + this, SLOT( contentsMoved(int,int) ) ); + viewport()->setAcceptDrops( TRUE ); + dragItem = 0; +} + +void QFileListBox::show() +{ + setBackgroundMode( PaletteBase ); + viewport()->setBackgroundMode( PaletteBase ); + QListBox::show(); +} + +void QFileListBox::keyPressEvent( QKeyEvent *e ) +{ + if ( ( e->key() == Key_Enter || + e->key() == Key_Return ) && + renaming ) + return; + + QString keyPressed = ((QKeyEvent *)e)->text().lower(); + QChar keyChar = keyPressed[0]; + bool handled = false; + if ( keyChar.isLetterOrNumber() ) { + QListBoxItem * i = 0; + if ( currentItem() ) + i = item( currentItem() ); + else + i = firstItem(); + if ( i->next() ) + i = i->next(); + else + i = firstItem(); + while ( i != item( currentItem() ) ) { + QString it = text( index( i ) ); + if ( it[0].lower() == keyChar ) { + clearSelection(); + setCurrentItem( i ); + handled = true; + e->accept(); + } else { + if ( i->next() ) + i = i->next(); + else + i = firstItem(); + } + } + } + cancelRename(); + if (!handled){ + QListBox::keyPressEvent( e ); + } +} + +void QFileListBox::viewportMousePressEvent( QMouseEvent *e ) +{ + pressPos = e->pos(); + mousePressed = FALSE; + + bool didRename = renaming; + + cancelRename(); + if ( !hasFocus() && !viewport()->hasFocus() ) + setFocus(); + + if ( e->button() != LeftButton ) { + QListBox::viewportMousePressEvent( e ); + firstMousePressEvent = FALSE; + return; + } + + int i = currentItem(); + bool wasSelected = FALSE; + if ( i != -1 ) + wasSelected = item( i )->isSelected(); + QListBox::mousePressEvent( e ); + + QFileDialogPrivate::MCItem *i1 = (QFileDialogPrivate::MCItem*)item( currentItem() ); + if ( i1 ) + mousePressed = ( !( (QFileDialogPrivate::File*)i1->i )->info.isDir() ) + || ( filedialog->mode() == QFileDialog::Directory ) || ( filedialog->mode() == QFileDialog::DirectoryOnly ); + + if ( itemAt( e->pos() ) != item( i ) ) { + firstMousePressEvent = FALSE; + return; + } + + if ( !firstMousePressEvent && !didRename && i == currentItem() && currentItem() != -1 && + wasSelected && QUrlInfo( filedialog->d->url, "." ).isWritable() && item( currentItem() )->text() != ".." ) { + renameTimer->start( QApplication::doubleClickInterval(), TRUE ); + renameItem = item( i ); + } + + firstMousePressEvent = FALSE; +} + +void QFileListBox::viewportMouseReleaseEvent( QMouseEvent *e ) +{ + dragItem = 0; + QListBox::viewportMouseReleaseEvent( e ); + mousePressed = FALSE; +} + +void QFileListBox::viewportMouseDoubleClickEvent( QMouseEvent *e ) +{ + renameTimer->stop(); + QListBox::viewportMouseDoubleClickEvent( e ); +} + +void QFileListBox::viewportMouseMoveEvent( QMouseEvent *e ) +{ + if ( !dragItem ) + dragItem = itemAt( e->pos() ); + renameTimer->stop(); +#ifndef QT_NO_DRAGANDDROP + if ( ( pressPos - e->pos() ).manhattanLength() > QApplication::startDragDistance() && mousePressed ) { + QListBoxItem *item = dragItem; + dragItem = 0; + if ( item ) { + if ( !itemRect( item ).contains( e->pos() ) ) + return; + QUriDrag* drag = new QUriDrag( viewport() ); + QStringList files; + if ( filedialog->mode() == QFileDialog::ExistingFiles ) + files = filedialog->selectedFiles(); + else + files = filedialog->selectedFile(); + drag->setFileNames( files ); + + if ( lined->parentWidget()->isVisible() ) + cancelRename(); + + connect( drag, SIGNAL( destroyed() ), + this, SLOT( dragObjDestroyed() ) ); + drag->drag(); + + mousePressed = FALSE; + } + } else +#endif + { + QListBox::viewportMouseMoveEvent( e ); + } + +} + +void QFileListBox::dragObjDestroyed() +{ +#ifndef QT_NO_DRAGANDDROP + //####### + //filedialog->rereadDir(); +#endif +} + +#ifndef QT_NO_DRAGANDDROP +void QFileListBox::viewportDragEnterEvent( QDragEnterEvent *e ) +{ + startDragUrl = filedialog->d->url; + startDragDir = filedialog->dirPath(); + currDropItem = 0; + + if ( !QUriDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + QStringList l; + QUriDrag::decodeLocalFiles( e, l ); + urls = (int)l.count(); + + if ( acceptDrop( e->pos(), e->source() ) ) { + e->accept(); + setCurrentDropItem( e->pos() ); + } else { + e->ignore(); + setCurrentDropItem( QPoint( -1, -1 ) ); + } + + oldDragPos = e->pos(); +} + +void QFileListBox::viewportDragMoveEvent( QDragMoveEvent *e ) +{ + if ( acceptDrop( e->pos(), e->source() ) ) { + switch ( e->action() ) { + case QDropEvent::Copy: + e->acceptAction(); + break; + case QDropEvent::Move: + e->acceptAction(); + break; + case QDropEvent::Link: + break; + default: + break; + } + if ( oldDragPos != e->pos() ) + setCurrentDropItem( e->pos() ); + } else { + changeDirTimer->stop(); + e->ignore(); + setCurrentDropItem( QPoint( -1, -1 ) ); + } + + oldDragPos = e->pos(); +} + +void QFileListBox::viewportDragLeaveEvent( QDragLeaveEvent * ) +{ + changeDirTimer->stop(); + setCurrentDropItem( QPoint( -1, -1 ) ); +//######## +// if ( startDragDir != filedialog->d->url ) +// filedialog->setUrl( startDragUrl ); +} + +void QFileListBox::viewportDropEvent( QDropEvent *e ) +{ + changeDirTimer->stop(); + + if ( !QUriDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + uint i; + QStrList l; + QUriDrag::decode( e, l ); + + bool move = e->action() == QDropEvent::Move; +// bool supportAction = move || e->action() == QDropEvent::Copy; + + QUrlOperator dest; + if ( currDropItem ) + dest = QUrlOperator( filedialog->d->url, QFileDialogPrivate::encodeFileName( currDropItem->text() ) ); + else + dest = filedialog->d->url; + QStringList lst; + for ( i = 0; i < l.count(); ++i ) { + lst << l.at( i ); + } + + // make sure that we can write to the destination before performing the action + bool exists = false; + QString name = (currDropItem ? QFileDialogPrivate::encodeFileName(currDropItem->text()) : QString(".")); + QUrlInfo info(filedialog->d->url, name); + for ( i = 0; i < lst.count(); ++i ) { + int slash = lst[i].findRev('/'); + QString filename = lst[i].right(lst[i].length() - slash - 1); + exists = exists || QFileDialogPrivate::fileExists( dest, filename); + } + if (info.isWritable() && !exists) + filedialog->d->url.copy( lst, dest, move ); + + // ##### what is supportAction for? + e->acceptAction(); + currDropItem = 0; +} + +bool QFileListBox::acceptDrop( const QPoint &pnt, QWidget *source ) +{ + QListBoxItem *item = itemAt( pnt ); + if ( !item || item && !itemRect( item ).contains( pnt ) ) { + if ( source == viewport() && startDragDir == filedialog->dirPath() ) + return FALSE; + return TRUE; + } + + QUrlInfo fi( filedialog->d->url, item->text() ); + + if ( fi.isDir() && itemRect( item ).contains( pnt ) ) + return TRUE; + return FALSE; +} + +void QFileListBox::setCurrentDropItem( const QPoint &pnt ) +{ + changeDirTimer->stop(); + + QListBoxItem *item = 0; + if ( pnt != QPoint( -1, -1 ) ) + item = itemAt( pnt ); + if ( item && !QUrlInfo( filedialog->d->url, item->text() ).isDir() ) + item = 0; + if ( item && !itemRect( item ).contains( pnt ) ) + item = 0; + + currDropItem = item; + if ( currDropItem ) + setCurrentItem( currDropItem ); + changeDirTimer->start( 750 ); +} +#endif // QT_NO_DRAGANDDROP + +void QFileListBox::changeDirDuringDrag() +{ +#ifndef QT_NO_DRAGANDDROP + if ( !currDropItem ) + return; + changeDirTimer->stop(); + QUrl u( filedialog->d->url, QFileDialogPrivate::encodeFileName(currDropItem->text()) ); + filedialog->setDir( u ); + currDropItem = 0; +#endif +} + +void QFileListBox::doubleClickTimeout() +{ + startRename(); + renameTimer->stop(); +} + +void QFileListBox::startRename( bool check ) +{ + if ( check && ( !renameItem || renameItem != item( currentItem() ) ) ) + return; + + int i = currentItem(); + setSelected( i, TRUE ); + QRect r = itemRect( item( i ) ); + int bdr = item( i )->pixmap() ? + item( i )->pixmap()->width() : 16; + int x = r.x() + bdr; + int y = r.y(); + int w = item( i )->width( this ) - bdr; + int h = QMAX( lined->height() + 2, r.height() ); + y = y + r.height() / 2 - h / 2; + + lined->parentWidget()->setGeometry( x, y, w + 6, h ); + lined->setFocus(); + lined->setText( item( i )->text() ); + lined->selectAll(); + lined->setFrame( FALSE ); + lined->parentWidget()->show(); + viewport()->setFocusProxy( lined ); + renaming = TRUE; +} + +void QFileListBox::clear() +{ + cancelRename(); + QListBox::clear(); +} + +void QFileListBox::rename() +{ + if ( !lined->text().isEmpty() ) { + QString file = currentText(); + + if ( lined->text() != file ) + filedialog->d->url.rename( file, lined->text() ); + } + cancelRename(); +} + +void QFileListBox::cancelRename() +{ + renameItem = 0; + lined->parentWidget()->hide(); + viewport()->setFocusProxy( this ); + renaming = FALSE; + updateItem( currentItem() ); + if ( lined->hasFocus() ) + viewport()->setFocus(); +} + +void QFileListBox::contentsMoved( int, int ) +{ + changeDirTimer->stop(); +#ifndef QT_NO_DRAGANDDROP + setCurrentDropItem( QPoint( -1, -1 ) ); +#endif +} + +/************************************************************************ + * + * Internal class QFileListView + * + ************************************************************************/ + +QFileDialogQFileListView::QFileDialogQFileListView( QWidget *parent, QFileDialog *dlg ) + : QListView( parent, "qt_filedlg_listview" ), renaming( FALSE ), renameItem( 0 ), + filedialog( dlg ), mousePressed( FALSE ), + firstMousePressEvent( TRUE ) +{ + changeDirTimer = new QTimer( this ); + QVBox *box = new QVBox( viewport(), "qt_vbox" ); + box->setFrameStyle( QFrame::Box | QFrame::Plain ); + lined = new QRenameEdit( box ); + lined->setFixedHeight( lined->sizeHint().height() ); + box->hide(); + box->setBackgroundMode( PaletteBase ); + renameTimer = new QTimer( this ); + connect( lined, SIGNAL( doRename() ), + this, SLOT (rename() ) ); + connect( lined, SIGNAL( cancelRename() ), + this, SLOT( cancelRename() ) ); + header()->setMovingEnabled( FALSE ); + connect( renameTimer, SIGNAL( timeout() ), + this, SLOT( doubleClickTimeout() ) ); + connect( changeDirTimer, SIGNAL( timeout() ), + this, SLOT( changeDirDuringDrag() ) ); + disconnect( header(), SIGNAL( sectionClicked(int) ), + this, SLOT( changeSortColumn(int) ) ); + connect( header(), SIGNAL( sectionClicked(int) ), + this, SLOT( changeSortColumn2(int) ) ); + connect( this, SIGNAL( contentsMoving(int,int) ), + this, SLOT( contentsMoved(int,int) ) ); + + viewport()->setAcceptDrops( TRUE ); + sortcolumn = 0; + ascending = TRUE; + dragItem = 0; +} + +void QFileDialogQFileListView::setSorting( int column, bool increasing ) +{ + if ( column == -1 ) { + QListView::setSorting( column, increasing ); + return; + } + + sortAscending = ascending = increasing; + sortcolumn = column; + switch ( column ) { + case 0: + sortFilesBy = QDir::Name; + break; + case 1: + sortFilesBy = QDir::Size; + break; + case 3: + sortFilesBy = QDir::Time; + break; + default: + sortFilesBy = QDir::Name; // #### ??? + break; + } + + filedialog->resortDir(); +} + +void QFileDialogQFileListView::changeSortColumn2( int column ) +{ + int lcol = header()->mapToLogical( column ); + setSorting( lcol, sortcolumn == lcol ? !ascending : TRUE ); +} + +void QFileDialogQFileListView::keyPressEvent( QKeyEvent *e ) +{ + if ( ( e->key() == Key_Enter || + e->key() == Key_Return ) && + renaming ) + return; + + QString keyPressed = e->text().lower(); + QChar keyChar = keyPressed[0]; + if ( keyChar.isLetterOrNumber() ) { + QListViewItem * i = 0; + if ( currentItem() ) + i = currentItem(); + else + i = firstChild(); + if ( i->nextSibling() ) + i = i->nextSibling(); + else + i = firstChild(); + while ( i != currentItem() ) { + QString it = i->text(0); + if ( it[0].lower() == keyChar ) { + clearSelection(); + ensureItemVisible( i ); + setCurrentItem( i ); + } else { + if ( i->nextSibling() ) + i = i->nextSibling(); + else + i = firstChild(); + } + } + return; + } + + cancelRename(); + QListView::keyPressEvent( e ); +} + +void QFileDialogQFileListView::viewportMousePressEvent( QMouseEvent *e ) +{ + pressPos = e->pos(); + mousePressed = FALSE; + + bool didRename = renaming; + cancelRename(); + if ( !hasFocus() && !viewport()->hasFocus() ) + setFocus(); + + if ( e->button() != LeftButton ) { + QListView::viewportMousePressEvent( e ); + firstMousePressEvent = FALSE; + return; + } + + QListViewItem *i = currentItem(); + QListView::viewportMousePressEvent( e ); + + QFileDialogPrivate::File *i1 = (QFileDialogPrivate::File*)currentItem(); + if ( i1 ) + mousePressed = !i1->info.isDir() || ( filedialog->mode() == QFileDialog::Directory ) || ( filedialog->mode() == QFileDialog::DirectoryOnly ); + + + if ( itemAt( e->pos() ) != i || + e->x() + contentsX() > columnWidth( 0 ) ) { + firstMousePressEvent = FALSE; + return; + } + + if ( !firstMousePressEvent && !didRename && i == currentItem() && currentItem() && + QUrlInfo( filedialog->d->url, "." ).isWritable() && currentItem()->text( 0 ) != ".." ) { + renameTimer->start( QApplication::doubleClickInterval(), TRUE ); + renameItem = currentItem(); + } + + firstMousePressEvent = FALSE; +} + +void QFileDialogQFileListView::viewportMouseDoubleClickEvent( QMouseEvent *e ) +{ + renameTimer->stop(); + QListView::viewportMouseDoubleClickEvent( e ); +} + +void QFileDialogQFileListView::viewportMouseReleaseEvent( QMouseEvent *e ) +{ + QListView::viewportMouseReleaseEvent( e ); + mousePressed = FALSE; + dragItem = 0; +} + +void QFileDialogQFileListView::viewportMouseMoveEvent( QMouseEvent *e ) +{ + renameTimer->stop(); + if ( !dragItem ) + dragItem = itemAt( e->pos() ); +#ifndef QT_NO_DRAGANDDROP + if ( ( pressPos - e->pos() ).manhattanLength() > QApplication::startDragDistance() && mousePressed ) { + QListViewItem *item = dragItem; + dragItem = 0; + if ( item ) { + QUriDrag* drag = new QUriDrag( viewport() ); + QStringList files; + if ( filedialog->mode() == QFileDialog::ExistingFiles ) + files = filedialog->selectedFiles(); + else + files = filedialog->selectedFile(); + drag->setFileNames( files ); + + if ( lined->isVisible() ) + cancelRename(); + + connect( drag, SIGNAL( destroyed() ), + this, SLOT( dragObjDestroyed() ) ); + drag->drag(); + + mousePressed = FALSE; + } + } +#endif +} + +void QFileDialogQFileListView::dragObjDestroyed() +{ +#ifndef QT_NO_DRAGANDDROP + //###### + //filedialog->rereadDir(); +#endif +} + +#ifndef QT_NO_DRAGANDDROP +void QFileDialogQFileListView::viewportDragEnterEvent( QDragEnterEvent *e ) +{ + startDragUrl = filedialog->d->url; + startDragDir = filedialog->dirPath(); + currDropItem = 0; + + if ( !QUriDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + QStringList l; + QUriDrag::decodeLocalFiles( e, l ); + urls = (int)l.count(); + + if ( acceptDrop( e->pos(), e->source() ) ) { + e->accept(); + setCurrentDropItem( e->pos() ); + } else { + e->ignore(); + setCurrentDropItem( QPoint( -1, -1 ) ); + } + + oldDragPos = e->pos(); +} + +void QFileDialogQFileListView::viewportDragMoveEvent( QDragMoveEvent *e ) +{ + if ( acceptDrop( e->pos(), e->source() ) ) { + if ( oldDragPos != e->pos() ) + setCurrentDropItem( e->pos() ); + switch ( e->action() ) { + case QDropEvent::Copy: + e->acceptAction(); + break; + case QDropEvent::Move: + e->acceptAction(); + break; + case QDropEvent::Link: + break; + default: + break; + } + } else { + changeDirTimer->stop(); + e->ignore(); + setCurrentDropItem( QPoint( -1, -1 ) ); + } + + oldDragPos = e->pos(); +} + +void QFileDialogQFileListView::viewportDragLeaveEvent( QDragLeaveEvent * ) +{ + changeDirTimer->stop(); + setCurrentDropItem( QPoint( -1, -1 ) ); +//######## +// if ( startDragDir != filedialog->d->url ) +// filedialog->setUrl( startDragUrl ); +} + +void QFileDialogQFileListView::viewportDropEvent( QDropEvent *e ) +{ + changeDirTimer->stop(); + + if ( !QUriDrag::canDecode( e ) ) { + e->ignore(); + return; + } + + QStringList l; + QUriDrag::decodeToUnicodeUris( e, l ); + + bool move = e->action() == QDropEvent::Move; +// bool supportAction = move || e->action() == QDropEvent::Copy; + + QUrlOperator dest; + if ( currDropItem ) + dest = QUrlOperator( filedialog->d->url, QFileDialogPrivate::encodeFileName( currDropItem->text( 0 ) ) ); + else + dest = filedialog->d->url; + + // make sure that we can write to the destination before performing the action + bool exists = false; + QString name = (currDropItem ? QFileDialogPrivate::encodeFileName(currDropItem->text(0)) : QString(".")); + QUrlInfo info(filedialog->d->url, name); + for (uint i = 0; i < l.count(); ++i) { + int slash = l[i].findRev('/'); + QString filename = l[i].right(l[i].length() - slash - 1); + exists = exists || QFileDialogPrivate::fileExists(dest, filename); + } + if (info.isWritable() && !exists) + filedialog->d->url.copy( l, dest, move ); + + // ##### what is supportAction for? + e->acceptAction(); + currDropItem = 0; +} + +bool QFileDialogQFileListView::acceptDrop( const QPoint &pnt, QWidget *source ) +{ + QListViewItem *item = itemAt( pnt ); + if ( !item || item && !itemRect( item ).contains( pnt ) ) { + if ( source == viewport() && startDragDir == filedialog->dirPath() ) + return FALSE; + return TRUE; + } + + QUrlInfo fi( filedialog->d->url, item->text( 0 ) ); + + if ( fi.isDir() && itemRect( item ).contains( pnt ) ) + return TRUE; + return FALSE; +} + +void QFileDialogQFileListView::setCurrentDropItem( const QPoint &pnt ) +{ + changeDirTimer->stop(); + + QListViewItem *item = itemAt( pnt ); + if ( pnt == QPoint( -1, -1 ) ) + item = 0; + if ( item && !QUrlInfo( filedialog->d->url, item->text( 0 ) ).isDir() ) + item = 0; + + if ( item && !itemRect( item ).contains( pnt ) ) + item = 0; + + currDropItem = item; + + if ( currDropItem ) + setCurrentItem( currDropItem ); + + changeDirTimer->start( 750 ); +} +#endif // QT_NO_DRAGANDDROP + +void QFileDialogQFileListView::changeDirDuringDrag() +{ +#ifndef QT_NO_DRAGANDDROP + if ( !currDropItem ) + return; + changeDirTimer->stop(); + QUrl u( filedialog->d->url, QFileDialogPrivate::encodeFileName(currDropItem->text( 0 ) ) ); + filedialog->setDir( u ); + currDropItem = 0; +#endif // QT_NO_DRAGANDDROP +} + + +void QFileDialogQFileListView::doubleClickTimeout() +{ + startRename(); + renameTimer->stop(); +} + +void QFileDialogQFileListView::startRename( bool check ) +{ + if ( check && ( !renameItem || renameItem != currentItem() ) ) + return; + + QListViewItem *i = currentItem(); + setSelected( i, TRUE ); + + QRect r = itemRect( i ); + int bdr = i->pixmap( 0 ) ? + i->pixmap( 0 )->width() : 16; + int x = r.x() + bdr; + int y = r.y(); + int w = columnWidth( 0 ) - bdr; + int h = QMAX( lined->height() + 2, r.height() ); + y = y + r.height() / 2 - h / 2; + + lined->parentWidget()->setGeometry( x, y, w + 6, h ); + lined->setFocus(); + lined->setText( i->text( 0 ) ); + lined->selectAll(); + lined->setFrame( FALSE ); + lined->parentWidget()->show(); + viewport()->setFocusProxy( lined ); + renaming = TRUE; +} + +void QFileDialogQFileListView::clear() +{ + cancelRename(); + QListView::clear(); +} + +void QFileDialogQFileListView::rename() +{ + if ( !lined->text().isEmpty() ) { + QString file = currentItem()->text( 0 ); + + if ( lined->text() != file ) + filedialog->d->url.rename( file, lined->text() ); + } + cancelRename(); +} + +void QFileDialogQFileListView::cancelRename() +{ + renameItem = 0; + lined->parentWidget()->hide(); + viewport()->setFocusProxy( this ); + renaming = FALSE; + if ( currentItem() ) + currentItem()->repaint(); + if ( lined->hasFocus() ) + viewport()->setFocus(); +} + +void QFileDialogQFileListView::contentsMoved( int, int ) +{ + changeDirTimer->stop(); +#ifndef QT_NO_DRAGANDDROP + setCurrentDropItem( QPoint( -1, -1 ) ); +#endif +} + + +QFileDialogPrivate::File::~File() +{ + if ( d->pendingItems.findRef( this ) ) + d->pendingItems.removeRef( this ); +} + +QString QFileDialogPrivate::File::text( int column ) const +{ + makeVariables(); + + switch( column ) { + case 0: + return info.name(); + case 1: + if ( info.isFile() ) { +#if (QT_VERSION-0 >= 0x040000) +#error "clean up Large File Support" +#elif defined(QT_ABI_QT4) + QIODevice::Offset size = info.size(); +#else + uint size = info.size(); +#endif +#if defined(QT_LARGEFILE_SUPPORT) && defined(Q_OS_UNIX) + // ### the following code should not be needed as soon + // ### as QUrlInfo::size() can return 64-bit + if ( size > INT_MAX ) { + struct stat buffer; + if ( ::stat( QFile::encodeName(info.name()), &buffer ) == 0 ) { + Q_ULLONG size64 = (Q_ULLONG)buffer.st_size; + return QString::number(size64); + } + } +#endif + return QString::number(size); + } else { + return QString::fromLatin1(""); + } + case 2: + if ( info.isFile() && info.isSymLink() ) { + return d->symLinkToFile; + } else if ( info.isFile() ) { + return d->file; + } else if ( info.isDir() && info.isSymLink() ) { + return d->symLinkToDir; + } else if ( info.isDir() ) { + return d->dir; + } else if ( info.isSymLink() ) { + return d->symLinkToSpecial; + } else { + return d->special; + } + case 3: { + return info.lastModified().toString( Qt::LocalDate ); + } + case 4: + if ( info.isReadable() ) + return info.isWritable() ? d->rw : d->ro; + else + return info.isWritable() ? d->wo : d->inaccessible; + } + + return QString::fromLatin1("<--->"); +} + +const QPixmap * QFileDialogPrivate::File::pixmap( int column ) const +{ + if ( column ) { + return 0; + } else if ( QListViewItem::pixmap( column ) ) { + return QListViewItem::pixmap( column ); + } else if ( info.isSymLink() ) { + if ( info.isFile() ) + return symLinkFileIcon; + else + return symLinkDirIcon; + } else if ( info.isDir() ) { + return closedFolderIcon; + } else if ( info.isFile() ) { + return fileIcon; + } else { + return fifteenTransparentPixels; + } +} + +QFileDialogPrivate::MCItem::MCItem( QListBox * lb, QListViewItem * item ) + : QListBoxItem() +{ + i = item; + if ( lb ) + lb->insertItem( this ); +} + +QFileDialogPrivate::MCItem::MCItem( QListBox * lb, QListViewItem * item, QListBoxItem *after ) + : QListBoxItem() +{ + i = item; + if ( lb ) + lb->insertItem( this, after ); +} + +QString QFileDialogPrivate::MCItem::text() const +{ + return i->text( 0 ); +} + + +const QPixmap *QFileDialogPrivate::MCItem::pixmap() const +{ + return i->pixmap( 0 ); +} + + +int QFileDialogPrivate::MCItem::height( const QListBox * lb ) const +{ + int hf = lb->fontMetrics().height(); + int hp = pixmap() ? pixmap()->height() : 0; + return QMAX(hf, hp) + 2; +} + + +int QFileDialogPrivate::MCItem::width( const QListBox * lb ) const +{ + QFontMetrics fm = lb->fontMetrics(); + int w = 2; + if ( pixmap() ) + w += pixmap()->width() + 4; + else + w += 18; + w += fm.width( text() ); + w += -fm.minLeftBearing(); + w += -fm.minRightBearing(); + w += 6; + return w; +} + + +void QFileDialogPrivate::MCItem::paint( QPainter * ptr ) +{ + QFontMetrics fm = ptr->fontMetrics(); + + int h; + + if ( pixmap() ) + h = QMAX( fm.height(), pixmap()->height()) + 2; + else + h = fm.height() + 2; + + const QPixmap * pm = pixmap(); + if ( pm ) + ptr->drawPixmap( 2, 1, *pm ); + + ptr->drawText( pm ? pm->width() + 4 : 22, h - fm.descent() - 2, + text() ); +} + +static QStringList makeFiltersList( const QString &filter ) +{ + if ( filter.isEmpty() ) + return QStringList(); + + int i = filter.find( ";;", 0 ); + QString sep( ";;" ); + if ( i == -1 ) { + if ( filter.find( "\n", 0 ) != -1 ) { + sep = "\n"; + i = filter.find( sep, 0 ); + } + } + + return QStringList::split( sep, filter ); +} + +/*! + \class QFileDialog qfiledialog.h + \brief The QFileDialog class provides dialogs that allow users to select files or directories. + \ingroup dialogs + \mainclass + + The QFileDialog class enables a user to traverse their file system in + order to select one or many files or a directory. + + The easiest way to create a QFileDialog is to use the static + functions. On Windows, these static functions will call the native + Windows file dialog and on Mac OS X, these static function will call + the native Mac OS X file dialog. + + \code + QString s = QFileDialog::getOpenFileName( + "/home", + "Images (*.png *.xpm *.jpg)", + this, + "open file dialog", + "Choose a file" ); + \endcode + + In the above example, a modal QFileDialog is created using a static + function. The startup directory is set to "/home". The file filter + is set to "Images (*.png *.xpm *.jpg)". The parent of the file dialog + is set to \e this and it is given the identification name - "open file + dialog". The caption at the top of file dialog is set to "Choose a + file". If you want to use multiple filters, separate each one with + \e two semi-colons, e.g. + \code + "Images (*.png *.xpm *.jpg);;Text files (*.txt);;XML files (*.xml)" + \endcode + + You can create your own QFileDialog without using the static + functions. By calling setMode(), you can set what can be returned by + the QFileDialog. + + \code + QFileDialog* fd = new QFileDialog( this, "file dialog", TRUE ); + fd->setMode( QFileDialog::AnyFile ); + \endcode + + In the above example, the mode of the file dialog is set to \c + AnyFile, meaning that the user can select any file, or even specify a + file that doesn't exist. This mode is useful for creating a "File Save + As" file dialog. Use \c ExistingFile if the user must select an + existing file or \c Directory if only a directory may be selected. + (See the \l QFileDialog::Mode enum for the complete list of modes.) + + You can retrieve the dialog's mode with mode(). Use setFilter() to set + the dialog's file filter, e.g. + + \code + fd->setFilter( "Images (*.png *.xpm *.jpg)" ); + \endcode + + In the above example, the filter is set to "Images (*.png *.xpm + *.jpg)", this means that only files with the extension \c png, \c xpm + or \c jpg will be shown in the QFileDialog. You can apply + several filters by using setFilters() and add additional filters with + addFilter(). Use setSelectedFilter() to select one of the filters + you've given as the file dialog's default filter. Whenever the user + changes the filter the filterSelected() signal is emitted. + + The file dialog has two view modes, QFileDialog::List which simply + lists file and directory names and QFileDialog::Detail which + displays additional information alongside each name, e.g. file size, + modification date, etc. Set the mode with setViewMode(). + + \code + fd->setViewMode( QFileDialog::Detail ); + \endcode + + The last important function you will need to use when creating your + own file dialog is selectedFile(). + + \code + QString fileName; + if ( fd->exec() == QDialog::Accepted ) + fileName = fd->selectedFile(); + \endcode + + In the above example, a modal file dialog is created and shown. If + the user clicked OK, then the file they selected is put in \c + fileName. + + If you are using the \c ExistingFiles mode then you will need to use + selectedFiles() which will return the selected files in a QStringList. + + The dialog's working directory can be set with setDir(). The display + of hidden files is controlled with setShowHiddenFiles(). The dialog + can be forced to re-read the directory with rereadDir() and re-sort + the directory with resortDir(). All the files in the current directory + can be selected with selectAll(). + + \section1 Creating and using preview widgets + + There are two kinds of preview widgets that can be used with + QFileDialogs: \e content preview widgets and \e information preview + widgets. They are created and used in the same way except that the + function names differ, e.g. setContentsPreview() and setInfoPreview(). + + A preview widget is a widget that is placed inside a QFileDialog so + that the user can see either the contents of the file, or information + about the file. + + \code + class Preview : public QLabel, public QFilePreview + { + public: + Preview( QWidget *parent=0 ) : QLabel( parent ) {} + + void previewUrl( const QUrl &u ) + { + QString path = u.path(); + QPixmap pix( path ); + if ( pix.isNull() ) + setText( "This is not a pixmap" ); + else + setPixmap( pix ); + } + }; + \endcode + + In the above snippet, we create a preview widget which inherits from + QLabel and QFilePreview. File preview widgets \e must inherit from + QFilePreview. + + Inside the class we reimplement QFilePreview::previewUrl(), this is + where we determine what happens when a file is selected. In the + above example we only show a preview of the file if it is a valid + pixmap. Here's how to make a file dialog use a preview widget: + + \code + Preview* p = new Preview; + + QFileDialog* fd = new QFileDialog( this ); + fd->setContentsPreviewEnabled( TRUE ); + fd->setContentsPreview( p, p ); + fd->setPreviewMode( QFileDialog::Contents ); + fd->show(); + \endcode + + The first line creates an instance of our preview widget. We then + create our file dialog and call setContentsPreviewEnabled( TRUE ), + this tell the file dialog to preview the contents of the currently + selected file. We then call setContentsPreview() -- note that we pass + the same preview widget twice. Finally, before showing the file + dialog, we call setPreviewMode() setting the mode to \e Contents which + will show the contents preview of the file that the user has selected. + + If you create another preview widget that is used for displaying + information about a file, create it in the same way as the contents + preview widget and call setInfoPreviewEnabled(), and + setInfoPreview(). Then the user will be able to switch between the + two preview modes. + + For more information about creating a QFilePreview widget see + \l{QFilePreview}. + + <img src=qfiledlg-m.png> <img src=qfiledlg-w.png> + +*/ + + +/*! \enum QFileDialog::Mode + + This enum is used to indicate what the user may select in the file + dialog, i.e. what the dialog will return if the user clicks OK. + + \value AnyFile The name of a file, whether it exists or not. + \value ExistingFile The name of a single existing file. + \value Directory The name of a directory. Both files and directories + are displayed. + \value DirectoryOnly The name of a directory. The file dialog will only display directories. + \value ExistingFiles The names of zero or more existing files. + + See setMode(). +*/ + +/*! + \enum QFileDialog::ViewMode + + This enum describes the view mode of the file dialog, i.e. what + information about each file will be displayed. + + \value List Display file and directory names with icons. + \value Detail Display file and directory names with icons plus + additional information, such as file size and modification date. + + See setViewMode(). +*/ + +/*! + \enum QFileDialog::PreviewMode + + This enum describes the preview mode of the file dialog. + + \value NoPreview No preview is shown at all. + \value Contents Show a preview of the contents of the current file + using the contents preview widget. + \value Info Show information about the current file using the + info preview widget. + + See setPreviewMode(), setContentsPreview() and setInfoPreview(). +*/ + +/*! + \fn void QFileDialog::detailViewSelectionChanged() + \internal +*/ + +/*! + \fn void QFileDialog::listBoxSelectionChanged() + \internal +*/ + +extern const char qt_file_dialog_filter_reg_exp[] = + "([a-zA-Z0-9 ]*)\\(([a-zA-Z0-9_.*? +;#\\[\\]]*)\\)$"; + +/*! + Constructs a file dialog called \a name, with the parent, \a parent. + If \a modal is TRUE then the file dialog is modal; otherwise it is + modeless. +*/ + +QFileDialog::QFileDialog( QWidget *parent, const char *name, bool modal ) + : QDialog( parent, name, modal, + (modal ? + (WStyle_Customize | WStyle_DialogBorder | WStyle_Title | WStyle_SysMenu) : 0) ) +{ + init(); + d->mode = ExistingFile; + d->types->insertItem( tr( "All Files (*)" ) ); + d->cursorOverride = FALSE; + emit dirEntered( d->url.dirPath() ); + rereadDir(); +} + + +/*! + Constructs a file dialog called \a name with the parent, \a parent. + If \a modal is TRUE then the file dialog is modal; otherwise it is + modeless. + + If \a dirName is specified then it will be used as the dialog's + working directory, i.e. it will be the directory that is shown when + the dialog appears. If \a filter is specified it will be used as the + dialog's file filter. + +*/ + +QFileDialog::QFileDialog( const QString& dirName, const QString & filter, + QWidget *parent, const char *name, bool modal ) + : QDialog( parent, name, modal, + (modal ? + (WStyle_Customize | WStyle_DialogBorder | WStyle_Title | WStyle_SysMenu) : 0) ) +{ + init(); + d->mode = ExistingFile; + rereadDir(); + QUrlOperator u( dirName ); + if ( !dirName.isEmpty() && ( !u.isLocalFile() || QDir( dirName ).exists() ) ) + setSelection( dirName ); + else if ( workingDirectory && !workingDirectory->isEmpty() ) + setDir( *workingDirectory ); + + if ( !filter.isEmpty() ) { + setFilters( filter ); + if ( !dirName.isEmpty() ) { + int dotpos = dirName.find( QChar('.'), 0, FALSE ); + if ( dotpos != -1 ) { + for ( int b=0 ; b<d->types->count() ; b++ ) { + if ( d->types->text(b).contains( dirName.right( dirName.length() - dotpos ) ) ) { + d->types->setCurrentItem( b ); + setFilter( d->types->text( b ) ); + return; + } + } + } + } + } else { + d->types->insertItem( tr( "All Files (*)" ) ); + } +} + + +#if defined(Q_WS_WIN) +extern int qt_ntfs_permission_lookup; +#endif + +/*! + \internal + Initializes the file dialog. +*/ + +void QFileDialog::init() +{ + setSizeGripEnabled( TRUE ); + d = new QFileDialogPrivate(); + d->mode = AnyFile; + d->last = 0; + d->lastEFSelected = 0; + d->moreFiles = 0; + d->infoPreview = FALSE; + d->contentsPreview = FALSE; + d->hadDotDot = FALSE; + d->ignoreNextKeyPress = FALSE; + d->progressDia = 0; + d->checkForFilter = FALSE; + d->ignoreNextRefresh = FALSE; + d->ignoreStop = FALSE; + d->pendingItems.setAutoDelete( FALSE ); + d->mimeTypeTimer = new QTimer( this ); + d->cursorOverride = FALSE; +#if defined(Q_WS_WIN) + d->oldPermissionLookup = qt_ntfs_permission_lookup; +#endif + connect( d->mimeTypeTimer, SIGNAL( timeout() ), + this, SLOT( doMimeTypeLookup() ) ); + + d->url = QUrlOperator( ::toRootIfNotExists( QDir::currentDirPath() ) ); + d->oldUrl = d->url; + d->currListChildren = 0; + + connect( &d->url, SIGNAL( start(QNetworkOperation*) ), + this, SLOT( urlStart(QNetworkOperation*) ) ); + connect( &d->url, SIGNAL( finished(QNetworkOperation*) ), + this, SLOT( urlFinished(QNetworkOperation*) ) ); + connect( &d->url, SIGNAL( newChildren(const QValueList<QUrlInfo>&,QNetworkOperation*) ), + this, SLOT( insertEntry(const QValueList<QUrlInfo>&,QNetworkOperation*) ) ); + connect( &d->url, SIGNAL( removed(QNetworkOperation*) ), + this, SLOT( removeEntry(QNetworkOperation*) ) ); + connect( &d->url, SIGNAL( createdDirectory(const QUrlInfo&,QNetworkOperation*) ), + this, SLOT( createdDirectory(const QUrlInfo&,QNetworkOperation*) ) ); + connect( &d->url, SIGNAL( itemChanged(QNetworkOperation*) ), + this, SLOT( itemChanged(QNetworkOperation*) ) ); + connect( &d->url, SIGNAL( dataTransferProgress(int,int,QNetworkOperation*) ), + this, SLOT( dataTransferProgress(int,int,QNetworkOperation*) ) ); + + nameEdit = new QLineEdit( this, "name/filter editor" ); + nameEdit->setMaxLength( 255 ); //_POSIX_MAX_PATH + connect( nameEdit, SIGNAL(textChanged(const QString&)), + this, SLOT(fileNameEditDone()) ); + nameEdit->installEventFilter( this ); + + d->splitter = new QSplitter( this, "qt_splitter" ); + + d->stack = new QWidgetStack( d->splitter, "files and more files" ); + + d->splitter->setSizePolicy( QSizePolicy( QSizePolicy::Expanding, QSizePolicy::Expanding ) ); + + files = new QFileDialogQFileListView( d->stack, this ); + QFontMetrics fm = fontMetrics(); + files->addColumn( tr("Name") ); + files->addColumn( tr("Size") ); + files->setColumnAlignment( 1, AlignRight ); + files->addColumn( tr("Type") ); + files->addColumn( tr("Date") ); + files->addColumn( tr("Attributes") ); + files->header()->setStretchEnabled( TRUE, 0 ); + + files->setMinimumSize( 50, 25 + 2*fm.lineSpacing() ); + + connect( files, SIGNAL( selectionChanged() ), + this, SLOT( detailViewSelectionChanged() ) ); + connect( files, SIGNAL(currentChanged(QListViewItem*)), + this, SLOT(updateFileNameEdit(QListViewItem*)) ); + connect( files, SIGNAL(doubleClicked(QListViewItem*)), + this, SLOT(selectDirectoryOrFile(QListViewItem*)) ); + connect( files, SIGNAL(returnPressed(QListViewItem*)), + this, SLOT(selectDirectoryOrFile(QListViewItem*)) ); + connect( files, SIGNAL(rightButtonPressed(QListViewItem*,const QPoint&,int)), + this, SLOT(popupContextMenu(QListViewItem*,const QPoint&,int)) ); + + files->installEventFilter( this ); + files->viewport()->installEventFilter( this ); + + d->moreFiles = new QFileListBox( d->stack, this ); + d->moreFiles->setRowMode( QListBox::FitToHeight ); + d->moreFiles->setVariableWidth( TRUE ); + + connect( d->moreFiles, SIGNAL(selected(QListBoxItem*)), + this, SLOT(selectDirectoryOrFile(QListBoxItem*)) ); + connect( d->moreFiles, SIGNAL( selectionChanged() ), + this, SLOT( listBoxSelectionChanged() ) ); + connect( d->moreFiles, SIGNAL(highlighted(QListBoxItem*)), + this, SLOT(updateFileNameEdit(QListBoxItem*)) ); + connect( d->moreFiles, SIGNAL( rightButtonPressed(QListBoxItem*,const QPoint&) ), + this, SLOT( popupContextMenu(QListBoxItem*,const QPoint&) ) ); + + d->moreFiles->installEventFilter( this ); + d->moreFiles->viewport()->installEventFilter( this ); + + okB = new QPushButton( tr("&OK"), this, "OK" ); //### Or "Save (see other "OK") + okB->setDefault( TRUE ); + okB->setEnabled( FALSE ); + connect( okB, SIGNAL(clicked()), this, SLOT(okClicked()) ); + cancelB = new QPushButton( tr("Cancel") , this, "Cancel" ); + connect( cancelB, SIGNAL(clicked()), this, SLOT(cancelClicked()) ); + + d->paths = new QComboBox( TRUE, this, "directory history/editor" ); + d->paths->setDuplicatesEnabled( FALSE ); + d->paths->setInsertionPolicy( QComboBox::NoInsertion ); + const QFileInfoList * rootDrives = QDir::drives(); + QFileInfoListIterator it( *rootDrives ); + QFileInfo *fi; + makeVariables(); + + while ( (fi = it.current()) != 0 ) { + ++it; + d->paths->insertItem( *openFolderIcon, fi->absFilePath() ); + } + + if ( !!QDir::homeDirPath() ) { + if ( !d->paths->listBox()->findItem( QDir::homeDirPath() ) ) + d->paths->insertItem( *openFolderIcon, QDir::homeDirPath() ); + } + + connect( d->paths, SIGNAL(activated(const QString&)), + this, SLOT(setDir(const QString&)) ); + + d->paths->installEventFilter( this ); + QObjectList *ol = d->paths->queryList( "QLineEdit" ); + if ( ol && ol->first() ) + ( (QLineEdit*)ol->first() )->installEventFilter( this ); + delete ol; + + d->geometryDirty = TRUE; + d->types = new QComboBox( TRUE, this, "file types" ); + d->types->setDuplicatesEnabled( FALSE ); + d->types->setEditable( FALSE ); + connect( d->types, SIGNAL(activated(const QString&)), + this, SLOT(setFilter(const QString&)) ); + connect( d->types, SIGNAL(activated(const QString&)), + this, SIGNAL(filterSelected(const QString&)) ); + + d->pathL = new QLabel( d->paths, tr("Look &in:"), this, "qt_looin_lbl" ); + d->fileL = new QLabel( nameEdit, tr("File &name:"), this, "qt_filename_lbl" ); + d->typeL = new QLabel( d->types, tr("File &type:"), this, "qt_filetype_lbl" ); + + d->goBack = new QToolButton( this, "go back" ); + d->goBack->setEnabled( FALSE ); + d->goBack->setFocusPolicy( TabFocus ); + connect( d->goBack, SIGNAL( clicked() ), this, SLOT( goBack() ) ); +#ifndef QT_NO_TOOLTIP + QToolTip::add( d->goBack, tr( "Back" ) ); +#endif + d->goBack->setIconSet( *goBackIcon ); + + d->cdToParent = new QToolButton( this, "cd to parent" ); + d->cdToParent->setFocusPolicy( TabFocus ); +#ifndef QT_NO_TOOLTIP + QToolTip::add( d->cdToParent, tr( "One directory up" ) ); +#endif + d->cdToParent->setIconSet( *cdToParentIcon ); + connect( d->cdToParent, SIGNAL(clicked()), + this, SLOT(cdUpClicked()) ); + + d->newFolder = new QToolButton( this, "new folder" ); + d->newFolder->setFocusPolicy( TabFocus ); +#ifndef QT_NO_TOOLTIP + QToolTip::add( d->newFolder, tr( "Create New Folder" ) ); +#endif + d->newFolder->setIconSet( *newFolderIcon ); + connect( d->newFolder, SIGNAL(clicked()), + this, SLOT(newFolderClicked()) ); + + d->modeButtons = new QButtonGroup( 0, "invisible group" ); + connect( d->modeButtons, SIGNAL(destroyed()), + this, SLOT(modeButtonsDestroyed()) ); + d->modeButtons->setExclusive( TRUE ); + connect( d->modeButtons, SIGNAL(clicked(int)), + d->stack, SLOT(raiseWidget(int)) ); + connect( d->modeButtons, SIGNAL(clicked(int)), + this, SLOT(changeMode(int)) ); + + d->mcView = new QToolButton( this, "mclistbox view" ); + d->mcView->setFocusPolicy( TabFocus ); +#ifndef QT_NO_TOOLTIP + QToolTip::add( d->mcView, tr( "List View" ) ); +#endif + d->mcView->setIconSet( *multiColumnListViewIcon ); + d->mcView->setToggleButton( TRUE ); + d->stack->addWidget( d->moreFiles, d->modeButtons->insert( d->mcView ) ); + d->detailView = new QToolButton( this, "list view" ); + d->detailView->setFocusPolicy( TabFocus ); +#ifndef QT_NO_TOOLTIP + QToolTip::add( d->detailView, tr( "Detail View" ) ); +#endif + d->detailView->setIconSet( *detailViewIcon ); + d->detailView->setToggleButton( TRUE ); + d->stack->addWidget( files, d->modeButtons->insert( d->detailView ) ); + + d->previewInfo = new QToolButton( this, "preview info view" ); + d->previewInfo->setFocusPolicy( TabFocus ); +#ifndef QT_NO_TOOLTIP + QToolTip::add( d->previewInfo, tr( "Preview File Info" ) ); +#endif + d->previewInfo->setIconSet( *previewInfoViewIcon ); + d->previewInfo->setToggleButton( TRUE ); + d->modeButtons->insert( d->previewInfo ); + + d->previewContents = new QToolButton( this, "preview info view" ); +#if defined(Q_WS_WIN) && !defined(Q_OS_TEMP) + if ( (qt_winver & WV_NT_based) > Qt::WV_NT ) +#else + if ( !qstrcmp(style().className(), "QWindowsStyle") ) +#endif + { + d->goBack->setAutoRaise( TRUE ); + d->cdToParent->setAutoRaise( TRUE ); + d->newFolder->setAutoRaise( TRUE ); + d->mcView->setAutoRaise( TRUE ); + d->detailView->setAutoRaise( TRUE ); + d->previewInfo->setAutoRaise( TRUE ); + d->previewContents->setAutoRaise( TRUE ); + } + d->previewContents->setFocusPolicy( TabFocus ); +#ifndef QT_NO_TOOLTIP + QToolTip::add( d->previewContents, tr( "Preview File Contents" ) ); +#endif + d->previewContents->setIconSet( *previewContentsViewIcon ); + d->previewContents->setToggleButton( TRUE ); + d->modeButtons->insert( d->previewContents ); + + connect( d->detailView, SIGNAL( clicked() ), + d->moreFiles, SLOT( cancelRename() ) ); + connect( d->detailView, SIGNAL( clicked() ), + files, SLOT( cancelRename() ) ); + connect( d->mcView, SIGNAL( clicked() ), + d->moreFiles, SLOT( cancelRename() ) ); + connect( d->mcView, SIGNAL( clicked() ), + files, SLOT( cancelRename() ) ); + + d->stack->raiseWidget( d->moreFiles ); + d->mcView->setOn( TRUE ); + + QHBoxLayout *lay = new QHBoxLayout( this ); + lay->setMargin( 6 ); + d->leftLayout = new QHBoxLayout( lay, 5 ); + d->topLevelLayout = new QVBoxLayout( (QWidget*)0, 5 ); + lay->addLayout( d->topLevelLayout, 1 ); + d->extraWidgetsLayouts.setAutoDelete( FALSE ); + d->extraLabels.setAutoDelete( FALSE ); + d->extraWidgets.setAutoDelete( FALSE ); + d->extraButtons.setAutoDelete( FALSE ); + d->toolButtons.setAutoDelete( FALSE ); + + QHBoxLayout * h; + + d->preview = new QWidgetStack( d->splitter, "qt_preview" ); + + d->infoPreviewWidget = new QWidget( d->preview, "qt_preview_info" ); + d->contentsPreviewWidget = new QWidget( d->preview, "qt_preview_contents" ); + d->infoPreviewer = d->contentsPreviewer = 0; + + h = new QHBoxLayout( 0 ); + d->buttonLayout = h; + d->topLevelLayout->addLayout( h ); + h->addWidget( d->pathL ); + h->addSpacing( 8 ); + h->addWidget( d->paths ); + h->addSpacing( 8 ); + if ( d->goBack ) + h->addWidget( d->goBack ); + h->addWidget( d->cdToParent ); + h->addSpacing( 2 ); + h->addWidget( d->newFolder ); + h->addSpacing( 4 ); + h->addWidget( d->mcView ); + h->addWidget( d->detailView ); + h->addWidget( d->previewInfo ); + h->addWidget( d->previewContents ); + + d->topLevelLayout->addWidget( d->splitter ); + + h = new QHBoxLayout(); + d->topLevelLayout->addLayout( h ); + h->addWidget( d->fileL ); + h->addWidget( nameEdit ); + h->addSpacing( 15 ); + h->addWidget( okB ); + + h = new QHBoxLayout(); + d->topLevelLayout->addLayout( h ); + h->addWidget( d->typeL ); + h->addWidget( d->types ); + h->addSpacing( 15 ); + h->addWidget( cancelB ); + + d->rightLayout = new QHBoxLayout( lay, 5 ); + d->topLevelLayout->setStretchFactor( d->mcView, 1 ); + d->topLevelLayout->setStretchFactor( files, 1 ); + + updateGeometries(); + + if ( d->goBack ) { + setTabOrder( d->paths, d->goBack ); + setTabOrder( d->goBack, d->cdToParent ); + } else { + setTabOrder( d->paths, d->cdToParent ); + } + setTabOrder( d->cdToParent, d->newFolder ); + setTabOrder( d->newFolder, d->mcView ); + setTabOrder( d->mcView, d->detailView ); + setTabOrder( d->detailView, d->moreFiles ); + setTabOrder( d->moreFiles, files ); + setTabOrder( files, nameEdit ); + setTabOrder( nameEdit, d->types ); + setTabOrder( d->types, okB ); + setTabOrder( okB, cancelB ); + + d->rw = tr( "Read-write" ); + d->ro = tr( "Read-only" ); + d->wo = tr( "Write-only" ); + d->inaccessible = tr( "Inaccessible" ); + + d->symLinkToFile = tr( "Symlink to File" ); + d->symLinkToDir = tr( "Symlink to Directory" ); + d->symLinkToSpecial = tr( "Symlink to Special" ); + d->file = tr( "File" ); + d->dir = tr( "Dir" ); + d->special = tr( "Special" ); + + if ( lastWidth == 0 ) { + QRect screen = QApplication::desktop()->screenGeometry( pos() ); + if ( screen.width() < 1024 || screen.height() < 768 ) { + resize( QMIN(screen.width(), 420), QMIN(screen.height(), 236) ); + } else { + QSize s = files->sizeHint(); + s = QSize( s.width() + 300, s.height() + 82 ); + + if ( s.width() * 3 > screen.width() * 2 ) + s.setWidth( screen.width() * 2 / 3 ); + + if ( s.height() * 3 > screen.height() * 2 ) + s.setHeight( screen.height() * 2 / 3 ); + else if ( s.height() * 3 < screen.height() ) + s.setHeight( screen.height() / 3 ); + + resize( s ); + } + updateLastSize(this); + } else { + resize( lastWidth, lastHeight ); + } + + if ( detailViewMode ) { + d->stack->raiseWidget( files ); + d->mcView->setOn( FALSE ); + d->detailView->setOn( TRUE ); + } + + d->preview->hide(); + nameEdit->setFocus(); + + connect( nameEdit, SIGNAL( returnPressed() ), + this, SLOT( fileNameEditReturnPressed() ) ); +} + +/*! + \internal +*/ + +void QFileDialog::fileNameEditReturnPressed() +{ + d->oldUrl = d->url; + if ( !isDirectoryMode( d->mode ) ) { + okClicked(); + } else { + d->currentFileName = QString::null; + if ( nameEdit->text().isEmpty() ) { + emit fileSelected( selectedFile() ); + accept(); + } else { + QUrlInfo f; + QFileDialogPrivate::File * c + = (QFileDialogPrivate::File *)files->currentItem(); + if ( c && files->isSelected(c) ) + f = c->info; + else + f = QUrlInfo( d->url, nameEdit->text() ); + if ( f.isDir() ) { + setUrl( QUrlOperator( d->url, + QFileDialogPrivate::encodeFileName(nameEdit->text() + "/" ) ) ); + d->checkForFilter = TRUE; + trySetSelection( TRUE, d->url, TRUE ); + d->checkForFilter = FALSE; + } + } + nameEdit->setText( QString::null ); + } +} + +/*! + \internal + Update the info and content preview widgets to display \a u. +*/ + +void QFileDialog::updatePreviews( const QUrl &u ) +{ + if ( d->infoPreviewer ) + d->infoPreviewer->previewUrl( u ); + if ( d->contentsPreviewer ) + d->contentsPreviewer->previewUrl( u ); +} + +/*! + \internal + Changes the preview mode to the mode specified at \a id. +*/ + +void QFileDialog::changeMode( int id ) +{ + if ( !d->infoPreview && !d->contentsPreview ) + return; + + QButton *btn = (QButton*)d->modeButtons->find( id ); + if ( !btn ) + return; + + if ( btn == d->previewContents && !d->contentsPreview ) + return; + if ( btn == d->previewInfo && !d->infoPreview ) + return; + + if ( btn != d->previewContents && btn != d->previewInfo ) { + d->preview->hide(); + } else { + if ( files->currentItem() ) + updatePreviews( QUrl( d->url, files->currentItem()->text( 0 ) ) ); + if ( btn == d->previewInfo ) + d->preview->raiseWidget( d->infoPreviewWidget ); + else + d->preview->raiseWidget( d->contentsPreviewWidget ); + d->preview->show(); + } +} + +/*! + Destroys the file dialog. +*/ + +QFileDialog::~QFileDialog() +{ + // since clear might call setContentsPos which would emit + // a signal and thus cause a recompute of sizes... + files->blockSignals( TRUE ); + d->moreFiles->blockSignals( TRUE ); + files->clear(); + d->moreFiles->clear(); + d->moreFiles->blockSignals( FALSE ); + files->blockSignals( FALSE ); + +#ifndef QT_NO_CURSOR + if ( d->cursorOverride ) + QApplication::restoreOverrideCursor(); +#endif + + delete d; + d = 0; +} + + +/*! + \property QFileDialog::selectedFile + + \brief the name of the selected file + + If a file was selected selectedFile contains the file's name including + its absolute path; otherwise selectedFile is empty. + + \sa QString::isEmpty(), selectedFiles, selectedFilter +*/ + +QString QFileDialog::selectedFile() const +{ + QString s = d->currentFileName; + // remove the protocol because we do not want to encode it... + QString prot = QUrl( s ).protocol(); + if ( !prot.isEmpty() ) { + prot += ":"; + s.remove( 0, prot.length() ); + } + QUrl u( prot + QFileDialogPrivate::encodeFileName( s ) ); + if ( u.isLocalFile() ) { + QString s = u.toString(); + if ( s.left( 5 ) == "file:" ) + s.remove( (uint)0, 5 ); + return s; + } + return d->currentFileName; +} + +/*! + \property QFileDialog::selectedFilter + + \brief the filter which the user has selected in the file dialog + + \sa filterSelected(), selectedFiles, selectedFile +*/ + +QString QFileDialog::selectedFilter() const +{ + return d->types->currentText(); +} + +/*! \overload + + Sets the current filter selected in the file dialog to the + \a{n}-th filter in the filter list. + + \sa filterSelected(), selectedFilter(), selectedFiles(), selectedFile() +*/ + +void QFileDialog::setSelectedFilter( int n ) +{ + d->types->setCurrentItem( n ); + QString f = d->types->currentText(); + QRegExp r( QString::fromLatin1(qt_file_dialog_filter_reg_exp) ); + int index = r.search( f ); + if ( index >= 0 ) + f = r.cap( 2 ); + d->url.setNameFilter( f ); + rereadDir(); +} + +/*! + Sets the current filter selected in the file dialog to the first + one that contains the text \a mask. +*/ + +void QFileDialog::setSelectedFilter( const QString& mask ) +{ + int n; + + for ( n = 0; n < d->types->count(); n++ ) { + if ( d->types->text( n ).contains( mask, FALSE ) ) { + d->types->setCurrentItem( n ); + QString f = mask; + QRegExp r( QString::fromLatin1(qt_file_dialog_filter_reg_exp) ); + int index = r.search( f ); + if ( index >= 0 ) + f = r.cap( 2 ); + d->url.setNameFilter( f ); + rereadDir(); + return; + } + } +} + +/*! + \property QFileDialog::selectedFiles + + \brief the list of selected files + + If one or more files are selected, selectedFiles contains their + names including their absolute paths. If no files are selected or + the mode isn't ExistingFiles selectedFiles is an empty list. + + It is more convenient to use selectedFile() if the mode is + \c ExistingFile, \c Directory or \c DirectoryOnly. + + Note that if you want to iterate over the list, you should + iterate over a copy, e.g. + \code + QStringList list = myFileDialog.selectedFiles(); + QStringList::Iterator it = list.begin(); + while( it != list.end() ) { + myProcessing( *it ); + ++it; + } + \endcode + + \sa selectedFile, selectedFilter, QValueList::empty() +*/ + +QStringList QFileDialog::selectedFiles() const +{ + QStringList lst; + + if ( mode() == ExistingFiles ) { + QStringList selectedLst; + QString selectedFiles = nameEdit->text(); + if (selectedFiles.findRev('\"') == -1) { + //probably because Enter was pressed on the nameEdit, so we have one file + //not in "" but raw + selectedLst.append(selectedFiles); + } else { + selectedFiles.truncate( selectedFiles.findRev( '\"' ) ); + selectedLst = selectedLst.split( QString("\" "), selectedFiles ); + } + for ( QStringList::Iterator it = selectedLst.begin(); it != selectedLst.end(); ++it ) { + QUrl u; + if ( (*it)[0] == '\"' ) { + u = QUrl( d->url, QFileDialogPrivate::encodeFileName( (*it).mid(1) ) ); + } else { + u = QUrl( d->url, QFileDialogPrivate::encodeFileName( (*it) ) ); + } + if ( u.isLocalFile() ) { + QString s = u.toString(); + if ( s.left( 5 ) == "file:" ) + s.remove( (uint)0, 5 ); + lst << s; + } else { + lst << u.toString(); + } + } + } + + return lst; +} + +/*! + Sets the default selection to \a filename. If \a filename is + absolute, setDir() is also called to set the file dialog's working + directory to the filename's directory. + + \omit + Only for external use. Not useful inside QFileDialog. + \endomit +*/ + +void QFileDialog::setSelection( const QString & filename ) +{ + d->oldUrl = d->url; + QString nf = d->url.nameFilter(); + if ( QUrl::isRelativeUrl( filename ) ) + d->url = QUrlOperator( d->url, QFileDialogPrivate::encodeFileName( filename ) ); + else + d->url = QUrlOperator( filename ); + d->url.setNameFilter( nf ); + d->checkForFilter = TRUE; + bool isDirOk; + bool isDir = d->url.isDir( &isDirOk ); + if ( !isDirOk ) + isDir = d->url.path().right( 1 ) == "/"; + if ( !isDir ) { + QUrlOperator u( d->url ); + d->url.setPath( d->url.dirPath() ); + trySetSelection( FALSE, u, TRUE ); + d->ignoreNextRefresh = TRUE; + nameEdit->selectAll(); + rereadDir(); + emit dirEntered( d->url.dirPath() ); + } else { + if ( !d->url.path().isEmpty() && + d->url.path().right( 1 ) != "/" ) { + QString p = d->url.path(); + p += "/"; + d->url.setPath( p ); + } + trySetSelection( TRUE, d->url, FALSE ); + rereadDir(); + emit dirEntered( d->url.dirPath() ); + nameEdit->setText( QString::fromLatin1("") ); + } + d->checkForFilter = FALSE; +} + +/*! + \property QFileDialog::dirPath + + \brief the file dialog's working directory + + \sa dir(), setDir() +*/ + +QString QFileDialog::dirPath() const +{ + return d->url.dirPath(); +} + + +/*! + + Sets the filter used in the file dialog to \a newFilter. + + If \a newFilter contains a pair of parentheses containing one or more + of <em><b>anything*something</b></em> separated by spaces or by + semi-colons then only the text contained in the parentheses is used as + the filter. This means that these calls are all equivalent: + + \code + fd->setFilter( "All C++ files (*.cpp *.cc *.C *.cxx *.c++)" ); + fd->setFilter( "*.cpp *.cc *.C *.cxx *.c++" ); + fd->setFilter( "All C++ files (*.cpp;*.cc;*.C;*.cxx;*.c++)" ); + fd->setFilter( "*.cpp;*.cc;*.C;*.cxx;*.c++" ); + \endcode + + \sa setFilters() +*/ + +void QFileDialog::setFilter( const QString & newFilter ) +{ + if ( newFilter.isEmpty() ) + return; + QString f = newFilter; + QRegExp r( QString::fromLatin1(qt_file_dialog_filter_reg_exp) ); + int index = r.search( f ); + if ( index >= 0 ) + f = r.cap( 2 ); + d->url.setNameFilter( f ); + if ( d->types->count() == 1 ) { + d->types->clear(); + d->types->insertItem( newFilter ); + } else { + for ( int i = 0; i < d->types->count(); ++i ) { + if ( d->types->text( i ).left( newFilter.length() ) == newFilter || + d->types->text( i ).left( f.length() ) == f ) { + d->types->setCurrentItem( i ); + break; + } + } + } + rereadDir(); +} + + +/*! \overload + Sets the file dialog's working directory to \a pathstr. + + \sa dir() +*/ + +void QFileDialog::setDir( const QString & pathstr ) +{ + QString dr = pathstr; + if ( dr.isEmpty() ) + return; + +#if defined(Q_OS_UNIX) + if ( dr.length() && dr[0] == '~' ) { + int i = 0; + while( i < (int)dr.length() && dr[i] != '/' ) + i++; + QCString user; + if ( i == 1 ) { +#if defined(QT_THREAD_SUPPORT) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) + +# ifndef _POSIX_LOGIN_NAME_MAX +# define _POSIX_LOGIN_NAME_MAX 9 +# endif + + char name[_POSIX_LOGIN_NAME_MAX]; + if ( ::getlogin_r( name, _POSIX_LOGIN_NAME_MAX ) == 0 ) + user = name; + else +#else + user = ::getlogin(); + if ( !user ) +#endif + user = getenv( "LOGNAME" ); + } else + user = dr.mid( 1, i-1 ).local8Bit(); + dr = dr.mid( i, dr.length() ); + struct passwd *pw; +#if defined(QT_THREAD_SUPPORT) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) && !defined(Q_OS_FREEBSD) && !defined(Q_OS_OPENBSD) + struct passwd mt_pw; + char buffer[2048]; + if ( ::getpwnam_r( user, &mt_pw, buffer, 2048, &pw ) == 0 && pw == &mt_pw ) +#else + pw = ::getpwnam( user ); + if ( pw ) +#endif + dr.prepend( QString::fromLocal8Bit(pw->pw_dir) ); + } +#endif + + setUrl( dr ); +} + +/*! + Returns the current directory shown in the file dialog. + + The ownership of the QDir pointer is transferred to the caller, so + it must be deleted by the caller when no longer required. + + \sa setDir() +*/ + +const QDir *QFileDialog::dir() const +{ + if ( d->url.isLocalFile() ) + return new QDir( d->url.path() ); + else + return 0; +} + +/*! + Sets the file dialog's working directory to \a dir. + \sa dir() +*/ + +void QFileDialog::setDir( const QDir &dir ) +{ + d->oldUrl = d->url; + QString nf( d->url.nameFilter() ); + d->url = dir.canonicalPath(); + d->url.setNameFilter( nf ); + QUrlInfo i( d->url, nameEdit->text() ); + d->checkForFilter = TRUE; + trySetSelection( i.isDir(), QUrlOperator( d->url, QFileDialogPrivate::encodeFileName(nameEdit->text() ) ), FALSE ); + d->checkForFilter = FALSE; + rereadDir(); + emit dirEntered( d->url.path() ); +} + +/*! + Sets the file dialog's working directory to the directory specified at \a url. + + \sa url() +*/ + +void QFileDialog::setUrl( const QUrlOperator &url ) +{ + d->oldUrl = d->url; + QString nf = d->url.nameFilter(); + + QString operatorPath = url.toString( FALSE, FALSE ); + if ( QUrl::isRelativeUrl( operatorPath ) ) { + d->url = QUrl( d->url, operatorPath ); + } else { + d->url = url; + } + d->url.setNameFilter( nf ); + + d->checkForFilter = TRUE; + if ( !d->url.isDir() ) { + QUrlOperator u = d->url; + d->url.setPath( d->url.dirPath() ); + trySetSelection( FALSE, u, FALSE ); + rereadDir(); + emit dirEntered( d->url.dirPath() ); + QString fn = u.fileName(); + nameEdit->setText( fn ); + } else { + trySetSelection( TRUE, d->url, FALSE ); + rereadDir(); + emit dirEntered( d->url.dirPath() ); + } + d->checkForFilter = FALSE; +} + +/*! + \property QFileDialog::showHiddenFiles + + \brief whether hidden files are shown in the file dialog + + The default is FALSE, i.e. don't show hidden files. +*/ + +void QFileDialog::setShowHiddenFiles( bool s ) +{ + if ( s == bShowHiddenFiles ) + return; + + bShowHiddenFiles = s; + rereadDir(); +} + +bool QFileDialog::showHiddenFiles() const +{ + return bShowHiddenFiles; +} + +/*! + Rereads the current directory shown in the file dialog. + + The only time you will need to call this function is if the contents of + the directory change and you wish to refresh the file dialog to reflect + the change. + + \sa resortDir() +*/ + +void QFileDialog::rereadDir() +{ +#ifndef QT_NO_CURSOR + if ( !d->cursorOverride ) { + QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) ); + d->cursorOverride = TRUE; + } +#endif + d->pendingItems.clear(); + if ( d->mimeTypeTimer->isActive() ) + d->mimeTypeTimer->stop(); + d->currListChildren = d->url.listChildren(); +#ifndef QT_NO_CURSOR + if ( d->cursorOverride ) { + QApplication::restoreOverrideCursor(); + d->cursorOverride = FALSE; + } +#endif +} + + +/*! + \fn void QFileDialog::fileHighlighted( const QString& ) + + This signal is emitted when the user highlights a file, i.e. makes + it the current file. + + \sa fileSelected(), filesSelected() +*/ + +/*! + \fn void QFileDialog::fileSelected( const QString& ) + + This signal is emitted when the user selects a file. + + \sa filesSelected(), fileHighlighted(), selectedFile() +*/ + +/*! + \fn void QFileDialog::filesSelected( const QStringList& ) + + This signal is emitted when the user selects one or more files in \e + ExistingFiles mode. + + \sa fileSelected(), fileHighlighted(), selectedFiles() +*/ + +/*! + \fn void QFileDialog::dirEntered( const QString& ) + + This signal is emitted when the user enters a directory. + + \sa dir() +*/ + +/*! + \fn void QFileDialog::filterSelected( const QString& ) + + This signal is emitted when the user selects a filter. + + \sa selectedFilter() +*/ + +extern bool qt_resolve_symlinks; // defined in qapplication.cpp +bool Q_EXPORT qt_use_native_dialogs = TRUE; + +/*! + This is a convenience static function that returns an existing file + selected by the user. If the user pressed Cancel, it returns a null + string. + + \code + QString s = QFileDialog::getOpenFileName( + "/home", + "Images (*.png *.xpm *.jpg)", + this, + "open file dialog", + "Choose a file to open" ); + \endcode + + The function creates a modal file dialog called \a name, with + parent, \a parent. If a parent is not 0, the dialog will be shown + centered over the parent. + + The file dialog's working directory will be set to \a startWith. If \a + startWith includes a file name, the file will be selected. The filter + is set to \a filter so that only those files which match the filter + are shown. The filter selected is set to \a selectedFilter. The parameters + \a startWith, \a selectedFilter and \a filter may be QString::null. + + The dialog's caption is set to \a caption. If \a caption is not + specified then a default caption will be used. + + Under Windows and Mac OS X, this static function will use the native + file dialog and not a QFileDialog, unless the style of the application + is set to something other than the native style (Note that on Windows the + dialog will spin a blocking modal event loop that will not dispatch any + QTimers and if parent is not 0 then it will position the dialog just under + the parent's titlebar). + + Under Unix/X11, the normal behavior of the file dialog is to resolve + and follow symlinks. For example, if /usr/tmp is a symlink to /var/tmp, + the file dialog will change to /var/tmp after entering /usr/tmp. + If \a resolveSymlinks is FALSE, the file dialog will treat + symlinks as regular directories. + + \sa getOpenFileNames(), getSaveFileName(), getExistingDirectory() +*/ + +QString QFileDialog::getOpenFileName( const QString & startWith, + const QString& filter, + QWidget *parent, const char* name, + const QString& caption, + QString *selectedFilter, + bool resolveSymlinks ) +{ + bool save_qt_resolve_symlinks = qt_resolve_symlinks; + qt_resolve_symlinks = resolveSymlinks; + + QStringList filters; + if ( !filter.isEmpty() ) + filters = makeFiltersList( filter ); + + makeVariables(); + QString initialSelection; + //### Problem with the logic here: If a startWith is given and a file + // with that name exists in D->URL, the box will be opened at D->URL instead of + // the last directory used ('workingDirectory'). + // + // hm... isn't that problem exactly the documented behaviour? the + // documented behaviour sounds meaningful. + if ( !startWith.isEmpty() ) { + QUrlOperator u( QFileDialogPrivate::encodeFileName( startWith ) ); + if ( u.isLocalFile() && QFileInfo( u.path() ).isDir() ) { + *workingDirectory = startWith; + } else { + if ( u.isLocalFile() ) { + QFileInfo fi( u.dirPath() ); + if ( fi.exists() ) { + *workingDirectory = u.dirPath(); + initialSelection = u.fileName(); + } + } else { + *workingDirectory = u.toString(); + initialSelection = QString::null;//u.fileName(); + } + } + } + + if ( workingDirectory->isNull() ) + *workingDirectory = ::toRootIfNotExists( QDir::currentDirPath() ); + +#if defined(Q_WS_WIN) + if ( qt_use_native_dialogs && qApp->style().styleHint( QStyle::SH_GUIStyle ) == WindowsStyle ) + return winGetOpenFileName( initialSelection, filter, workingDirectory, + parent, name, caption, selectedFilter ); +#elif defined(Q_WS_MAC) + if (qt_use_native_dialogs && (qApp->style().inherits(QMAC_DEFAULT_STYLE) + || qApp->style().inherits("QMacStyle"))) + return qt_mac_precomposeFileName(macGetOpenFileNames(filter, + startWith.isEmpty() ? 0 : workingDirectory, + parent, name, caption, selectedFilter, FALSE).first()); +#endif + + QFileDialog *dlg = new QFileDialog( *workingDirectory, QString::null, parent, name ? name : "qt_filedlg_gofn", TRUE ); + + Q_CHECK_PTR( dlg ); +#ifndef QT_NO_WIDGET_TOPEXTRA + if ( !caption.isNull() ) + dlg->setCaption( caption ); + else + dlg->setCaption( QFileDialog::tr( "Open" ) ); +#endif + + dlg->setFilters( filters ); + if ( selectedFilter ) + dlg->setFilter( *selectedFilter ); + dlg->setMode( QFileDialog::ExistingFile ); + QString result; + if ( !initialSelection.isEmpty() ) + dlg->setSelection( initialSelection ); + if ( dlg->exec() == QDialog::Accepted ) { + result = dlg->selectedFile(); + *workingDirectory = dlg->d->url; + if ( selectedFilter ) + *selectedFilter = dlg->selectedFilter(); + } + delete dlg; + + qt_resolve_symlinks = save_qt_resolve_symlinks; + + return result; +} + +/*! + This is a convenience static function that will return a file name + selected by the user. The file does not have to exist. + + It creates a modal file dialog called \a name, with parent, \a parent. + If a parent is not 0, the dialog will be shown centered over the + parent. + + \code + QString s = QFileDialog::getSaveFileName( + "/home", + "Images (*.png *.xpm *.jpg)", + this, + "save file dialog", + "Choose a filename to save under" ); + \endcode + + The file dialog's working directory will be set to \a startWith. If \a + startWith includes a file name, the file will be selected. The filter + is set to \a filter so that only those files which match the filter + are shown. The filter selected is set to \a selectedFilter. The parameters + \a startWith, \a selectedFilter and \a filter may be QString::null. + + The dialog's caption is set to \a caption. If \a caption is not + specified then a default caption will be used. + + Under Windows and Mac OS X, this static function will use the native + file dialog and not a QFileDialog, unless the style of the application + is set to something other than the native style. (Note that on Windows the + dialog will spin a blocking modal event loop that will not dispatch any + QTimers and if parent is not 0 then it will position the dialog just under + the parent's titlebar. + + Under Unix/X11, the normal behavior of the file dialog is to resolve + and follow symlinks. For example, if /usr/tmp is a symlink to /var/tmp, + the file dialog will change to /var/tmp after entering /usr/tmp. + If \a resolveSymlinks is FALSE, the file dialog will treat + symlinks as regular directories. + + \sa getOpenFileName(), getOpenFileNames(), getExistingDirectory() +*/ + +QString QFileDialog::getSaveFileName( const QString & startWith, + const QString& filter, + QWidget *parent, const char* name, + const QString& caption, + QString *selectedFilter, + bool resolveSymlinks) +{ + bool save_qt_resolve_symlinks = qt_resolve_symlinks; + qt_resolve_symlinks = resolveSymlinks; + + QStringList filters; + if ( !filter.isEmpty() ) + filters = makeFiltersList( filter ); + + makeVariables(); + QString initialSelection; + if ( !startWith.isEmpty() ) { + QUrlOperator u( QFileDialogPrivate::encodeFileName( startWith ) ); + if ( u.isLocalFile() && QFileInfo( u.path() ).isDir() ) { + *workingDirectory = startWith; + } else { + if ( u.isLocalFile() ) { + QFileInfo fi( u.dirPath() ); + if ( fi.exists() ) { + *workingDirectory = u.dirPath(); + initialSelection = u.fileName(); + } + } else { + *workingDirectory = u.toString(); + initialSelection = QString::null;//u.fileName(); + } + } + } + + if ( workingDirectory->isNull() ) + *workingDirectory = ::toRootIfNotExists( QDir::currentDirPath() ); + +#if defined(Q_WS_WIN) + if ( qt_use_native_dialogs && qApp->style().styleHint( QStyle::SH_GUIStyle ) == WindowsStyle ) + return winGetSaveFileName( initialSelection, filter, workingDirectory, + parent, name, caption, selectedFilter ); +#elif defined(Q_WS_MAC) + if (qt_use_native_dialogs && (qApp->style().inherits(QMAC_DEFAULT_STYLE) + || qApp->style().inherits("QMacStyle"))) + return qt_mac_precomposeFileName(macGetSaveFileName(initialSelection, filter, + startWith.isEmpty() ? 0 : workingDirectory, parent, name, + caption, selectedFilter)); +#endif + + QFileDialog *dlg = new QFileDialog( *workingDirectory, QString::null, parent, name ? name : "qt_filedlg_gsfn", TRUE ); + + Q_CHECK_PTR( dlg ); +#ifndef QT_NO_WIDGET_TOPEXTRA + if ( !caption.isNull() ) + dlg->setCaption( caption ); + else + dlg->setCaption( QFileDialog::tr( "Save As" ) ); +#endif + + QString result; + dlg->setFilters( filters ); + if ( selectedFilter ) + dlg->setFilter( *selectedFilter ); + dlg->setMode( QFileDialog::AnyFile ); + if ( !initialSelection.isEmpty() ) + dlg->setSelection( initialSelection ); + if ( dlg->exec() == QDialog::Accepted ) { + result = dlg->selectedFile(); + *workingDirectory = dlg->d->url; + if ( selectedFilter ) + *selectedFilter = dlg->selectedFilter(); + } + delete dlg; + + qt_resolve_symlinks = save_qt_resolve_symlinks; + + return result; +} + +/*! + \internal + Activated when the "OK" button is clicked. +*/ + +void QFileDialog::okClicked() +{ + QString fn( nameEdit->text() ); + +#if defined(Q_WS_WIN) + QFileInfo fi( d->url.path() + fn ); + if ( fi.isSymLink() ) { + nameEdit->setText( fi.readLink() ); + } +#endif + + if ( fn.contains("*") ) { + addFilter( fn ); + nameEdit->blockSignals( TRUE ); + nameEdit->setText( QString::fromLatin1("") ); + nameEdit->blockSignals( FALSE ); + return; + } + + *workingDirectory = d->url; + detailViewMode = files->isVisible(); + updateLastSize(this); + + if ( isDirectoryMode( d->mode ) ) { + QUrlInfo f( d->url, nameEdit->text() ); + if ( f.isDir() ) { + d->currentFileName = d->url; + if ( d->currentFileName.right(1) != "/" ) + d->currentFileName += '/'; + if ( f.name() != "." ) + d->currentFileName += f.name(); + accept(); + return; + } + // Since it's not a directory and we clicked ok, we + // don't really want to do anything else + return; + } + + // if we're in multi-selection mode and something is selected, + // accept it and be done. + if ( mode() == ExistingFiles ) { + if ( ! nameEdit->text().isEmpty() ) { + QStringList sf = selectedFiles(); + bool isdir = FALSE; + if ( sf.count() == 1 ) { + QUrlOperator u( d->url, sf[0] ); + bool ok; + isdir = u.isDir(&ok) && ok; + } + if ( !isdir ) { + emit filesSelected( sf ); + accept(); + return; + } + } + } + + if ( mode() == AnyFile ) { + QUrlOperator u( d->url, QFileDialogPrivate::encodeFileName(nameEdit->text()) ); + if ( !u.isDir() ) { + d->currentFileName = u; + emit fileSelected( selectedFile() ); + accept(); + return; + } + } + + if ( mode() == ExistingFile ) { + if ( !QFileDialogPrivate::fileExists( d->url, nameEdit->text() ) ) + return; + } + + // If selection is valid, return it, else try + // using selection as a directory to change to. + if ( !d->currentFileName.isNull() && !d->currentFileName.contains( "*" ) ) { + emit fileSelected( selectedFile() ); + accept(); + } else { + QUrlInfo f; + QFileDialogPrivate::File * c + = (QFileDialogPrivate::File *)files->currentItem(); + QFileDialogPrivate::MCItem * m + = (QFileDialogPrivate::MCItem *)d->moreFiles->item( d->moreFiles->currentItem() ); + if ( c && files->isVisible() && files->hasFocus() || + m && d->moreFiles->isVisible() && d->moreFiles->hasFocus() ) { + if ( c && files->isVisible() ) + f = c->info; + else + f = ( (QFileDialogPrivate::File*)m->i )->info; + } else { + f = QUrlInfo( d->url, nameEdit->text() ); + } + if ( f.isDir() ) { + setUrl( QUrlOperator( d->url, QFileDialogPrivate::encodeFileName(f.name() + "/" ) ) ); + d->checkForFilter = TRUE; + trySetSelection( TRUE, d->url, TRUE ); + d->checkForFilter = FALSE; + } else { + if ( !nameEdit->text().contains( "/" ) && + !nameEdit->text().contains( "\\" ) +#if defined(Q_OS_WIN32) + && nameEdit->text()[ 1 ] != ':' +#endif + ) + addFilter( nameEdit->text() ); + else if ( nameEdit->text()[ 0 ] == '/' || + nameEdit->text()[ 0 ] == '\\' +#if defined(Q_OS_WIN32) + || nameEdit->text()[ 1 ] == ':' +#endif + ) + setDir( nameEdit->text() ); + else if ( nameEdit->text().left( 3 ) == "../" || nameEdit->text().left( 3 ) == "..\\" ) + setDir( QUrl( d->url.toString(), QFileDialogPrivate::encodeFileName(nameEdit->text() ) ).toString() ); + } + nameEdit->setText( "" ); + } +} + +/*! + \internal + Activated when the "Filter" button is clicked. +*/ + +void QFileDialog::filterClicked() +{ + // unused +} + +/*! + \internal + Activated when the "Cancel" button is clicked. +*/ + +void QFileDialog::cancelClicked() +{ + *workingDirectory = d->url; + detailViewMode = files->isVisible(); + updateLastSize(this); + reject(); +} + + +/*!\reimp +*/ + +void QFileDialog::resizeEvent( QResizeEvent * e ) +{ + QDialog::resizeEvent( e ); + updateGeometries(); +} + +/* + \internal + The only correct way to try to set currentFileName +*/ +bool QFileDialog::trySetSelection( bool isDir, const QUrlOperator &u, bool updatelined ) +{ + if ( !isDir && !u.path().isEmpty() && u.path().right( 1 ) == "/" ) + isDir = TRUE; + if ( u.fileName().contains( "*") && d->checkForFilter ) { + QString fn( u.fileName() ); + if ( fn.contains( "*" ) ) { + addFilter( fn ); + d->currentFileName = QString::null; + d->url.setFileName( QString::null ); + nameEdit->setText( QString::fromLatin1("") ); + return FALSE; + } + } + + if ( d->preview && d->preview->isVisible() ) + updatePreviews( u ); + + QString old = d->currentFileName; + + if ( isDirectoryMode( mode() ) ) { + if ( isDir ) + d->currentFileName = u; + else + d->currentFileName = QString::null; + } else if ( !isDir && mode() == ExistingFiles ) { + d->currentFileName = u; + } else if ( !isDir || ( mode() == AnyFile && !isDir ) ) { + d->currentFileName = u; + } else { + d->currentFileName = QString::null; + } + if ( updatelined && !d->currentFileName.isEmpty() ) { + // If the selection is valid, or if its a directory, allow OK. + if ( !d->currentFileName.isNull() || isDir ) { + if ( u.fileName() != ".." ) { + QString fn = u.fileName(); + nameEdit->setText( fn ); + } else { + nameEdit->setText(""); + } + } else + nameEdit->setText( QString::fromLatin1("") ); + } + + if ( !d->currentFileName.isNull() || isDir ) { + okB->setEnabled( TRUE ); + } else if ( !isDirectoryMode( d->mode ) ) { + okB->setEnabled( FALSE ); + } + + if ( d->currentFileName.length() && old != d->currentFileName ) + emit fileHighlighted( selectedFile() ); + + return !d->currentFileName.isNull(); +} + + +/*! Make sure the minimum and maximum sizes of everything are sane. +*/ + +void QFileDialog::updateGeometries() +{ + if ( !d || !d->geometryDirty ) + return; + + d->geometryDirty = FALSE; + + QSize r, t; + + // we really should have a QSize::unite() +#define RM r.setWidth( QMAX(r.width(),t.width()) ); \ +r.setHeight( QMAX(r.height(),t.height()) ) + + // labels first + r = d->pathL->sizeHint(); + t = d->fileL->sizeHint(); + RM; + t = d->typeL->sizeHint(); + RM; + d->pathL->setFixedSize( d->pathL->sizeHint() ); + d->fileL->setFixedSize( r ); + d->typeL->setFixedSize( r ); + + // single-line input areas + r = d->paths->sizeHint(); + t = nameEdit->sizeHint(); + RM; + t = d->types->sizeHint(); + RM; + r.setWidth( t.width() * 2 / 3 ); + t.setWidth( QWIDGETSIZE_MAX ); + t.setHeight( r.height() ); + d->paths->setMinimumSize( r ); + d->paths->setMaximumSize( t ); + nameEdit->setMinimumSize( r ); + nameEdit->setMaximumSize( t ); + d->types->setMinimumSize( r ); + d->types->setMaximumSize( t ); + + // buttons on top row + r = QSize( 0, d->paths->minimumSize().height() ); + t = QSize( 21, 20 ); + RM; + if ( r.height()+1 > r.width() ) + r.setWidth( r.height()+1 ); + if ( d->goBack ) + d->goBack->setFixedSize( r ); + d->cdToParent->setFixedSize( r ); + d->newFolder->setFixedSize( r ); + d->mcView->setFixedSize( r ); + d->detailView->setFixedSize( r ); + + QButton *b = 0; + if ( !d->toolButtons.isEmpty() ) { + for ( b = d->toolButtons.first(); b; b = d->toolButtons.next() ) + b->setFixedSize( b->sizeHint().width(), r.height() ); + } + + if ( d->infoPreview ) { + d->previewInfo->show(); + d->previewInfo->setFixedSize( r ); + } else { + d->previewInfo->hide(); + d->previewInfo->setFixedSize( QSize( 0, 0 ) ); + } + + if ( d->contentsPreview ) { + d->previewContents->show(); + d->previewContents->setFixedSize( r ); + } else { + d->previewContents->hide(); + d->previewContents->setFixedSize( QSize( 0, 0 ) ); + } + + // open/save, cancel + r = QSize( 75, 20 ); + t = okB->sizeHint(); + RM; + t = cancelB->sizeHint(); + RM; + + okB->setFixedSize( r ); + cancelB->setFixedSize( r ); + + d->topLevelLayout->activate(); + +#undef RM +} + + +/*! Updates the file name edit box to \a newItem in the file dialog + when the cursor moves in the listview. +*/ + +void QFileDialog::updateFileNameEdit( QListViewItem * newItem ) +{ + if ( !newItem ) + return; + + if ( mode() == ExistingFiles ) { + detailViewSelectionChanged(); + QUrl u( d->url, QFileDialogPrivate::encodeFileName( ((QFileDialogPrivate::File*)files->currentItem())->info.name() ) ); + QFileInfo fi( u.toString( FALSE, FALSE ) ); + if ( !fi.isDir() ) + emit fileHighlighted( u.toString( FALSE, FALSE ) ); + } else if ( files->isSelected( newItem ) ) { + QFileDialogPrivate::File * i = (QFileDialogPrivate::File *)newItem; + if ( i && i->i && !i->i->isSelected() ) { + d->moreFiles->blockSignals( TRUE ); + d->moreFiles->setSelected( i->i, TRUE ); + d->moreFiles->blockSignals( FALSE ); + } + // Encode the filename in case it had any special characters in it + QString encFile = QFileDialogPrivate::encodeFileName( newItem->text( 0 ) ); + trySetSelection( i->info.isDir(), QUrlOperator( d->url, encFile ), TRUE ); + } +} + +void QFileDialog::detailViewSelectionChanged() +{ + if ( d->mode != ExistingFiles ) + return; + + nameEdit->clear(); + QString str; + QListViewItem * i = files->firstChild(); + d->moreFiles->blockSignals( TRUE ); + while( i ) { + if ( d->moreFiles && isVisible() ) { + QFileDialogPrivate::File *f = (QFileDialogPrivate::File *)i; + if ( f->i && f->i->isSelected() != i->isSelected() ) + d->moreFiles->setSelected( f->i, i->isSelected() ); + } + if ( i->isSelected() && !( (QFileDialogPrivate::File *)i )->info.isDir() ) + str += QString( "\"%1\" " ).arg( i->text( 0 ) ); + i = i->nextSibling(); + } + d->moreFiles->blockSignals( FALSE ); + nameEdit->setText( str ); + nameEdit->setCursorPosition( str.length() ); + okB->setEnabled( TRUE ); + if ( d->preview && d->preview->isVisible() && files->currentItem() ) { + QUrl u = QUrl( d->url, QFileDialogPrivate::encodeFileName( ((QFileDialogPrivate::File*)files->currentItem())->info.name() ) ); + updatePreviews( u ); + } +} + +void QFileDialog::listBoxSelectionChanged() +{ + if ( d->mode != ExistingFiles ) + return; + + if ( d->ignoreNextRefresh ) { + d->ignoreNextRefresh = FALSE; + return; + } + + nameEdit->clear(); + QString str; + QListBoxItem * i = d->moreFiles->item( 0 ); + QListBoxItem * j = 0; + int index = 0; + files->blockSignals( TRUE ); + while( i ) { + QFileDialogPrivate::MCItem *mcitem = (QFileDialogPrivate::MCItem *)i; + if ( files && isVisible() ) { + if ( mcitem->i->isSelected() != mcitem->isSelected() ) { + files->setSelected( mcitem->i, mcitem->isSelected() ); + + // What happens here is that we want to emit signal highlighted for + // newly added items. But QListBox apparently emits selectionChanged even + // when a user clicks on the same item twice. So, basically emulate the behaivor + // we have in the "Details" view which only emits highlighted the first time we + // click on the item. Perhaps at some point we should have a call to + // updateFileNameEdit(QListViewItem) which also emits fileHighlighted() for + // ExistingFiles. For better or for worse, this clones the behaivor of the + // "Details" view quite well. + if ( mcitem->isSelected() && i != d->lastEFSelected ) { + QUrl u( d->url, QFileDialogPrivate::encodeFileName( ((QFileDialogPrivate::File*)(mcitem)->i)->info.name()) ); + d->lastEFSelected = i; + emit fileHighlighted( u.toString(FALSE, FALSE) ); + } + } + } + if ( d->moreFiles->isSelected( i ) + && !( (QFileDialogPrivate::File*)(mcitem)->i )->info.isDir() ) { + str += QString( "\"%1\" " ).arg( i->text() ); + if ( j == 0 ) + j = i; + } + i = d->moreFiles->item( ++index ); + } + + files->blockSignals( FALSE ); + nameEdit->setText( str ); + nameEdit->setCursorPosition( str.length() ); + okB->setEnabled( TRUE ); + if ( d->preview && d->preview->isVisible() && j ) { + QUrl u = QUrl( d->url, + QFileDialogPrivate::encodeFileName( ( (QFileDialogPrivate::File*)( (QFileDialogPrivate::MCItem*)j )->i )->info.name() ) ); + updatePreviews( u ); + } +} + +/*! \overload */ + +void QFileDialog::updateFileNameEdit( QListBoxItem * newItem ) +{ + if ( !newItem ) + return; + QFileDialogPrivate::MCItem * i = (QFileDialogPrivate::MCItem *)newItem; + if ( i->i ) { + i->i->listView()->setSelected( i->i, i->isSelected() ); + updateFileNameEdit( i->i ); + } +} + + +/*! Updates the dialog when the file name edit changes. */ + +void QFileDialog::fileNameEditDone() +{ + QUrlInfo f( d->url, nameEdit->text() ); + if ( mode() != QFileDialog::ExistingFiles ) { + QUrlOperator u( d->url, QFileDialogPrivate::encodeFileName( nameEdit->text() ) ); + trySetSelection( f.isDir(), u, FALSE ); + if ( d->preview && d->preview->isVisible() ) + updatePreviews( u ); + } +} + + + +/*! This private slot reacts to double-clicks in the list view. The item that +was double-clicked is specified in \a newItem */ + +void QFileDialog::selectDirectoryOrFile( QListViewItem * newItem ) +{ + + *workingDirectory = d->url; + detailViewMode = files->isVisible(); + updateLastSize(this); + + if ( !newItem ) + return; + + if ( d->url.isLocalFile() ) { + QFileInfo fi( d->url.path() + newItem->text(0) ); +#if defined(Q_WS_WIN) + if ( fi.isSymLink() ) { + nameEdit->setText( fi.readLink() ); + okClicked(); + return; + } +#endif + } + + QFileDialogPrivate::File * i = (QFileDialogPrivate::File *)newItem; + + QString oldName = nameEdit->text(); + if ( i->info.isDir() ) { + setUrl( QUrlOperator( d->url, QFileDialogPrivate::encodeFileName( i->info.name() ) + "/" ) ); + if ( isDirectoryMode( mode() ) ) { + QUrlInfo f ( d->url, QString::fromLatin1( "." ) ); + trySetSelection( f.isDir(), d->url, TRUE ); + } + } else if ( newItem->isSelectable() && + trySetSelection( i->info.isDir(), QUrlOperator( d->url, QFileDialogPrivate::encodeFileName( i->info.name() ) ), TRUE ) ) { + if ( !isDirectoryMode( mode() ) ) { + if ( mode() == ExistingFile ) { + if ( QFileDialogPrivate::fileExists( d->url, nameEdit->text() ) ) { + emit fileSelected( selectedFile() ); + accept(); + } + } else { + emit fileSelected( selectedFile() ); + accept(); + } + } + } else if ( isDirectoryMode( d->mode ) ) { + d->currentFileName = d->url; + accept(); + } + if ( !oldName.isEmpty() && !isDirectoryMode( mode() ) ) + nameEdit->setText( oldName ); +} + + +void QFileDialog::selectDirectoryOrFile( QListBoxItem * newItem ) +{ + if ( !newItem ) + return; + + QFileDialogPrivate::MCItem * i = (QFileDialogPrivate::MCItem *)newItem; + if ( i->i ) { + i->i->listView()->setSelected( i->i, i->isSelected() ); + selectDirectoryOrFile( i->i ); + } +} + + +void QFileDialog::popupContextMenu( QListViewItem *item, const QPoint &p, + int ) +{ + if ( item ) { + files->setCurrentItem( item ); + files->setSelected( item, TRUE ); + } + + PopupAction action; + popupContextMenu( item ? item->text( 0 ) : QString::null, TRUE, action, p ); + + if ( action == PA_Open ) + selectDirectoryOrFile( item ); + else if ( action == PA_Rename ) + files->startRename( FALSE ); + else if ( action == PA_Delete ) + deleteFile( item ? item->text( 0 ) : QString::null ); + else if ( action == PA_Reload ) + rereadDir(); + else if ( action == PA_Hidden ) { + bShowHiddenFiles = !bShowHiddenFiles; + rereadDir(); + } else if ( action == PA_SortName ) { + sortFilesBy = (int)QDir::Name; + sortAscending = TRUE; + resortDir(); + } else if ( action == PA_SortSize ) { + sortFilesBy = (int)QDir::Size; + sortAscending = TRUE; + resortDir(); + } else if ( action == PA_SortDate ) { + sortFilesBy = (int)QDir::Time; + sortAscending = TRUE; + resortDir(); + } else if ( action == PA_SortUnsorted ) { + sortFilesBy = (int)QDir::Unsorted; + sortAscending = TRUE; + resortDir(); + } + +} + +void QFileDialog::popupContextMenu( QListBoxItem *item, const QPoint & p ) +{ + PopupAction action; + popupContextMenu( item ? item->text() : QString::null, FALSE, action, p ); + + if ( action == PA_Open ) + selectDirectoryOrFile( item ); + else if ( action == PA_Rename ) + d->moreFiles->startRename( FALSE ); + else if ( action == PA_Delete ) + deleteFile( item->text() ); + else if ( action == PA_Reload ) + rereadDir(); + else if ( action == PA_Hidden ) { + bShowHiddenFiles = !bShowHiddenFiles; + rereadDir(); + } else if ( action == PA_SortName ) { + sortFilesBy = (int)QDir::Name; + sortAscending = TRUE; + resortDir(); + } else if ( action == PA_SortSize ) { + sortFilesBy = (int)QDir::Size; + sortAscending = TRUE; + resortDir(); + } else if ( action == PA_SortDate ) { + sortFilesBy = (int)QDir::Time; + sortAscending = TRUE; + resortDir(); + } else if ( action == PA_SortUnsorted ) { + sortFilesBy = (int)QDir::Unsorted; + sortAscending = TRUE; + resortDir(); + } +} + +void QFileDialog::popupContextMenu( const QString &filename, bool, + PopupAction &action, const QPoint &p ) +{ + action = PA_Cancel; + + bool glob = filename.isEmpty(); + + QPopupMenu m( 0, "file dialog context menu" ); + m.setCheckable( TRUE ); + + if ( !glob ) { + QString okt; + if ( QUrlInfo( d->url, filename ).isDir() ) { + okt = tr( "&Open" ); + } else { + if ( mode() == AnyFile ) + okt = tr( "&Save" ); + else + okt = tr( "&Open" ); + } + int ok = m.insertItem( okt ); + + m.insertSeparator(); + int rename = m.insertItem( tr( "&Rename" ) ); + int del = m.insertItem( tr( "&Delete" ) ); + + if ( filename.isEmpty() || !QUrlInfo( d->url, filename ).isWritable() || + filename == ".." ) { + if ( filename.isEmpty() || !QUrlInfo( d->url, filename ).isReadable() ) + m.setItemEnabled( ok, FALSE ); + m.setItemEnabled( rename, FALSE ); + m.setItemEnabled( del, FALSE ); + } + + m.move( p ); + int res = m.exec(); + + if ( res == ok ) + action = PA_Open; + else if ( res == rename ) + action = PA_Rename; + else if ( res == del ) + action = PA_Delete; + } else { + int reload = m.insertItem( tr( "R&eload" ) ); + + QPopupMenu m2( 0, "sort menu" ); + + int sname = m2.insertItem( tr( "Sort by &Name" ) ); + //int stype = m2.insertItem( tr( "Sort by &Type" ) ); + int ssize = m2.insertItem( tr( "Sort by &Size" ) ); + int sdate = m2.insertItem( tr( "Sort by &Date" ) ); + m2.insertSeparator(); + int sunsorted = m2.insertItem( tr( "&Unsorted" ) ); + + //m2.setItemEnabled( stype, FALSE ); + + if ( sortFilesBy == (int)QDir::Name ) + m2.setItemChecked( sname, TRUE ); + else if ( sortFilesBy == (int)QDir::Size ) + m2.setItemChecked( ssize, TRUE ); +// else if ( sortFilesBy == 0x16 ) +// m2.setItemChecked( stype, TRUE ); + else if ( sortFilesBy == (int)QDir::Time ) + m2.setItemChecked( sdate, TRUE ); + else if ( sortFilesBy == (int)QDir::Unsorted ) + m2.setItemChecked( sunsorted, TRUE ); + + m.insertItem( tr( "Sort" ), &m2 ); + + m.insertSeparator(); + + int hidden = m.insertItem( tr( "Show &hidden files" ) ); + m.setItemChecked( hidden, bShowHiddenFiles ); + + m.move( p ); + int res = m.exec(); + + if ( res == reload ) + action = PA_Reload; + else if ( res == hidden ) + action = PA_Hidden; + else if ( res == sname ) + action = PA_SortName; +// else if ( res == stype ) +// action = PA_SortType; + else if ( res == sdate ) + action = PA_SortDate; + else if ( res == ssize ) + action = PA_SortSize; + else if ( res == sunsorted ) + action = PA_SortUnsorted; + } + +} + +void QFileDialog::deleteFile( const QString &filename ) +{ + if ( filename.isEmpty() ) + return; + + QUrlInfo fi( d->url, QFileDialogPrivate::encodeFileName( filename ) ); + QString t = tr( "the file" ); + if ( fi.isDir() ) + t = tr( "the directory" ); + if ( fi.isSymLink() ) + t = tr( "the symlink" ); + + if ( QMessageBox::warning( this, + tr( "Delete %1" ).arg( t ), + tr( "<qt>Are you sure you wish to delete %1 \"%2\"?</qt>" ) + .arg( t ).arg(filename), + tr( "&Yes" ), tr( "&No" ), QString::null, 1 ) == 0 ) + d->url.remove( QFileDialogPrivate::encodeFileName( filename ) ); + +} + +void QFileDialog::fileSelected( int ) +{ + // unused +} + +void QFileDialog::fileHighlighted( int ) +{ + // unused +} + +void QFileDialog::dirSelected( int ) +{ + // unused +} + +void QFileDialog::pathSelected( int ) +{ + // unused +} + + +void QFileDialog::cdUpClicked() +{ + QString oldName = nameEdit->text(); + setUrl( QUrlOperator( d->url, ".." ) ); + if ( !oldName.isEmpty() ) + nameEdit->setText( oldName ); +} + +void QFileDialog::newFolderClicked() +{ + QString foldername( tr( "New Folder 1" ) ); + int i = 0; + QStringList lst; + QListViewItemIterator it( files ); + for ( ; it.current(); ++it ) + if ( it.current()->text( 0 ).contains( tr( "New Folder" ) ) ) + lst.append( it.current()->text( 0 ) ); + + if ( !lst.count() == 0 ) + while ( lst.contains( foldername ) ) + foldername = tr( "New Folder %1" ).arg( ++i ); + + d->url.mkdir( foldername ); +} + +void QFileDialog::createdDirectory( const QUrlInfo &info, QNetworkOperation * ) +{ + resortDir(); + if ( d->moreFiles->isVisible() ) { + for ( uint i = 0; i < d->moreFiles->count(); ++i ) { + if ( d->moreFiles->text( i ) == info.name() ) { + d->moreFiles->setCurrentItem( i ); + d->moreFiles->startRename( FALSE ); + break; + } + } + } else { + QListViewItem *item = files->firstChild(); + while ( item ) { + if ( item->text( 0 ) == info.name() ) { + files->setSelected( item, TRUE ); + files->setCurrentItem( item ); + files->startRename( FALSE ); + break; + } + item = item->nextSibling(); + } + } +} + + +/*! + This is a convenience static function that will return an existing directory + selected by the user. + + \code + QString s = QFileDialog::getExistingDirectory( + "/home", + this, + "get existing directory", + "Choose a directory", + TRUE ); + \endcode + + This function creates a modal file dialog called \a name, with + parent, \a parent. If parent is not 0, the dialog will be shown + centered over the parent. + + The dialog's working directory is set to \a dir, and the caption is + set to \a caption. Either of these may be QString::null in which case + the current directory and a default caption will be used respectively. + + Note on Windows that if \a dir is QString::null then the dialog's working + directory will be set to the user's My Documents directory. + + If \a dirOnly is TRUE, then only directories will be shown in + the file dialog; otherwise both directories and files will be shown. + + Under Unix/X11, the normal behavior of the file dialog is to resolve + and follow symlinks. For example, if /usr/tmp is a symlink to /var/tmp, + the file dialog will change to /var/tmp after entering /usr/tmp. + If \a resolveSymlinks is FALSE, the file dialog will treat + symlinks as regular directories. + + Under Windows and Mac OS X, this static function will use the native + file dialog and not a QFileDialog, unless the style of the application + is set to something other than the native style. (Note that on Windows the + dialog will spin a blocking modal event loop that will not dispatch any + QTimers and if parent is not 0 then it will position the dialog just under + the parent's titlebar). + + \sa getOpenFileName(), getOpenFileNames(), getSaveFileName() +*/ + +QString QFileDialog::getExistingDirectory( const QString & dir, + QWidget *parent, + const char* name, + const QString& caption, + bool dirOnly, + bool resolveSymlinks) +{ + bool save_qt_resolve_symlinks = qt_resolve_symlinks; + qt_resolve_symlinks = resolveSymlinks; + + makeVariables(); + QString wd; + if ( workingDirectory ) + wd = *workingDirectory; + +#if defined(Q_WS_WIN) + QString initialDir; + if ( !dir.isEmpty() ) { + QUrlOperator u( dir ); + if ( QFileInfo( u.path() ).isDir() ) + initialDir = dir; + } else + initialDir = QString::null; + if ( qt_use_native_dialogs && qApp->style().styleHint( QStyle::SH_GUIStyle ) == WindowsStyle && dirOnly ) + return winGetExistingDirectory( initialDir, parent, name, caption ); +#endif +#if defined(Q_WS_MAC) + QString *initialDir = 0; + if (!dir.isEmpty()) { + QUrlOperator u(dir); + if (QFileInfo(u.path()).isDir()) + initialDir = (QString *)&dir; + } + if( qt_use_native_dialogs && (qApp->style().inherits(QMAC_DEFAULT_STYLE) + || qApp->style().inherits("QMacStyle"))) + return qt_mac_precomposeFileName(macGetOpenFileNames("", initialDir, parent, name, + caption, 0, FALSE, TRUE).first()); +#endif + + QFileDialog *dlg = new QFileDialog( parent, name ? name : "qt_filedlg_ged", TRUE ); + + Q_CHECK_PTR( dlg ); +#ifndef QT_NO_WIDGET_TOPEXTRA + if ( !caption.isNull() ) + dlg->setCaption( caption ); + else + dlg->setCaption( QFileDialog::tr("Find Directory") ); +#endif + + dlg->setMode( dirOnly ? DirectoryOnly : Directory ); + + dlg->d->types->clear(); + dlg->d->types->insertItem( QFileDialog::tr("Directories") ); + dlg->d->types->setEnabled( FALSE ); + + QString dir_( dir ); + dir_ = dir_.simplifyWhiteSpace(); + if ( dir_.isEmpty() && !wd.isEmpty() ) + dir_ = wd; + QUrlOperator u( dir_ ); + if ( u.isLocalFile() ) { + if ( !dir_.isEmpty() ) { + QFileInfo f( u.path() ); + if ( f.exists() ) + if ( f.isDir() ) { + dlg->setDir( dir_ ); + wd = dir_; + } + } else if ( !wd.isEmpty() ) { + QUrl tempUrl( wd ); + QFileInfo f( tempUrl.path() ); + if ( f.isDir() ) { + dlg->setDir( wd ); + } + } else { + QString theDir = dir_; + if ( theDir.isEmpty() ) { + theDir = ::toRootIfNotExists( QDir::currentDirPath() ); + } if ( !theDir.isEmpty() ) { + QUrl tempUrl( theDir ); + QFileInfo f( tempUrl.path() ); + if ( f.isDir() ) { + wd = theDir; + dlg->setDir( theDir ); + } + } + } + } else { + dlg->setUrl( dir_ ); + } + + QString result; + dlg->setSelection( dlg->d->url.toString() ); + + if ( dlg->exec() == QDialog::Accepted ) { + result = dlg->selectedFile(); + wd = result; + } + delete dlg; + + if ( !result.isEmpty() && result.right( 1 ) != "/" ) + result += "/"; + + qt_resolve_symlinks = save_qt_resolve_symlinks; + + return result; +} + + +/*! + \property QFileDialog::mode + \brief the file dialog's mode + + The default mode is \c ExistingFile. +*/ + +void QFileDialog::setMode( Mode newMode ) +{ + if ( d->mode != newMode ) { + d->mode = newMode; + QString sel = d->currentFileName; + int maxnamelen = 255; // _POSIX_MAX_PATH + if ( isDirectoryMode( newMode ) ) { + files->setSelectionMode( QListView::Single ); + d->moreFiles->setSelectionMode( QListBox::Single ); + if ( sel.isNull() ) + sel = QString::fromLatin1("."); + d->types->setEnabled( FALSE ); + } else if ( newMode == ExistingFiles ) { + maxnamelen = INT_MAX; + files->setSelectionMode( QListView::Extended ); + d->moreFiles->setSelectionMode( QListBox::Extended ); + d->types->setEnabled( TRUE ); + } else { + files->setSelectionMode( QListView::Single ); + d->moreFiles->setSelectionMode( QListBox::Single ); + d->types->setEnabled( TRUE ); + } + nameEdit->setMaxLength(maxnamelen); + rereadDir(); + QUrlInfo f( d->url, "." ); + trySetSelection( f.isDir(), d->url, FALSE ); + } + + QString okt; + bool changeFilters = FALSE; + if ( mode() == AnyFile ) { + okt = tr("&Save"); + d->fileL->setText( tr("File &name:") ); + if ( d->types->count() == 1 ) { + d->types->setCurrentItem( 0 ); + if ( d->types->currentText() == "Directories" ) { + changeFilters = TRUE; + } + } + } + else if ( mode() == Directory || mode() == DirectoryOnly ) { + okt = tr("&OK"); + d->fileL->setText( tr("Directory:") ); + d->types->clear(); + d->types->insertItem( tr("Directories") ); + } + else { + okt = tr("&Open"); + d->fileL->setText( tr("File &name:") ); + if ( d->types->count() == 1 ) { + d->types->setCurrentItem( 0 ); + if ( d->types->currentText() == "Directories" ) { + changeFilters = TRUE; + } + } + } + + if ( changeFilters ) { + d->types->clear(); + d->types->insertItem( tr("All Files (*)") ); + } + + okB->setText( okt ); +} + +QFileDialog::Mode QFileDialog::mode() const +{ + return d->mode; +} + +/*! \reimp +*/ + +void QFileDialog::done( int i ) +{ + if ( i == QDialog::Accepted && (d->mode == ExistingFile || d->mode == ExistingFiles) ) { + QStringList selection = selectedFiles(); + for ( uint f = 0; f < selection.count(); f++ ) { + QString file = selection[f]; + if ( file.isNull() ) + continue; + if ( d->url.isLocalFile() && !QFile::exists( file ) ) { + QMessageBox::information( this, tr("Error"), + tr("%1\nFile not found.\nCheck path and filename.").arg( file ) ); + return; + } + } + } + QDialog::done( i ); +} + +/*! + \property QFileDialog::viewMode + + \brief the file dialog's view mode + + If you set the view mode to be \e Detail (the default), then you + will see the file's details, such as the size of the file and the + date the file was last modified in addition to the file's name. + + If you set the view mode to be \e List, then you will just + see a list of the files and folders. + + See \l QFileDialog::ViewMode +*/ + + +QFileDialog::ViewMode QFileDialog::viewMode() const +{ + if ( detailViewMode ) + return Detail; + else + return List; +} + +void QFileDialog::setViewMode( ViewMode m ) +{ + if ( m == Detail ) { + detailViewMode = TRUE; + d->stack->raiseWidget( files ); + d->detailView->setOn( TRUE ); + d->mcView->setOn( FALSE ); + } else if ( m == List ) { + detailViewMode = FALSE; + d->stack->raiseWidget( d->moreFiles ); + d->detailView->setOn( FALSE ); + d->mcView->setOn( TRUE ); + } +} + + +/*! + \property QFileDialog::previewMode + + \brief the preview mode for the file dialog + + If you set the mode to be a mode other than \e NoPreview, you must + use setInfoPreview() or setContentsPreview() to set the dialog's + preview widget to your preview widget and enable the preview + widget(s) with setInfoPreviewEnabled() or + setContentsPreviewEnabled(). + + \sa infoPreview, contentsPreview, viewMode +*/ + +void QFileDialog::setPreviewMode( PreviewMode m ) +{ + if ( m == NoPreview ) { + d->previewInfo->setOn( FALSE ); + d->previewContents->setOn( FALSE ); + } else if ( m == Info && d->infoPreview ) { + d->previewInfo->setOn( TRUE ); + d->previewContents->setOn( FALSE ); + changeMode( d->modeButtons->id( d->previewInfo ) ); + } else if ( m == Contents && d->contentsPreview ) { + d->previewInfo->setOn( FALSE ); + d->previewContents->setOn( TRUE ); + changeMode( d->modeButtons->id( d->previewContents ) ); + } +} +QFileDialog::PreviewMode QFileDialog::previewMode() const +{ + if ( d->infoPreview && d->infoPreviewWidget->isVisible() ) + return Info; + else if ( d->contentsPreview && d->contentsPreviewWidget->isVisible() ) + return Contents; + + return NoPreview; +} + + +/*! + Adds the specified widgets to the bottom of the file dialog. The + label \a l is placed underneath the "file name" and the "file types" + labels. The widget \a w is placed underneath the file types combobox. + The button \a b is placed underneath the Cancel pushbutton. + + \code + MyFileDialog::MyFileDialog( QWidget* parent, const char* name ) : + QFileDialog( parent, name ) + { + QLabel* label = new QLabel( "Added widgets", this ); + QLineEdit* lineedit = new QLineEdit( this ); + QPushButton* pushbutton = new QPushButton( this ); + + addWidgets( label, lineedit, pushbutton ); + } + \endcode + + If you don't want to have one of the widgets added, pass 0 in that + widget's position. + + Every time you call this function, a new row of widgets will be added + to the bottom of the file dialog. + + \sa addToolButton(), addLeftWidget(), addRightWidget() +*/ + +void QFileDialog::addWidgets( QLabel * l, QWidget * w, QPushButton * b ) +{ + if ( !l && !w && !b ) + return; + + d->geometryDirty = TRUE; + + QHBoxLayout *lay = new QHBoxLayout(); + d->extraWidgetsLayouts.append( lay ); + d->topLevelLayout->addLayout( lay ); + + if ( !l ) + l = new QLabel( this, "qt_intern_lbl" ); + d->extraLabels.append( l ); + lay->addWidget( l ); + + if ( !w ) + w = new QWidget( this, "qt_intern_widget" ); + d->extraWidgets.append( w ); + lay->addWidget( w ); + lay->addSpacing( 15 ); + + if ( b ) { + d->extraButtons.append( b ); + lay->addWidget( b ); + } else { + QWidget *wid = new QWidget( this, "qt_extrabuttons_widget" ); + d->extraButtons.append( wid ); + lay->addWidget( wid ); + } + + updateGeometries(); +} + +/*! + Adds the tool button \a b to the row of tool buttons at the top of the + file dialog. The button is appended to the right of + this row. If \a separator is TRUE, a small space is inserted between the + last button of the row and the new button \a b. + + \sa addWidgets(), addLeftWidget(), addRightWidget() +*/ + +void QFileDialog::addToolButton( QButton *b, bool separator ) +{ + if ( !b || !d->buttonLayout ) + return; + + d->geometryDirty = TRUE; + + d->toolButtons.append( b ); + if ( separator ) + d->buttonLayout->addSpacing( 8 ); + d->buttonLayout->addWidget( b ); + + updateGeometries(); +} + +/*! + Adds the widget \a w to the left-hand side of the file dialog. + + \sa addRightWidget(), addWidgets(), addToolButton() +*/ + +void QFileDialog::addLeftWidget( QWidget *w ) +{ + if ( !w ) + return; + d->geometryDirty = TRUE; + + d->leftLayout->addWidget( w ); + d->leftLayout->addSpacing( 5 ); + + updateGeometries(); +} + +/*! + Adds the widget \a w to the right-hand side of the file dialog. + + \sa addLeftWidget(), addWidgets(), addToolButton() +*/ + +void QFileDialog::addRightWidget( QWidget *w ) +{ + if ( !w ) + return; + d->geometryDirty = TRUE; + + d->rightLayout->addSpacing( 5 ); + d->rightLayout->addWidget( w ); + + updateGeometries(); +} + +/*! \reimp */ + +void QFileDialog::keyPressEvent( QKeyEvent * ke ) +{ + if ( !d->ignoreNextKeyPress && + ke && ( ke->key() == Key_Enter || + ke->key() == Key_Return ) ) { + ke->ignore(); + if ( d->paths->hasFocus() ) { + ke->accept(); + if ( d->url == QUrl(d->paths->currentText()) ) + nameEdit->setFocus(); + } else if ( d->types->hasFocus() ) { + ke->accept(); + // ### is there a suitable condition for this? only valid + // wildcards? + nameEdit->setFocus(); + } else if ( nameEdit->hasFocus() ) { + if ( d->currentFileName.isNull() ) { + // maybe change directory + QUrlInfo i( d->url, nameEdit->text() ); + if ( i.isDir() ) { + nameEdit->setText( QString::fromLatin1("") ); + setDir( QUrlOperator( d->url, QFileDialogPrivate::encodeFileName(i.name()) ) ); + } + ke->accept(); + } else if ( mode() == ExistingFiles ) { + QUrlInfo i( d->url, nameEdit->text() ); + if ( i.isFile() ) { + QListViewItem * i = files->firstChild(); + while ( i && nameEdit->text() != i->text( 0 ) ) + i = i->nextSibling(); + if ( i ) + files->setSelected( i, TRUE ); + else + ke->accept(); // strangely, means to ignore that event + } + } + } else if ( files->hasFocus() || d->moreFiles->hasFocus() ) { + ke->accept(); + } + } else if ( ke->key() == Key_Escape ) { + ke->ignore(); + } + + d->ignoreNextKeyPress = FALSE; + + if ( !ke->isAccepted() ) { + QDialog::keyPressEvent( ke ); + } +} + + +/*! \class QFileIconProvider qfiledialog.h + + \brief The QFileIconProvider class provides icons for QFileDialog to + use. + + \ingroup misc + + By default QFileIconProvider is not used, but any application or + library can subclass it, reimplement pixmap() to return a suitable + icon, and make all QFileDialog objects use it by calling the static + function QFileDialog::setIconProvider(). + + It is advisable to make all the icons that QFileIconProvider returns be + the same size or at least the same width. This makes the list view + look much better. + + \sa QFileDialog +*/ + + +/*! Constructs an empty file icon provider called \a name, with the + parent \a parent. +*/ + +QFileIconProvider::QFileIconProvider( QObject * parent, const char* name ) + : QObject( parent, name ) +{ + // nothing necessary +} + + +/*! + Returns a pointer to a pixmap that should be used to + signify the file with the information \a info. + + If pixmap() returns 0, QFileDialog draws the default pixmap. + + The default implementation returns particular icons for files, directories, + link-files and link-directories. It returns a blank "icon" for other types. + + If you return a pixmap here, it should measure 16x16 pixels. +*/ + +const QPixmap * QFileIconProvider::pixmap( const QFileInfo & info ) +{ + if ( info.isSymLink() ) { + if ( info.isFile() ) + return symLinkFileIcon; + else + return symLinkDirIcon; + } else if ( info.isDir() ) { + return closedFolderIcon; + } else if ( info.isFile() ) { + return fileIcon; + } else { + return fifteenTransparentPixels; + } +} + +/*! + Sets the QFileIconProvider used by the file dialog to \a provider. + + The default is that there is no QFileIconProvider and QFileDialog + just draws a folder icon next to each directory and nothing next + to files. + + \sa QFileIconProvider, iconProvider() +*/ + +void QFileDialog::setIconProvider( QFileIconProvider * provider ) +{ + fileIconProvider = provider; +} + + +/*! + Returns a pointer to the icon provider currently set on the file dialog. + By default there is no icon provider, and this function returns 0. + + \sa setIconProvider(), QFileIconProvider +*/ + +QFileIconProvider * QFileDialog::iconProvider() +{ + return fileIconProvider; +} + + +#if defined(Q_WS_WIN) + +// ### FIXME: this code is duplicated in qdns.cpp +static QString getWindowsRegString( HKEY key, const QString &subKey ) +{ + QString s; + QT_WA( { + char buf[1024]; + DWORD bsz = sizeof(buf); + int r = RegQueryValueEx( key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)buf, &bsz ); + if ( r == ERROR_SUCCESS ) { + s = QString::fromUcs2( (unsigned short *)buf ); + } else if ( r == ERROR_MORE_DATA ) { + char *ptr = new char[bsz+1]; + r = RegQueryValueEx( key, (TCHAR*)subKey.ucs2(), 0, 0, (LPBYTE)ptr, &bsz ); + if ( r == ERROR_SUCCESS ) + s = ptr; + delete [] ptr; + } + } , { + char buf[512]; + DWORD bsz = sizeof(buf); + int r = RegQueryValueExA( key, subKey.local8Bit(), 0, 0, (LPBYTE)buf, &bsz ); + if ( r == ERROR_SUCCESS ) { + s = buf; + } else if ( r == ERROR_MORE_DATA ) { + char *ptr = new char[bsz+1]; + r = RegQueryValueExA( key, subKey.local8Bit(), 0, 0, (LPBYTE)ptr, &bsz ); + if ( r == ERROR_SUCCESS ) + s = ptr; + delete [] ptr; + } + } ); + return s; +} + +static void initPixmap( QPixmap &pm ) +{ + pm.fill( Qt::white ); +} + + +QWindowsIconProvider::QWindowsIconProvider( QObject *parent, const char *name ) + : QFileIconProvider( parent, name ) +{ + pixw = GetSystemMetrics( SM_CXSMICON ); + pixh = GetSystemMetrics( SM_CYSMICON ); + + HKEY k; + HICON si; + int r; + QString s; + UINT res = 0; + + // ---------- get default folder pixmap + const wchar_t iconFolder[] = L"folder\\DefaultIcon"; // workaround for Borland + QT_WA( { + r = RegOpenKeyEx( HKEY_CLASSES_ROOT, + iconFolder, + 0, KEY_READ, &k ); + } , { + r = RegOpenKeyExA( HKEY_CLASSES_ROOT, + "folder\\DefaultIcon", + 0, KEY_READ, &k ); + } ); + resolveLibs(); + if ( r == ERROR_SUCCESS ) { + s = getWindowsRegString( k, QString::null ); + RegCloseKey( k ); + + QStringList lst = QStringList::split( ",", s ); + + if (lst.count() >= 2) { // don't just assume that lst has two entries +#ifndef Q_OS_TEMP + QT_WA( { + res = ptrExtractIconEx( (TCHAR*)lst[ 0 ].simplifyWhiteSpace().ucs2(), + lst[ 1 ].simplifyWhiteSpace().toInt(), + 0, &si, 1 ); + } , { + res = ExtractIconExA( lst[ 0 ].simplifyWhiteSpace().local8Bit(), + lst[ 1 ].simplifyWhiteSpace().toInt(), + 0, &si, 1 ); + } ); +#else + res = (UINT)ExtractIconEx( (TCHAR*)lst[ 0 ].simplifyWhiteSpace().ucs2(), + lst[ 1 ].simplifyWhiteSpace().toInt(), + 0, &si, 1 ); +#endif + } + if ( res ) { + defaultFolder.resize( pixw, pixh ); + initPixmap( defaultFolder ); + QPainter p( &defaultFolder ); + DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL ); + p.end(); + defaultFolder.setMask( defaultFolder.createHeuristicMask() ); + *closedFolderIcon = defaultFolder; + DestroyIcon( si ); + } else { + defaultFolder = *closedFolderIcon; + } + } else { + RegCloseKey( k ); + } + + //------------------------------- get default file pixmap +#ifndef Q_OS_TEMP + QT_WA( { + res = ptrExtractIconEx( L"shell32.dll", + 0, 0, &si, 1 ); + } , { + res = ExtractIconExA( "shell32.dll", + 0, 0, &si, 1 ); + } ); +#else + res = (UINT)ExtractIconEx( L"shell32.dll", + 0, 0, &si, 1 ); +#endif + + if ( res ) { + defaultFile.resize( pixw, pixh ); + initPixmap( defaultFile ); + QPainter p( &defaultFile ); + DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL ); + p.end(); + defaultFile.setMask( defaultFile.createHeuristicMask() ); + *fileIcon = defaultFile; + DestroyIcon( si ); + } else { + defaultFile = *fileIcon; + } + + //------------------------------- get default exe pixmap +#ifndef Q_OS_TEMP + QT_WA( { + res = ptrExtractIconEx( L"shell32.dll", + 2, 0, &si, 1 ); + } , { + res = ExtractIconExA( "shell32.dll", + 2, 0, &si, 1 ); + } ); +#else + res = (UINT)ExtractIconEx( L"ceshell.dll", + 10, 0, &si, 1 ); +#endif + + if ( res ) { + defaultExe.resize( pixw, pixh ); + initPixmap( defaultExe ); + QPainter p( &defaultExe ); + DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL ); + p.end(); + defaultExe.setMask( defaultExe.createHeuristicMask() ); + DestroyIcon( si ); + } else { + defaultExe = *fileIcon; + } +} + +QWindowsIconProvider::~QWindowsIconProvider() +{ + if ( this == fileIconProvider ) + fileIconProvider = 0; +} + +const QPixmap * QWindowsIconProvider::pixmap( const QFileInfo &fi ) +{ + if (fi.isSymLink()) { + QString real = fi.readLink(); + if (!real.isEmpty()) + return pixmap(QFileInfo(real)); + } + + QString ext = fi.extension( FALSE ).upper(); + QString key = ext; + ext.prepend( "." ); + QMap< QString, QPixmap >::Iterator it; + + if ( fi.isDir() ) { + return &defaultFolder; + } else if ( ext != ".EXE" ) { + it = cache.find( key ); + if ( it != cache.end() ) + return &( *it ); + + HKEY k, k2; + int r; + QT_WA( { + r = RegOpenKeyEx( HKEY_CLASSES_ROOT, (TCHAR*)ext.ucs2(), + 0, KEY_READ, &k ); + } , { + r = RegOpenKeyExA( HKEY_CLASSES_ROOT, ext.local8Bit(), + 0, KEY_READ, &k ); + } ); + QString s; + if ( r == ERROR_SUCCESS ) { + s = getWindowsRegString( k, QString::null ); + } else { + cache[ key ] = defaultFile; + RegCloseKey( k ); + return &defaultFile; + } + RegCloseKey( k ); + + QT_WA( { + r = RegOpenKeyEx( HKEY_CLASSES_ROOT, (TCHAR*)QString( s + "\\DefaultIcon" ).ucs2(), + 0, KEY_READ, &k2 ); + } , { + r = RegOpenKeyExA( HKEY_CLASSES_ROOT, QString( s + "\\DefaultIcon" ).local8Bit() , + 0, KEY_READ, &k2 ); + } ); + if ( r == ERROR_SUCCESS ) { + s = getWindowsRegString( k2, QString::null ); + } else { + cache[ key ] = defaultFile; + RegCloseKey( k2 ); + return &defaultFile; + } + RegCloseKey( k2 ); + + QStringList lst = QStringList::split( ",", s ); + + HICON si; + UINT res = 0; + if (lst.count() >= 2) { // don't just assume that lst has two entries + QString filepath = lst[ 0 ].stripWhiteSpace(); + if ( !filepath.isEmpty() ) { + if ( filepath.find("%1") != -1 ) { + filepath = filepath.arg( fi.filePath() ); + if ( ext == ".DLL" ) { + pix = defaultFile; + return &pix; + } + } + if ( filepath[0] == '"' && filepath[(int)filepath.length()-1] == '"' ) + filepath = filepath.mid( 1, filepath.length()-2 ); + + resolveLibs(); +#ifndef Q_OS_TEMP + QT_WA( { + res = ptrExtractIconEx( (TCHAR*)filepath.ucs2(), lst[ 1 ].stripWhiteSpace().toInt(), + 0, &si, 1 ); + } , { + res = ExtractIconExA( filepath.local8Bit(), lst[ 1 ].stripWhiteSpace().toInt(), + 0, &si, 1 ); + } ); +#else + res = (UINT)ExtractIconEx( (TCHAR*)filepath.ucs2(), lst[ 1 ].stripWhiteSpace().toInt(), + 0, &si, 1 ); +#endif + } + } + + if ( res ) { + pix.resize( pixw, pixh ); + initPixmap( pix ); + QPainter p( &pix ); + DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL ); + p.end(); + pix.setMask( pix.createHeuristicMask() ); + DestroyIcon( si ); + } else { + pix = defaultFile; + } + + cache[ key ] = pix; + return &pix; + } else { + HICON si; + UINT res = 0; + if ( !fi.absFilePath().isEmpty() ) { +#ifndef Q_OS_TEMP + QT_WA( { + res = ptrExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), -1, + 0, 0, 1 ); + } , { + res = ExtractIconExA( fi.absFilePath().local8Bit(), -1, + 0, 0, 1 ); + } ); + + if ( res ) { + QT_WA( { + res = ptrExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), res - 1, + 0, &si, 1 ); + } , { + res = ExtractIconExA( fi.absFilePath().local8Bit(), res - 1, + 0, &si, 1 ); + } ); + } +#else + res = (UINT)ExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), -1, + 0, 0, 1 ); + if ( res ) + res = (UINT)ExtractIconEx( (TCHAR*)fi.absFilePath().ucs2(), res - 1, + 0, &si, 1 ); +#endif + + } + + if ( res ) { + pix.resize( pixw, pixh ); + initPixmap( pix ); + QPainter p( &pix ); + DrawIconEx( p.handle(), 0, 0, si, pixw, pixh, 0, 0, DI_NORMAL ); + p.end(); + pix.setMask( pix.createHeuristicMask() ); + DestroyIcon( si ); + } else { + pix = defaultExe; + } + + return &pix; + } + + // can't happen! + return 0; +} +#endif + + + +/*! + \reimp +*/ +bool QFileDialog::eventFilter( QObject * o, QEvent * e ) +{ + if ( e->type() == QEvent::KeyPress && ( (QKeyEvent*)e )->key() == Key_F5 ) { + rereadDir(); + ((QKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == QEvent::KeyPress && ( (QKeyEvent*)e )->key() == Key_F2 && + ( o == files || o == files->viewport() ) ) { + if ( files->isVisible() && files->currentItem() ) { + if ( QUrlInfo( d->url, "." ).isWritable() && files->currentItem()->text( 0 ) != ".." ) { + files->renameItem = files->currentItem(); + files->startRename( TRUE ); + } + } + ((QKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == QEvent::KeyPress && ( (QKeyEvent*)e )->key() == Key_F2 && + ( o == d->moreFiles || o == d->moreFiles->viewport() ) ) { + if ( d->moreFiles->isVisible() && d->moreFiles->currentItem() != -1 ) { + if ( QUrlInfo( d->url, "." ).isWritable() && + d->moreFiles->item( d->moreFiles->currentItem() )->text() != ".." ) { + d->moreFiles->renameItem = d->moreFiles->item( d->moreFiles->currentItem() ); + d->moreFiles->startRename( TRUE ); + } + } + ((QKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == QEvent::KeyPress && d->moreFiles->renaming ) { + d->moreFiles->lined->setFocus(); + QApplication::sendEvent( d->moreFiles->lined, e ); + ((QKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == QEvent::KeyPress && files->renaming ) { + files->lined->setFocus(); + QApplication::sendEvent( files->lined, e ); + ((QKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == QEvent::KeyPress && + ((QKeyEvent *)e)->key() == Key_Backspace && + ( o == files || + o == d->moreFiles || + o == files->viewport() || + o == d->moreFiles->viewport() ) ) { + cdUpClicked(); + ((QKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == QEvent::KeyPress && + ((QKeyEvent *)e)->key() == Key_Delete && + ( o == files || + o == files->viewport() ) ) { + if ( files->currentItem() ) + deleteFile( files->currentItem()->text( 0 ) ); + ((QKeyEvent *)e)->accept(); + return TRUE; + } else if ( e->type() == QEvent::KeyPress && + ((QKeyEvent *)e)->key() == Key_Delete && + ( o == d->moreFiles || + o == d->moreFiles->viewport() ) ) { + int c = d->moreFiles->currentItem(); + if ( c >= 0 ) + deleteFile( d->moreFiles->item( c )->text() ); + ((QKeyEvent *)e)->accept(); + return TRUE; + } else if ( o == files && e->type() == QEvent::FocusOut && files->currentItem() ) { + } else if ( o == files && e->type() == QEvent::KeyPress ) { + QTimer::singleShot( 0, this, SLOT(fixupNameEdit()) ); + } else if ( o == nameEdit && e->type() == QEvent::KeyPress && d->mode != AnyFile ) { + if ( ( nameEdit->cursorPosition() == (int)nameEdit->text().length() || nameEdit->hasSelectedText() ) && + isprint(((QKeyEvent *)e)->ascii()) ) { +#if defined(Q_WS_WIN) + QString nt( nameEdit->text().lower() ); +#else + QString nt( nameEdit->text() ); +#endif + nt.truncate( nameEdit->cursorPosition() ); + nt += (char)(((QKeyEvent *)e)->ascii()); + QListViewItem * i = files->firstChild(); +#if defined(Q_WS_WIN) + while( i && i->text( 0 ).left(nt.length()).lower() != nt ) +#else + while( i && i->text( 0 ).left(nt.length()) != nt ) +#endif + i = i->nextSibling(); + if ( i ) { + nt = i->text( 0 ); + int cp = nameEdit->cursorPosition()+1; + nameEdit->validateAndSet( nt, cp, cp, nt.length() ); + return TRUE; + } + } + } else if ( o == nameEdit && e->type() == QEvent::FocusIn ) { + fileNameEditDone(); + } else if ( d->moreFiles->renaming && o != d->moreFiles->lined && e->type() == QEvent::FocusIn ) { + d->moreFiles->lined->setFocus(); + return TRUE; + } else if ( files->renaming && o != files->lined && e->type() == QEvent::FocusIn ) { + files->lined->setFocus(); + return TRUE; + } else if ( ( o == d->moreFiles || o == d->moreFiles->viewport() ) && + e->type() == QEvent::FocusIn ) { + if ( o == d->moreFiles->viewport() && !d->moreFiles->viewport()->hasFocus() || + o == d->moreFiles && !d->moreFiles->hasFocus() ) + ((QWidget*)o)->setFocus(); + return FALSE; + } + + return QDialog::eventFilter( o, e ); +} + +/*! + Sets the filters used in the file dialog to \a filters. Each group + of filters must be separated by \c{;;} (\e two semi-colons). + + \code + QString types("Image files (*.png *.xpm *.jpg);;" + "Text files (*.txt);;" + "Any files (*)"); + QFileDialog fd = new QFileDialog( this ); + fd->setFilters( types ); + fd->show(); + \endcode + +*/ + +void QFileDialog::setFilters( const QString &filters ) +{ + QStringList lst = makeFiltersList( filters ); + setFilters( lst ); +} + +/*! + \overload + + \a types must be a null-terminated list of strings. + +*/ + +void QFileDialog::setFilters( const char ** types ) +{ + if ( !types || !*types ) + return; + + d->types->clear(); + while( types && *types ) { + d->types->insertItem( QString::fromLatin1(*types) ); + types++; + } + d->types->setCurrentItem( 0 ); + setFilter( d->types->text( 0 ) ); +} + + +/*! \overload void QFileDialog::setFilters( const QStringList & ) +*/ + +void QFileDialog::setFilters( const QStringList & types ) +{ + if ( types.count() < 1 ) + return; + + d->types->clear(); + for ( QStringList::ConstIterator it = types.begin(); it != types.end(); ++it ) + d->types->insertItem( *it ); + d->types->setCurrentItem( 0 ); + setFilter( d->types->text( 0 ) ); +} + +/*! + Adds the filter \a filter to the list of filters and makes it the + current filter. + + \code + QFileDialog* fd = new QFileDialog( this ); + fd->addFilter( "Images (*.png *.jpg *.xpm)" ); + fd->show(); + \endcode + + In the above example, a file dialog is created, and the file filter "Images + (*.png *.jpg *.xpm)" is added and is set as the current filter. The original + filter, "All Files (*)", is still available. + + \sa setFilter(), setFilters() +*/ + +void QFileDialog::addFilter( const QString &filter ) +{ + if ( filter.isEmpty() ) + return; + QString f = filter; + QRegExp r( QString::fromLatin1(qt_file_dialog_filter_reg_exp) ); + int index = r.search( f ); + if ( index >= 0 ) + f = r.cap( 2 ); + for ( int i = 0; i < d->types->count(); ++i ) { + QString f2( d->types->text( i ) ); + int index = r.search( f2 ); + if ( index >= 0 ) + f2 = r.cap( 1 ); + if ( f2 == f ) { + d->types->setCurrentItem( i ); + setFilter( f2 ); + return; + } + } + + d->types->insertItem( filter ); + d->types->setCurrentItem( d->types->count() - 1 ); + setFilter( d->types->text( d->types->count() - 1 ) ); +} + +/*! + Since modeButtons is a top-level widget, it may be destroyed by the + kernel at application exit. Notice if this happens to + avoid double deletion. +*/ + +void QFileDialog::modeButtonsDestroyed() +{ + if ( d ) + d->modeButtons = 0; +} + + +/*! + This is a convenience static function that will return one or more + existing files selected by the user. + + \code + QStringList files = QFileDialog::getOpenFileNames( + "Images (*.png *.xpm *.jpg)", + "/home", + this, + "open files dialog", + "Select one or more files to open" ); + \endcode + + This function creates a modal file dialog called \a name, with + parent \a parent. If \a parent is not 0, the dialog will be shown + centered over the parent. + + The file dialog's working directory will be set to \a dir. If \a + dir includes a file name, the file will be selected. The filter + is set to \a filter so that only those files which match the filter + are shown. The filter selected is set to \a selectedFilter. The parameters + \a dir, \a selectedFilter and \a filter may be QString::null. + + The dialog's caption is set to \a caption. If \a caption is not + specified then a default caption will be used. + + Under Windows and Mac OS X, this static function will use the native + file dialog and not a QFileDialog, unless the style of the application + is set to something other than the native style. (Note that on Windows the + dialog will spin a blocking modal event loop that will not dispatch any + QTimers and if parent is not 0 then it will position the dialog just under + the parent's titlebar). + + Under Unix/X11, the normal behavior of the file dialog is to resolve + and follow symlinks. For example, if /usr/tmp is a symlink to /var/tmp, + the file dialog will change to /var/tmp after entering /usr/tmp. + If \a resolveSymlinks is FALSE, the file dialog will treat + symlinks as regular directories. + + Note that if you want to iterate over the list of files, you should + iterate over a copy, e.g. + \code + QStringList list = files; + QStringList::Iterator it = list.begin(); + while( it != list.end() ) { + myProcessing( *it ); + ++it; + } + \endcode + + \sa getOpenFileName(), getSaveFileName(), getExistingDirectory() +*/ + +QStringList QFileDialog::getOpenFileNames( const QString & filter, + const QString& dir, + QWidget *parent, + const char* name, + const QString& caption, + QString *selectedFilter, + bool resolveSymlinks ) +{ + bool save_qt_resolve_symlinks = qt_resolve_symlinks; + qt_resolve_symlinks = resolveSymlinks; + + QStringList filters; + if ( !filter.isEmpty() ) + filters = makeFiltersList( filter ); + + makeVariables(); + + if ( workingDirectory->isNull() ) + *workingDirectory = ::toRootIfNotExists( QDir::currentDirPath() ); + + if ( !dir.isEmpty() ) { + // #### works only correct for local files + QUrlOperator u( QFileDialogPrivate::encodeFileName(dir) ); + if ( u.isLocalFile() && QFileInfo( u.path() ).isDir() ) { + *workingDirectory = dir; + } else { + *workingDirectory = u.toString(); + } + } + +#if defined(Q_WS_WIN) + if ( qt_use_native_dialogs && qApp->style().styleHint( QStyle::SH_GUIStyle ) == WindowsStyle ) + return winGetOpenFileNames( filter, workingDirectory, parent, name, caption, selectedFilter ); +#elif defined(Q_WS_MAC) + if (qt_use_native_dialogs && (qApp->style().inherits(QMAC_DEFAULT_STYLE) + || qApp->style().inherits("QMacStyle"))) { + QStringList sl = macGetOpenFileNames(filter, dir.isEmpty() ? 0 : workingDirectory, parent, + name, caption, selectedFilter); + QStringList::iterator it = sl.begin(); + while (it != sl.end()) { + *it = qt_mac_precomposeFileName(*it); + ++it; + } + return sl; + } +#endif + + QFileDialog *dlg = new QFileDialog( *workingDirectory, QString::null, parent, name ? name : "qt_filedlg_gofns", TRUE ); + + Q_CHECK_PTR( dlg ); +#ifndef QT_NO_WIDGET_TOPEXTRA + if ( !caption.isNull() ) + dlg->setCaption( caption ); + else + dlg->setCaption( QFileDialog::tr("Open") ); +#endif + + dlg->setFilters( filters ); + if ( selectedFilter ) + dlg->setFilter( *selectedFilter ); + dlg->setMode( QFileDialog::ExistingFiles ); + QString result; + QStringList lst; + if ( dlg->exec() == QDialog::Accepted ) { + lst = dlg->selectedFiles(); + *workingDirectory = dlg->d->url; + if ( selectedFilter ) + *selectedFilter = dlg->selectedFilter(); + } + delete dlg; + + qt_resolve_symlinks = save_qt_resolve_symlinks; + return lst; +} + +/*! Updates the line edit to match the speed-key usage in QListView. */ + +void QFileDialog::fixupNameEdit() +{ + if ( files->currentItem() ) { + if ( ( (QFileDialogPrivate::File*)files->currentItem() )->info.isFile() ) + nameEdit->setText( files->currentItem()->text( 0 ) ); + } +} + +/*! + Returns the URL of the current working directory in the file dialog. + + \sa setUrl() +*/ + +QUrl QFileDialog::url() const +{ + return d->url; +} + +static bool isRoot( const QUrl &u ) +{ +#if defined(Q_OS_MAC9) + QString p = QDir::convertSeparators(u.path()); + if(p.contains(':') == 1) + return TRUE; +#elif defined(Q_OS_UNIX) + if ( u.path() == "/" ) + return TRUE; +#elif defined(Q_OS_WIN32) + QString p = u.path(); + if ( p.length() == 3 && + p.right( 2 ) == ":/" ) + return TRUE; + if ( p[ 0 ] == '/' && p[ 1 ] == '/' ) { + int slashes = p.contains( '/' ); + if ( slashes <= 3 ) + return TRUE; + if ( slashes == 4 && p[ (int)p.length() - 1 ] == '/' ) + return TRUE; + } +#else +#if defined(Q_CC_GNU) +#warning "case not covered.." +#endif +#endif + + if ( !u.isLocalFile() && u.path() == "/" ) + return TRUE; + + return FALSE; +} + +void QFileDialog::urlStart( QNetworkOperation *op ) +{ + if ( !op ) + return; + +#if defined(Q_WS_WIN) + qt_ntfs_permission_lookup--; +#endif + if ( op->operation() == QNetworkProtocol::OpListChildren ) { +#ifndef QT_NO_CURSOR + if ( !d->cursorOverride ) { + QApplication::setOverrideCursor( QCursor( Qt::WaitCursor ) ); + d->cursorOverride = TRUE; + } +#endif + if ( isRoot( d->url ) ) + d->cdToParent->setEnabled( FALSE ); + else + d->cdToParent->setEnabled( TRUE ); + d->mimeTypeTimer->stop(); + d->sortedList.clear(); + d->pendingItems.clear(); + d->moreFiles->clearSelection(); + files->clearSelection(); + d->moreFiles->clear(); + files->clear(); + files->setSorting( -1 ); + + QString s = d->url.toString( FALSE, FALSE ); + bool found = FALSE; + for ( int i = 0; i < d->paths->count(); ++i ) { +#if defined(Q_WS_WIN) + if ( d->paths->text( i ).lower() == s.lower() ) { +#else + if ( d->paths->text( i ) == s ) { +#endif + found = TRUE; + d->paths->setCurrentItem( i ); + break; + } + } + if ( !found ) { + d->paths->insertItem( *openFolderIcon, s, -1 ); + d->paths->setCurrentItem( d->paths->count() - 1 ); + } + d->last = 0; + d->hadDotDot = FALSE; + + if ( d->goBack && d->history.last() != d->url.toString() ) { + d->history.append( d->url.toString() ); + if ( d->history.count() > 1 ) + d->goBack->setEnabled( TRUE ); + } + } +} + +void QFileDialog::urlFinished( QNetworkOperation *op ) +{ + if ( !op ) + return; + +#ifndef QT_NO_CURSOR + if ( op->operation() == QNetworkProtocol::OpListChildren && + d->cursorOverride ) { + QApplication::restoreOverrideCursor(); + d->cursorOverride = FALSE; + } +#endif + + if ( op->state() == QNetworkProtocol::StFailed ) { + if ( d->paths->hasFocus() ) + d->ignoreNextKeyPress = TRUE; + + if ( d->progressDia ) { + d->ignoreStop = TRUE; + d->progressDia->close(); + delete d->progressDia; + d->progressDia = 0; + } + + int ecode = op->errorCode(); + QMessageBox::critical( this, tr( "Error" ), op->protocolDetail() ); + + if ( ecode == QNetworkProtocol::ErrListChildren || ecode == QNetworkProtocol::ErrParse || + ecode == QNetworkProtocol::ErrUnknownProtocol || ecode == QNetworkProtocol::ErrLoginIncorrect || + ecode == QNetworkProtocol::ErrValid || ecode == QNetworkProtocol::ErrHostNotFound || + ecode == QNetworkProtocol::ErrFileNotExisting ) { + if (d->url != d->oldUrl) { + d->url = d->oldUrl; + rereadDir(); + } + } else { + // another error happened, no need to go back to last dir + } + } else if ( op->operation() == QNetworkProtocol::OpListChildren && + op == d->currListChildren ) { + if ( !d->hadDotDot && !isRoot( d->url ) ) { + bool ok = TRUE; +#if defined(Q_WS_WIN) + if ( d->url.path().left( 2 ) == "//" ) + ok = FALSE; +#endif + if ( ok ) { + QUrlInfo ui( d->url, ".." ); + ui.setName( ".." ); + ui.setDir( TRUE ); + ui.setFile( FALSE ); + ui.setSymLink( FALSE ); + ui.setSize( 0 ); + QValueList<QUrlInfo> lst; + lst << ui; + insertEntry( lst, 0 ); + } + } + resortDir(); + } else if ( op->operation() == QNetworkProtocol::OpGet ) { + } else if ( op->operation() == QNetworkProtocol::OpPut ) { + rereadDir(); + if ( d->progressDia ) { + d->ignoreStop = TRUE; + d->progressDia->close(); + } + delete d->progressDia; + d->progressDia = 0; + } + +#if defined(Q_WS_WIN) + if (d->oldPermissionLookup != qt_ntfs_permission_lookup) + qt_ntfs_permission_lookup++; +#endif +} + +void QFileDialog::dataTransferProgress( int bytesDone, int bytesTotal, QNetworkOperation *op ) +{ + if ( !op ) + return; + + QString label; + QUrl u( op->arg( 0 ) ); + if ( u.isLocalFile() ) { + label = u.path(); + } else { + label = QString( "%1 (on %2)" ); + label = label.arg( u.path() ).arg( u.host() ); + } + + if ( !d->progressDia ) { + if ( bytesDone < bytesTotal) { + d->ignoreStop = FALSE; + d->progressDia = new QFDProgressDialog( this, label, bytesTotal ); + connect( d->progressDia, SIGNAL( cancelled() ), + this, SLOT( stopCopy() ) ); + d->progressDia->show(); + } else + return; + } + + if ( d->progressDia ) { + if ( op->operation() == QNetworkProtocol::OpGet ) { + if ( d->progressDia ) { + d->progressDia->setReadProgress( bytesDone ); + } + } else if ( op->operation() == QNetworkProtocol::OpPut ) { + if ( d->progressDia ) { + d->progressDia->setWriteLabel( label ); + d->progressDia->setWriteProgress( bytesDone ); + } + } else { + return; + } + } +} + +void QFileDialog::insertEntry( const QValueList<QUrlInfo> &lst, QNetworkOperation *op ) +{ + if ( op && op->operation() == QNetworkProtocol::OpListChildren && + op != d->currListChildren ) + return; + QValueList<QUrlInfo>::ConstIterator it = lst.begin(); + for ( ; it != lst.end(); ++it ) { + const QUrlInfo &inf = *it; + if ( d->mode == DirectoryOnly && !inf.isDir() ) + continue; + if ( inf.name() == ".." ) { + d->hadDotDot = TRUE; + if ( isRoot( d->url ) ) + continue; +#if defined(Q_WS_WIN) + if ( d->url.path().left( 2 ) == "//" ) + continue; +#endif + } else if ( inf.name() == "." ) + continue; + +#if defined(Q_WS_WIN) + // Workaround a Windows bug, '..' is apparantly hidden in directories + // that are one level away from root + if ( !bShowHiddenFiles && inf.name() != ".." ) { + if ( d->url.isLocalFile() ) { + QString file = d->url.path(); + if ( !file.endsWith( "/" ) ) + file.append( "/" ); + file += inf.name(); + QT_WA( { + if ( GetFileAttributesW( (TCHAR*)file.ucs2() ) & FILE_ATTRIBUTE_HIDDEN ) + continue; + } , { + if ( GetFileAttributesA( file.local8Bit() ) & FILE_ATTRIBUTE_HIDDEN ) + continue; + } ); + } else { + if ( inf.name() != ".." && inf.name()[0] == QChar('.') ) + continue; + } + } +#else + if ( !bShowHiddenFiles && inf.name() != ".." ) { + if ( inf.name()[ 0 ] == QChar( '.' ) ) + continue; + } +#endif + if ( !d->url.isLocalFile() ) { + QFileDialogPrivate::File * i = 0; + QFileDialogPrivate::MCItem *i2 = 0; + i = new QFileDialogPrivate::File( d, &inf, files ); + i2 = new QFileDialogPrivate::MCItem( d->moreFiles, i ); + + if ( d->mode == ExistingFiles && inf.isDir() || + ( isDirectoryMode( d->mode ) && inf.isFile() ) ) { + i->setSelectable( FALSE ); + i2->setSelectable( FALSE ); + } + + i->i = i2; + } + + d->sortedList.append( new QUrlInfo( inf ) ); + } +} + +void QFileDialog::removeEntry( QNetworkOperation *op ) +{ + if ( !op ) + return; + + QUrlInfo *i = 0; + QListViewItemIterator it( files ); + bool ok1 = FALSE, ok2 = FALSE; + for ( i = d->sortedList.first(); it.current(); ++it, i = d->sortedList.next() ) { + QString encName = QFileDialogPrivate::encodeFileName( + ( (QFileDialogPrivate::File*)it.current() )->info.name() ); + if ( encName == op->arg( 0 ) ) { + d->pendingItems.removeRef( (QFileDialogPrivate::File*)it.current() ); + delete ( (QFileDialogPrivate::File*)it.current() )->i; + delete it.current(); + ok1 = TRUE; + } + if ( i && i->name() == op->arg( 0 ) ) { + d->sortedList.removeRef( i ); + i = d->sortedList.prev(); + ok2 = TRUE; + } + if ( ok1 && ok2 ) + break; + } +} + +void QFileDialog::itemChanged( QNetworkOperation *op ) +{ + if ( !op ) + return; + + QUrlInfo *i = 0; + QListViewItemIterator it1( files ); + bool ok1 = FALSE, ok2 = FALSE; + // first check whether the new file replaces an existing file. + for ( i = d->sortedList.first(); it1.current(); ++it1, i = d->sortedList.next() ) { + if ( ( (QFileDialogPrivate::File*)it1.current() )->info.name() == op->arg( 1 ) ) { + delete ( (QFileDialogPrivate::File*)it1.current() )->i; + delete it1.current(); + ok1 = TRUE; + } + if ( i && i->name() == op->arg( 1 ) ) { + d->sortedList.removeRef( i ); + i = d->sortedList.prev(); + ok2 = TRUE; + } + if ( ok1 && ok2 ) + break; + } + + i = 0; + QListViewItemIterator it( files ); + ok1 = FALSE; + ok2 = FALSE; + for ( i = d->sortedList.first(); it.current(); ++it, i = d->sortedList.next() ) { + if ( ( (QFileDialogPrivate::File*)it.current() )->info.name() == op->arg( 0 ) ) { + ( (QFileDialogPrivate::File*)it.current() )->info.setName( op->arg( 1 ) ); + ok1 = TRUE; + } + if ( i && i->name() == op->arg( 0 ) ) { + i->setName( op->arg( 1 ) ); + ok2 = TRUE; + } + if ( ok1 && ok2 ) + break; + } + + resortDir(); +} + +/*! + \property QFileDialog::infoPreview + + \brief whether the file dialog can provide preview information about + the currently selected file + + The default is FALSE. +*/ +bool QFileDialog::isInfoPreviewEnabled() const +{ + return d->infoPreview; +} + +void QFileDialog::setInfoPreviewEnabled( bool info ) +{ + if ( info == d->infoPreview ) + return; + d->geometryDirty = TRUE; + d->infoPreview = info; + updateGeometries(); +} + + +/*! + \property QFileDialog::contentsPreview + + \brief whether the file dialog can provide a contents preview of the + currently selected file + + The default is FALSE. + + \sa setContentsPreview() setInfoPreviewEnabled() +*/ +// ### improve the above documentation: how is the preview done, how can I add +// support for customized preview, etc. + +bool QFileDialog::isContentsPreviewEnabled() const +{ + return d->contentsPreview; +} + +void QFileDialog::setContentsPreviewEnabled( bool contents ) +{ + if ( contents == d->contentsPreview ) + return; + d->geometryDirty = TRUE; + d->contentsPreview = contents; + updateGeometries(); +} + + +/*! + Sets the widget to be used for displaying information about the file + to the widget \a w and a preview of that information to the + QFilePreview \a preview. + + Normally you would create a preview widget that derives from both QWidget and + QFilePreview, so you should pass the same widget twice. If you + don't, you must remember to delete the preview object in order to + avoid memory leaks. + + \code + class Preview : public QLabel, public QFilePreview + { + public: + Preview( QWidget *parent=0 ) : QLabel( parent ) {} + + void previewUrl( const QUrl &u ) + { + QString path = u.path(); + QPixmap pix( path ); + if ( pix.isNull() ) + setText( "This is not a pixmap" ); + else + setText( "This is a pixmap" ); + } + }; + + //... + + int main( int argc, char** argv ) + { + Preview* p = new Preview; + + QFileDialog* fd = new QFileDialog( this ); + fd->setInfoPreviewEnabled( TRUE ); + fd->setInfoPreview( p, p ); + fd->setPreviewMode( QFileDialog::Info ); + fd->show(); + } + + \endcode + + \sa setContentsPreview(), setInfoPreviewEnabled(), setPreviewMode() + +*/ + +void QFileDialog::setInfoPreview( QWidget *w, QFilePreview *preview ) +{ + if ( !w || !preview ) + return; + + if ( d->infoPreviewWidget ) { + d->preview->removeWidget( d->infoPreviewWidget ); + delete d->infoPreviewWidget; + } + d->infoPreviewWidget = w; + d->infoPreviewer = preview; + w->reparent( d->preview, 0, QPoint( 0, 0 ) ); +} + +/*! + Sets the widget to be used for displaying the contents of the file + to the widget \a w and a preview of those contents to the + QFilePreview \a preview. + + Normally you would create a preview widget that derives from both QWidget and + QFilePreview, so you should pass the same widget twice. If you + don't, you must remember to delete the preview object in order to + avoid memory leaks. + + \code + class Preview : public QLabel, public QFilePreview + { + public: + Preview( QWidget *parent=0 ) : QLabel( parent ) {} + + void previewUrl( const QUrl &u ) + { + QString path = u.path(); + QPixmap pix( path ); + if ( pix.isNull() ) + setText( "This is not a pixmap" ); + else + setPixmap( pix ); + } + }; + + //... + + int main( int argc, char** argv ) + { + Preview* p = new Preview; + + QFileDialog* fd = new QFileDialog( this ); + fd->setContentsPreviewEnabled( TRUE ); + fd->setContentsPreview( p, p ); + fd->setPreviewMode( QFileDialog::Contents ); + fd->show(); + } + \endcode + + \sa setContentsPreviewEnabled(), setInfoPreview(), setPreviewMode() +*/ + +void QFileDialog::setContentsPreview( QWidget *w, QFilePreview *preview ) +{ + if ( !w || !preview ) + return; + + if ( d->contentsPreviewWidget ) { + d->preview->removeWidget( d->contentsPreviewWidget ); + delete d->contentsPreviewWidget; + } + d->contentsPreviewWidget = w; + d->contentsPreviewer = preview; + w->reparent( d->preview, 0, QPoint( 0, 0 ) ); +} + +/*! + Re-sorts the displayed directory. + + \sa rereadDir() +*/ + +void QFileDialog::resortDir() +{ + d->mimeTypeTimer->stop(); + d->pendingItems.clear(); + + QFileDialogPrivate::File *item = 0; + QFileDialogPrivate::MCItem *item2 = 0; + + d->sortedList.sort(); + + if ( files->childCount() > 0 || d->moreFiles->count() > 0 ) { + d->moreFiles->clear(); + files->clear(); + d->last = 0; + files->setSorting( -1 ); + } + + QUrlInfo *i = sortAscending ? d->sortedList.first() : d->sortedList.last(); + for ( ; i; i = sortAscending ? d->sortedList.next() : d->sortedList.prev() ) { + item = new QFileDialogPrivate::File( d, i, files ); + item2 = new QFileDialogPrivate::MCItem( d->moreFiles, item, item2 ); + item->i = item2; + d->pendingItems.append( item ); + if ( d->mode == ExistingFiles && item->info.isDir() || + ( isDirectoryMode( d->mode ) && item->info.isFile() ) ) { + item->setSelectable( FALSE ); + item2->setSelectable( FALSE ); + } + } + + // ##### As the QFileIconProvider only support QFileInfo and no + // QUrlInfo it can be only used for local files at the moment. In + // 3.0 we have to change the API of QFileIconProvider to work on + // QUrlInfo so that also remote filesystems can be show mime-type + // specific icons. + if ( d->url.isLocalFile() ) + d->mimeTypeTimer->start( 0 ); +} + +/*! + Stops the current copy operation. +*/ + +void QFileDialog::stopCopy() +{ + if ( d->ignoreStop ) + return; + + d->url.blockSignals( TRUE ); + d->url.stop(); + if ( d->progressDia ) { + d->ignoreStop = TRUE; + QTimer::singleShot( 100, this, SLOT( removeProgressDia() ) ); + } + d->url.blockSignals( FALSE ); +} + +/*! + \internal +*/ + +void QFileDialog::removeProgressDia() +{ + if ( d->progressDia ) + delete d->progressDia; + d->progressDia = 0; +} + +/*! + \internal +*/ + +void QFileDialog::doMimeTypeLookup() +{ + if ( !iconProvider() ) { + d->pendingItems.clear(); + d->mimeTypeTimer->stop(); + return; + } + + d->mimeTypeTimer->stop(); + if ( d->pendingItems.count() == 0 ) { + return; + } + + QRect r; + QFileDialogPrivate::File *item = d->pendingItems.first(); + if ( item ) { + QFileInfo fi; + if ( d->url.isLocalFile() ) { + fi.setFile( QUrl( d->url.path(), QFileDialogPrivate::encodeFileName( item->info.name() ) ).path( FALSE ) ); + } else + fi.setFile( item->info.name() ); // ##### + const QPixmap *p = iconProvider()->pixmap( fi ); + if ( p && p != item->pixmap( 0 ) && + ( !item->pixmap( 0 ) || p->serialNumber() != item->pixmap( 0 )->serialNumber() ) && + p != fifteenTransparentPixels ) { + item->hasMimePixmap = TRUE; + + // evil hack to avoid much too much repaints! + QGuardedPtr<QFileDialog> that( this ); // this may be deleted by an event handler + qApp->processEvents(); + if ( that.isNull() ) + return; + files->setUpdatesEnabled( FALSE ); + files->viewport()->setUpdatesEnabled( FALSE ); + if ( item != d->pendingItems.first() ) + return; + item->setPixmap( 0, *p ); + qApp->processEvents(); + if ( that.isNull() ) + return; + files->setUpdatesEnabled( TRUE ); + files->viewport()->setUpdatesEnabled( TRUE ); + + if ( files->isVisible() ) { + QRect ir( files->itemRect( item ) ); + if ( ir != QRect( 0, 0, -1, -1 ) ) { + r = r.unite( ir ); + } + } else { + QRect ir( d->moreFiles->itemRect( item->i ) ); + if ( ir != QRect( 0, 0, -1, -1 ) ) { + r = r.unite( ir ); + } + } + } + if ( d->pendingItems.count() ) + d->pendingItems.removeFirst(); + } + + if ( d->moreFiles->isVisible() ) { + d->moreFiles->viewport()->repaint( r, FALSE ); + } else { + files->viewport()->repaint( r, FALSE ); + } + + if ( d->pendingItems.count() ) + d->mimeTypeTimer->start( 0 ); + else if ( d->moreFiles->isVisible() ) + d->moreFiles->triggerUpdate( TRUE ); +} + +/*! + If \a b is TRUE then all the files in the current directory are selected; + otherwise, they are deselected. +*/ + +void QFileDialog::selectAll( bool b ) +{ + if ( d->mode != ExistingFiles ) + return; + d->moreFiles->selectAll( b ); + files->selectAll( b ); +} + +void QFileDialog::goBack() +{ + if ( !d->goBack || !d->goBack->isEnabled() ) + return; + d->history.remove( d->history.last() ); + if ( d->history.count() < 2 ) + d->goBack->setEnabled( FALSE ); + setUrl( d->history.last() ); +} + +// a class with wonderfully inflexible flexibility. why doesn't it +// just subclass QWidget in the first place? 'you have to derive your +// preview widget from QWidget and from this class' indeed. + +/*! + \class QFilePreview qfiledialog.h + \ingroup misc + \brief The QFilePreview class provides file previewing in QFileDialog. + + This class is an abstract base class which is used to implement + widgets that can display a preview of a file in a QFileDialog. + + You must derive the preview widget from both QWidget and from this + class. Then you must reimplement this class's previewUrl() function, + which is called by the file dialog if the preview of a file + (specified as a URL) should be shown. + + See also QFileDialog::setPreviewMode(), QFileDialog::setContentsPreview(), + QFileDialog::setInfoPreview(), QFileDialog::setInfoPreviewEnabled(), + QFileDialog::setContentsPreviewEnabled(). + + For an example of a preview widget see qt/examples/qdir/qdir.cpp. +*/ + +/*! + Constructs the QFilePreview. +*/ + +QFilePreview::QFilePreview() +{ +} + +/*! + \fn void QFilePreview::previewUrl( const QUrl &url ) + + This function is called by QFileDialog if a preview + for the \a url should be shown. Reimplement this + function to provide file previewing. +*/ + + +#include "qfiledialog.moc" + +#endif diff --git a/src/dialogs/qfiledialog.h b/src/dialogs/qfiledialog.h new file mode 100644 index 0000000..82d1f9a --- /dev/null +++ b/src/dialogs/qfiledialog.h @@ -0,0 +1,347 @@ +/**************************************************************************** +** +** Definition of QFileDialog class +** +** Created : 950428 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QFILEDIALOG_H +#define QFILEDIALOG_H + +class QPushButton; +class QButton; +class QLabel; +class QWidget; +class QFileDialog; +class QTimer; +class QNetworkOperation; +class QLineEdit; +class QListViewItem; +class QListBoxItem; +class QFileDialogPrivate; +class QFileDialogQFileListView; + +#ifndef QT_H +#include "qdir.h" +#include "qdialog.h" +#include "qurloperator.h" +#include "qurlinfo.h" +#endif // QT_H + +#if __GNUC__ - 0 > 3 +#pragma GCC system_header +#endif + +#ifndef QT_NO_FILEDIALOG + +class Q_EXPORT QFileIconProvider : public QObject +{ + Q_OBJECT +public: + QFileIconProvider( QObject * parent = 0, const char* name = 0 ); + virtual const QPixmap * pixmap( const QFileInfo & ); + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QFileIconProvider( const QFileIconProvider & ); + QFileIconProvider& operator=( const QFileIconProvider & ); +#endif +}; + +class Q_EXPORT QFilePreview +{ +public: + QFilePreview(); + virtual void previewUrl( const QUrl &url ) = 0; + +}; + +class Q_EXPORT QFileDialog : public QDialog +{ + Q_OBJECT + Q_ENUMS( Mode ViewMode PreviewMode ) + // ##### Why are this read-only properties ? + Q_PROPERTY( QString selectedFile READ selectedFile ) + Q_PROPERTY( QString selectedFilter READ selectedFilter ) + Q_PROPERTY( QStringList selectedFiles READ selectedFiles ) + // #### Should not we be able to set the path ? + Q_PROPERTY( QString dirPath READ dirPath ) + Q_PROPERTY( bool showHiddenFiles READ showHiddenFiles WRITE setShowHiddenFiles ) + Q_PROPERTY( Mode mode READ mode WRITE setMode ) + Q_PROPERTY( ViewMode viewMode READ viewMode WRITE setViewMode ) + Q_PROPERTY( PreviewMode previewMode READ previewMode WRITE setPreviewMode ) + Q_PROPERTY( bool infoPreview READ isInfoPreviewEnabled WRITE setInfoPreviewEnabled ) + Q_PROPERTY( bool contentsPreview READ isContentsPreviewEnabled WRITE setContentsPreviewEnabled ) + +public: + QFileDialog( const QString& dirName, const QString& filter = QString::null, + QWidget* parent=0, const char* name=0, bool modal = FALSE ); + QFileDialog( QWidget* parent=0, const char* name=0, bool modal = FALSE ); + ~QFileDialog(); + + // recommended static functions + + static QString getOpenFileName( const QString &initially = QString::null, + const QString &filter = QString::null, + QWidget *parent = 0, const char* name = 0, + const QString &caption = QString::null, + QString *selectedFilter = 0, + bool resolveSymlinks = TRUE); + static QString getSaveFileName( const QString &initially = QString::null, + const QString &filter = QString::null, + QWidget *parent = 0, const char* name = 0, + const QString &caption = QString::null, + QString *selectedFilter = 0, + bool resolveSymlinks = TRUE); + static QString getExistingDirectory( const QString &dir = QString::null, + QWidget *parent = 0, + const char* name = 0, + const QString &caption = QString::null, + bool dirOnly = TRUE, + bool resolveSymlinks = TRUE); + static QStringList getOpenFileNames( const QString &filter= QString::null, + const QString &dir = QString::null, + QWidget *parent = 0, + const char* name = 0, + const QString &caption = QString::null, + QString *selectedFilter = 0, + bool resolveSymlinks = TRUE); + + // other static functions + + static void setIconProvider( QFileIconProvider * ); + static QFileIconProvider * iconProvider(); + + // non-static function for special needs + + QString selectedFile() const; + QString selectedFilter() const; + virtual void setSelectedFilter( const QString& ); + virtual void setSelectedFilter( int ); + + void setSelection( const QString &); + + void selectAll( bool b ); + + QStringList selectedFiles() const; + + QString dirPath() const; + + void setDir( const QDir & ); + const QDir *dir() const; + + void setShowHiddenFiles( bool s ); + bool showHiddenFiles() const; + + void rereadDir(); + void resortDir(); + + enum Mode { AnyFile, ExistingFile, Directory, ExistingFiles, DirectoryOnly }; + void setMode( Mode ); + Mode mode() const; + + enum ViewMode { Detail, List }; + enum PreviewMode { NoPreview, Contents, Info }; + void setViewMode( ViewMode m ); + ViewMode viewMode() const; + void setPreviewMode( PreviewMode m ); + PreviewMode previewMode() const; + + bool eventFilter( QObject *, QEvent * ); + + bool isInfoPreviewEnabled() const; + bool isContentsPreviewEnabled() const; + void setInfoPreviewEnabled( bool ); + void setContentsPreviewEnabled( bool ); + + void setInfoPreview( QWidget *w, QFilePreview *preview ); + void setContentsPreview( QWidget *w, QFilePreview *preview ); + + QUrl url() const; + + void addFilter( const QString &filter ); + +public slots: + void done( int ); + void setDir( const QString& ); + void setUrl( const QUrlOperator &url ); + void setFilter( const QString& ); + void setFilters( const QString& ); + void setFilters( const char ** ); + void setFilters( const QStringList& ); + +protected: + void resizeEvent( QResizeEvent * ); + void keyPressEvent( QKeyEvent * ); + + void addWidgets( QLabel *, QWidget *, QPushButton * ); + void addToolButton( QButton *b, bool separator = FALSE ); + void addLeftWidget( QWidget *w ); + void addRightWidget( QWidget *w ); + +signals: + void fileHighlighted( const QString& ); + void fileSelected( const QString& ); + void filesSelected( const QStringList& ); + void dirEntered( const QString& ); + void filterSelected( const QString& ); + +private slots: + void detailViewSelectionChanged(); + void listBoxSelectionChanged(); + void changeMode( int ); + void fileNameEditReturnPressed(); + void stopCopy(); + void removeProgressDia(); + + void fileSelected( int ); + void fileHighlighted( int ); + void dirSelected( int ); + void pathSelected( int ); + + void updateFileNameEdit( QListViewItem *); + void selectDirectoryOrFile( QListViewItem * ); + void popupContextMenu( QListViewItem *, const QPoint &, int ); + void popupContextMenu( QListBoxItem *, const QPoint & ); + void updateFileNameEdit( QListBoxItem *); + void selectDirectoryOrFile( QListBoxItem * ); + void fileNameEditDone(); + + void okClicked(); + void filterClicked(); // not used + void cancelClicked(); + + void cdUpClicked(); + void newFolderClicked(); + + void fixupNameEdit(); + + void doMimeTypeLookup(); + + void updateGeometries(); + void modeButtonsDestroyed(); + void urlStart( QNetworkOperation *op ); + void urlFinished( QNetworkOperation *op ); + void dataTransferProgress( int bytesDone, int bytesTotal, QNetworkOperation * ); + void insertEntry( const QValueList<QUrlInfo> &fi, QNetworkOperation *op ); + void removeEntry( QNetworkOperation * ); + void createdDirectory( const QUrlInfo &info, QNetworkOperation * ); + void itemChanged( QNetworkOperation * ); + void goBack(); + +private: + enum PopupAction { + PA_Open = 0, + PA_Delete, + PA_Rename, + PA_SortName, + PA_SortSize, + PA_SortType, + PA_SortDate, + PA_SortUnsorted, + PA_Cancel, + PA_Reload, + PA_Hidden + }; + + void init(); + bool trySetSelection( bool isDir, const QUrlOperator &, bool ); + void deleteFile( const QString &filename ); + void popupContextMenu( const QString &filename, bool withSort, + PopupAction &action, const QPoint &p ); + void updatePreviews( const QUrl &u ); + + QDir reserved; // was cwd + QString fileName; + + friend class QFileDialogQFileListView; + friend class QFileListBox; + + QFileDialogPrivate *d; + QFileDialogQFileListView *files; + + QLineEdit *nameEdit; // also filter + QPushButton *okB; + QPushButton *cancelB; + +#if defined(Q_WS_WIN) + static QString winGetOpenFileName( const QString &initialSelection, + const QString &filter, + QString* workingDirectory, + QWidget *parent = 0, + const char* name = 0, + const QString& caption = QString::null, + QString* selectedFilter = 0 ); + static QString winGetSaveFileName( const QString &initialSelection, + const QString &filter, + QString* workingDirectory, + QWidget *parent = 0, + const char* name = 0, + const QString& caption = QString::null, + QString* selectedFilter = 0 ); + static QStringList winGetOpenFileNames( const QString &filter, + QString* workingDirectory, + QWidget *parent = 0, + const char* name = 0, + const QString& caption = QString::null, + QString* selectedFilter = 0 ); + static QString winGetExistingDirectory( const QString &initialDirectory, + QWidget* parent = 0, + const char* name = 0, + const QString& caption = QString::null); + static QString resolveLinkFile( const QString& linkfile ); +#endif +#if defined(Q_WS_MACX) || defined(Q_WS_MAC9) + static QString macGetSaveFileName( const QString &, const QString &, + QString *, QWidget *, const char*, + const QString&, QString *); + static QStringList macGetOpenFileNames( const QString &, QString*, + QWidget *, const char *, + const QString&, QString *, + bool = TRUE, bool = FALSE ); +#endif + + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QFileDialog( const QFileDialog & ); + QFileDialog &operator=( const QFileDialog & ); +#endif +}; + +#endif + +#endif // QFILEDIALOG_H diff --git a/src/dialogs/qfontdialog.cpp b/src/dialogs/qfontdialog.cpp new file mode 100644 index 0000000..1deec00 --- /dev/null +++ b/src/dialogs/qfontdialog.cpp @@ -0,0 +1,831 @@ +/**************************************************************************** +** +** Implementation of QFontDialog +** +** Created : 970605 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qwindowdefs.h" + +#ifndef QT_NO_FONTDIALOG + +#include "qfontdialog.h" + +#include "qlineedit.h" +#include "qlistbox.h" +#include "qpushbutton.h" +#include "qcheckbox.h" +#include "qcombobox.h" +#include "qlayout.h" +#include "qvgroupbox.h" +#include "qhgroupbox.h" +#include "qlabel.h" +#include "qapplication.h" +#include "qfontdatabase.h" +#include "qstyle.h" +#include <private/qfontdata_p.h> +#include <qvalidator.h> + +/*! + \class QFontDialog qfontdialog.h + \ingroup dialogs + \mainclass + \brief The QFontDialog class provides a dialog widget for selecting a font. + + The usual way to use this class is to call one of the static convenience + functions, e.g. getFont(). + + Examples: + + \code + bool ok; + QFont font = QFontDialog::getFont( + &ok, QFont( "Helvetica [Cronyx]", 10 ), this ); + if ( ok ) { + // font is set to the font the user selected + } else { + // the user canceled the dialog; font is set to the initial + // value, in this case Helvetica [Cronyx], 10 + } + \endcode + + The dialog can also be used to set a widget's font directly: + \code + myWidget.setFont( QFontDialog::getFont( 0, myWidget.font() ) ); + \endcode + If the user clicks OK the font they chose will be used for myWidget, + and if they click Cancel the original font is used. + + \sa QFont QFontInfo QFontMetrics + + <img src=qfontdlg-w.png> +*/ + +class QFontDialogPrivate +{ +public: + QFontDialogPrivate() : script( QFontPrivate::defaultScript ) {}; + QLabel * familyAccel; + QLineEdit * familyEdit; + QListBox * familyList; + + QLabel * styleAccel; + QLineEdit * styleEdit; + QListBox * styleList; + + QLabel * sizeAccel; + QLineEdit * sizeEdit; + QListBox * sizeList; + + QVGroupBox * effects; + QCheckBox * strikeout; + QCheckBox * underline; + QComboBox * color; + + QHGroupBox * sample; + QLineEdit * sampleEdit; + + QLabel * scriptAccel; + QComboBox * scriptCombo; + + QPushButton * ok; + QPushButton * cancel; + + QBoxLayout * buttonLayout; + QBoxLayout * effectsLayout; + QBoxLayout * sampleLayout; + QBoxLayout * sampleEditLayout; + + QFontDatabase fdb; + + QString family; + QFont::Script script; + QString style; + int size; + + bool smoothScalable; +}; + + +/*! + \internal + Constructs a standard font dialog. + + Use setFont() to set the initial font attributes. + + The \a parent, \a name, \a modal and \a f parameters are passed to + the QDialog constructor. + + \sa getFont() +*/ + +QFontDialog::QFontDialog( QWidget *parent, const char *name, + bool modal, WFlags f ) + : QDialog( parent, name, modal, f ) +{ + setSizeGripEnabled( TRUE ); + d = new QFontDialogPrivate; + // grid + d->familyEdit = new QLineEdit( this, "font family I" ); + d->familyEdit->setReadOnly( TRUE ); + d->familyList = new QListBox( this, "font family II" ); + d->familyEdit->setFocusProxy( d->familyList ); + + d->familyAccel + = new QLabel( d->familyList, tr("&Font"), this, "family accelerator" ); + d->familyAccel->setIndent( 2 ); + + d->styleEdit = new QLineEdit( this, "font style I" ); + d->styleEdit->setReadOnly( TRUE ); + d->styleList = new QListBox( this, "font style II" ); + d->styleEdit->setFocusProxy( d->styleList ); + + d->styleAccel + = new QLabel( d->styleList, tr("Font st&yle"), this, "style accelerator" ); + d->styleAccel->setIndent( 2 ); + + d->sizeEdit = new QLineEdit( this, "font size I" ); + d->sizeEdit->setFocusPolicy( ClickFocus ); + QIntValidator *validator = new QIntValidator( 1, 512, this ); + d->sizeEdit->setValidator( validator ); + d->sizeList = new QListBox( this, "font size II" ); + + d->sizeAccel + = new QLabel ( d->sizeEdit, tr("&Size"), this, "size accelerator" ); + d->sizeAccel->setIndent( 2 ); + + // effects box + d->effects = new QVGroupBox( tr("Effects"), this, "font effects" ); + d->strikeout = new QCheckBox( d->effects, "strikeout on/off" ); + d->strikeout->setText( tr("Stri&keout") ); + d->underline = new QCheckBox( d->effects, "underline on/off" ); + d->underline->setText( tr("&Underline") ); + + d->sample = new QHGroupBox( tr("Sample"), this, "sample text" ); + d->sampleEdit = new QLineEdit( d->sample, "r/w sample text" ); + d->sampleEdit->setSizePolicy( QSizePolicy( QSizePolicy::Ignored, QSizePolicy::Ignored) ); + d->sampleEdit->setAlignment( AlignCenter ); + // Note that the sample text is *not* translated with tr(), as the + // characters used depend on the charset encoding. + d->sampleEdit->setText( "AaBbYyZz" ); + + d->scriptCombo = new QComboBox( FALSE, this, "font encoding" ); + + d->scriptAccel + = new QLabel( d->scriptCombo, tr("Scr&ipt"), this,"encoding label"); + d->scriptAccel->setIndent( 2 ); + + d->size = 0; + d->smoothScalable = FALSE; + + connect( d->scriptCombo, SIGNAL(activated(int)), + SLOT(scriptHighlighted(int)) ); + connect( d->familyList, SIGNAL(highlighted(int)), + SLOT(familyHighlighted(int)) ); + connect( d->styleList, SIGNAL(highlighted(int)), + SLOT(styleHighlighted(int)) ); + connect( d->sizeList, SIGNAL(highlighted(const QString&)), + SLOT(sizeHighlighted(const QString&)) ); + connect( d->sizeEdit, SIGNAL(textChanged(const QString&)), + SLOT(sizeChanged(const QString&)) ); + + connect( d->strikeout, SIGNAL(clicked()), + SLOT(updateSample()) ); + connect( d->underline, SIGNAL(clicked()), + SLOT(updateSample()) ); + + (void)d->familyList->sizeHint(); + (void)d->styleList->sizeHint(); + (void)d->sizeList->sizeHint(); + + for (int i = 0; i < QFont::NScripts; i++) { + QString scriptname = QFontDatabase::scriptName((QFont::Script) i); + if ( !scriptname.isEmpty() ) + d->scriptCombo->insertItem( scriptname ); + } + + updateFamilies(); + if ( d->familyList->count() != 0 ) + d->familyList->setCurrentItem( 0 ); + + // grid layout + QGridLayout * mainGrid = new QGridLayout( this, 9, 6, 12, 0 ); + + mainGrid->addWidget( d->familyAccel, 0, 0 ); + mainGrid->addWidget( d->familyEdit, 1, 0 ); + mainGrid->addWidget( d->familyList, 2, 0 ); + + mainGrid->addWidget( d->styleAccel, 0, 2 ); + mainGrid->addWidget( d->styleEdit, 1, 2 ); + mainGrid->addWidget( d->styleList, 2, 2 ); + + mainGrid->addWidget( d->sizeAccel, 0, 4 ); + mainGrid->addWidget( d->sizeEdit, 1, 4 ); + mainGrid->addWidget( d->sizeList, 2, 4 ); + + mainGrid->setColStretch( 0, 38 ); + mainGrid->setColStretch( 2, 24 ); + mainGrid->setColStretch( 4, 10 ); + + mainGrid->addColSpacing( 1, 6 ); + mainGrid->addColSpacing( 3, 6 ); + mainGrid->addColSpacing( 5, 6 ); + + mainGrid->addRowSpacing( 3, 12 ); + + mainGrid->addWidget( d->effects, 4, 0 ); + + mainGrid->addMultiCellWidget( d->sample, 4, 7, 2, 4 ); + + mainGrid->addWidget( d->scriptAccel, 5, 0 ); + mainGrid->addRowSpacing( 6, 2 ); + mainGrid->addWidget( d->scriptCombo, 7, 0 ); + + mainGrid->addRowSpacing( 8, 12 ); + + QHBoxLayout *buttonBox = new QHBoxLayout; + mainGrid->addMultiCell( buttonBox, 9, 9, 0, 4 ); + + buttonBox->addStretch( 1 ); + QString okt = modal ? tr("OK") : tr("Apply"); + d->ok = new QPushButton( okt, this, "accept font selection" ); + buttonBox->addWidget( d->ok ); + if ( modal ) + connect( d->ok, SIGNAL(clicked()), SLOT(accept()) ); + d->ok->setDefault( TRUE ); + + buttonBox->addSpacing( 12 ); + + QString cancelt = modal ? tr("Cancel") : tr("Close"); + d->cancel = new QPushButton( cancelt, this, "cancel/close" ); + buttonBox->addWidget( d->cancel ); + connect( d->cancel, SIGNAL(clicked()), SLOT(reject()) ); + + resize( 500, 360 ); + + d->sizeEdit->installEventFilter( this ); + d->familyList->installEventFilter( this ); + d->styleList->installEventFilter( this ); + d->sizeList->installEventFilter( this ); + + d->familyList->setFocus(); +} + +/*! + \internal + Destroys the font dialog and frees up its storage. +*/ + +QFontDialog::~QFontDialog() +{ + delete d; + d = 0; +} + +/*! + Executes a modal font dialog and returns a font. + + If the user clicks OK, the selected font is returned. If the user + clicks Cancel, the \a initial font is returned. + + The dialog is called \a name, with the parent \a parent. + \a initial is the initially selected font. + If the \a ok parameter is not-null, \e *\a ok is set to TRUE if the + user clicked OK, and set to FALSE if the user clicked Cancel. + + This static function is less flexible than the full QFontDialog + object, but is convenient and easy to use. + + Examples: + \code + bool ok; + QFont font = QFontDialog::getFont( &ok, QFont( "Times", 12 ), this ); + if ( ok ) { + // font is set to the font the user selected + } else { + // the user canceled the dialog; font is set to the initial + // value, in this case Times, 12. + } + \endcode + + The dialog can also be used to set a widget's font directly: + \code + myWidget.setFont( QFontDialog::getFont( 0, myWidget.font() ) ); + \endcode + In this example, if the user clicks OK the font they chose will be + used, and if they click Cancel the original font is used. +*/ +QFont QFontDialog::getFont( bool *ok, const QFont &initial, + QWidget *parent, const char* name) +{ + return getFont( ok, &initial, parent, name ); +} + +/*! + \overload + + Executes a modal font dialog and returns a font. + + If the user clicks OK, the selected font is returned. If the user + clicks Cancel, the Qt default font is returned. + + The dialog is called \a name, with parent \a parent. + If the \a ok parameter is not-null, \e *\a ok is set to TRUE if the + user clicked OK, and FALSE if the user clicked Cancel. + + This static function is less functional than the full QFontDialog + object, but is convenient and easy to use. + + Example: + \code + bool ok; + QFont font = QFontDialog::getFont( &ok, this ); + if ( ok ) { + // font is set to the font the user selected + } else { + // the user canceled the dialog; font is set to the default + // application font, QApplication::font() + } + \endcode + +*/ +QFont QFontDialog::getFont( bool *ok, QWidget *parent,const char* name) +{ + return getFont( ok, 0, parent, name ); +} + +QFont QFontDialog::getFont( bool *ok, const QFont *def, + QWidget *parent, const char* name) +{ + QFont result; + if ( def ) + result = *def; + + QFontDialog *dlg = new QFontDialog( parent, name, TRUE ); + + dlg->setFont( ( def ? *def : QFont() ) ); +#ifndef QT_NO_WIDGET_TOPEXTRA + dlg->setCaption( tr("Select Font") ); +#endif + + bool res = (dlg->exec() == QDialog::Accepted); + if ( res ) + result = dlg->font(); + if ( ok ) + *ok = res; + delete dlg; + return result; +} + + +/*! + \internal + An event filter to make the Up, Down, PageUp and PageDown keys work + correctly in the line edits. The source of the event is the object + \a o and the event is \a e. +*/ + +bool QFontDialog::eventFilter( QObject * o , QEvent * e ) +{ + if ( e->type() == QEvent::KeyPress) { + QKeyEvent * k = (QKeyEvent *)e; + if ( o == d->sizeEdit && + (k->key() == Key_Up || + k->key() == Key_Down || + k->key() == Key_Prior || + k->key() == Key_Next) ) { + + int ci = d->sizeList->currentItem(); + (void)QApplication::sendEvent( d->sizeList, k ); + + if ( ci != d->sizeList->currentItem() && + style().styleHint(QStyle::SH_FontDialog_SelectAssociatedText, this)) + d->sizeEdit->selectAll(); + return TRUE; + } else if ( ( o == d->familyList || o == d->styleList ) && + ( k->key() == Key_Return || k->key() == Key_Enter) ) { + k->accept(); + accept(); + return TRUE; + } + } else if ( e->type() == QEvent::FocusIn && + style().styleHint(QStyle::SH_FontDialog_SelectAssociatedText, this) ) { + if ( o == d->familyList ) + d->familyEdit->selectAll(); + else if ( o == d->styleList ) + d->styleEdit->selectAll(); + else if ( o == d->sizeList ) + d->sizeEdit->selectAll(); + } else if ( e->type() == QEvent::MouseButtonPress && o == d->sizeList ) { + d->sizeEdit->setFocus(); + } + return QDialog::eventFilter( o, e ); +} + +#ifdef Q_WS_MAC +// #define SHOW_FONTS_IN_FAMILIES +#endif + +#ifdef SHOW_FONTS_IN_FAMILIES +#include "qpainter.h" +#include <sizeedit.h> + +class QListBoxFontText : public QListBoxText +{ + QFont cfont; +public: + QListBoxFontText( const QString & text ); + ~QListBoxFontText() { } + + int height( const QListBox * ) const; + int width( const QListBox * ) const; + +protected: + void paint( QPainter * ); +}; + +QListBoxFontText::QListBoxFontText( const QString & text ) + : QListBoxText(text), cfont(text) +{ +} + +int QListBoxFontText::height( const QListBox * ) const +{ + QFontMetrics fm(cfont); + return QMAX( fm.lineSpacing() + 2, QApplication::globalStrut().height() ); +} + +int QListBoxFontText::width( const QListBox * ) const +{ + QFontMetrics fm(cfont); + return QMAX( fm.width( text() ) + 6, QApplication::globalStrut().width() ); +} + +void QListBoxFontText::paint( QPainter *painter ) +{ + painter->save(); + painter->setFont(cfont); + QListBoxText::paint(painter); + painter->restore(); +} + +#endif + +/*! + \internal + Updates the contents of the "font family" list box. This + function can be reimplemented if you have special requirements. +*/ + +void QFontDialog::updateFamilies() +{ + d->familyList->blockSignals( TRUE ); + + enum match_t { MATCH_NONE=0, MATCH_LAST_RESORT=1, MATCH_APP=2, MATCH_FALLBACK, MATCH_FAMILY=3 }; + + QStringList familyNames = d->fdb.families(d->script); + { + // merge the unicode/unknown family list with the above list. + QStringList l = d->fdb.families(QFont::Unicode) + + d->fdb.families(QFont::UnknownScript); + QStringList::ConstIterator it = l.begin(), end = l.end(); + for (; it != end; ++it) { + if (! familyNames.contains(*it)) + familyNames << *it; + } + } + + familyNames.sort(); + + d->familyList->clear(); +#ifdef SHOW_FONTS_IN_FAMILIES + QStringList::Iterator it = familyNames.begin(); + int idx = 0; + for( ; it != familyNames.end() ; ++it ) + d->familyList->insertItem(new QListBoxFontText(*it), idx++); +#else + d->familyList->insertStringList( familyNames ); +#endif + + QString foundryName1, familyName1, foundryName2, familyName2; + int bestFamilyMatch = -1; + match_t bestFamilyType = MATCH_NONE; + + QFont f; + + // ##### do the right thing for a list of family names in the font. + QFontDatabase::parseFontName(d->family, foundryName1, familyName1); + + QStringList::Iterator it = familyNames.begin(); + int i = 0; + for( ; it != familyNames.end(); ++it, ++i ) { + + QFontDatabase::parseFontName(*it, foundryName2, familyName2); + + //try to match.. + if ( familyName1 == familyName2 ) { + bestFamilyType = MATCH_FAMILY; + if ( foundryName1 == foundryName2 ) { + bestFamilyMatch = i; + break; + } + if ( bestFamilyMatch < MATCH_FAMILY ) + bestFamilyMatch = i; + } + + //and try some fall backs + match_t type = MATCH_NONE; + if ( bestFamilyType <= MATCH_NONE && familyName2 == f.lastResortFamily() ) + type = MATCH_LAST_RESORT; + if ( bestFamilyType <= MATCH_LAST_RESORT && familyName2 == f.family() ) + type = MATCH_APP; + // ### add fallback for script + if ( type != MATCH_NONE ) { + bestFamilyType = type; + bestFamilyMatch = i; + } + } + + if (i != -1 && bestFamilyType != MATCH_NONE) + d->familyList->setCurrentItem(bestFamilyMatch); + else + d->familyList->setCurrentItem( 0 ); + d->familyEdit->setText( d->familyList->currentText() ); + if ( style().styleHint(QStyle::SH_FontDialog_SelectAssociatedText, this) && + d->familyList->hasFocus() ) + d->familyEdit->selectAll(); + + d->familyList->blockSignals( FALSE ); + updateStyles(); +} + +/*! + \internal + Updates the contents of the "font style" list box. This + function can be reimplemented if you have special requirements. +*/ + +void QFontDialog::updateStyles() +{ + d->styleList->blockSignals( TRUE ); + + d->styleList->clear(); + + QStringList styles = d->fdb.styles( d->familyList->currentText() ); + + if ( styles.isEmpty() ) { + d->styleEdit->clear(); + d->smoothScalable = FALSE; + } else { + d->styleList->insertStringList( styles ); + + if ( !d->style.isEmpty() ) { + bool found = FALSE; + bool first = TRUE; + QString cstyle = d->style; + redo: + for ( int i = 0 ; i < (int)d->styleList->count() ; i++ ) { + if ( cstyle == d->styleList->text(i) ) { + d->styleList->setCurrentItem( i ); + found = TRUE; + break; + } + } + if (!found && first) { + if (cstyle.contains("Italic")) { + cstyle.replace("Italic", "Oblique"); + first = FALSE; + goto redo; + } else if (cstyle.contains("Oblique")) { + cstyle.replace("Oblique", "Italic"); + first = FALSE; + goto redo; + } + } + if ( !found ) + d->styleList->setCurrentItem( 0 ); + } + + d->styleEdit->setText( d->styleList->currentText() ); + if ( style().styleHint(QStyle::SH_FontDialog_SelectAssociatedText, this) && + d->styleList->hasFocus() ) + d->styleEdit->selectAll(); + + d->smoothScalable = d->fdb.isSmoothlyScalable( d->familyList->currentText(), d->styleList->currentText() ); + } + + d->styleList->blockSignals( FALSE ); + + updateSizes(); +} + +/*! + \internal + Updates the contents of the "font size" list box. This + function can be reimplemented if you have special requirements. +*/ + +void QFontDialog::updateSizes() +{ + d->sizeList->blockSignals( TRUE ); + + d->sizeList->clear(); + + if ( !d->familyList->currentText().isEmpty() ) { + QValueList<int> sizes = d->fdb.pointSizes( d->familyList->currentText(), d->styleList->currentText() ); + + int i = 0; + bool found = FALSE; + for( QValueList<int>::iterator it = sizes.begin() ; it != sizes.end(); ++it ) { + d->sizeList->insertItem( QString::number( *it ) ); + if ( !found && *it >= d->size ) { + d->sizeList->setCurrentItem( i ); + found = TRUE; + } + ++i; + } + if ( !found ) { + // we request a size bigger than the ones in the list, select the biggest one + d->sizeList->setCurrentItem( d->sizeList->count() - 1 ); + } + + d->sizeEdit->blockSignals( TRUE ); + d->sizeEdit->setText( ( d->smoothScalable ? QString::number( d->size ) : d->sizeList->currentText() ) ); + if ( style().styleHint(QStyle::SH_FontDialog_SelectAssociatedText, this) && + d->sizeList->hasFocus() ) + d->sizeEdit->selectAll(); + d->sizeEdit->blockSignals( FALSE ); + } else { + d->sizeEdit->clear(); + } + + d->sizeList->blockSignals( FALSE ); + updateSample(); +} + +void QFontDialog::updateSample() +{ + if ( d->familyList->currentText().isEmpty() ) + d->sampleEdit->clear(); + else + d->sampleEdit->setFont( font() ); +} + +/*! + \internal +*/ +void QFontDialog::scriptHighlighted( int index ) +{ + d->script = (QFont::Script)index; + d->sampleEdit->setText( d->fdb.scriptSample( d->script ) ); + updateFamilies(); +} + +/*! + \internal +*/ +void QFontDialog::familyHighlighted( int i ) +{ + d->family = d->familyList->text( i ); + d->familyEdit->setText( d->family ); + if ( style().styleHint(QStyle::SH_FontDialog_SelectAssociatedText, this) && + d->familyList->hasFocus() ) + d->familyEdit->selectAll(); + + updateStyles(); +} + + +/*! + \internal +*/ + +void QFontDialog::styleHighlighted( int index ) +{ + QString s = d->styleList->text( index ); + d->styleEdit->setText( s ); + if ( style().styleHint(QStyle::SH_FontDialog_SelectAssociatedText, this) && + d->styleList->hasFocus() ) + d->styleEdit->selectAll(); + + d->style = s; + + updateSizes(); +} + + +/*! + \internal +*/ + +void QFontDialog::sizeHighlighted( const QString &s ) +{ + d->sizeEdit->setText( s ); + if ( style().styleHint(QStyle::SH_FontDialog_SelectAssociatedText, this) && + d->sizeEdit->hasFocus() ) + d->sizeEdit->selectAll(); + + d->size = s.toInt(); + updateSample(); +} + +/*! + \internal + This slot is called if the user changes the font size. + The size is passed in the \a s argument as a \e string. +*/ + +void QFontDialog::sizeChanged( const QString &s ) +{ + // no need to check if the conversion is valid, since we have an QIntValidator in the size edit + int size = s.toInt(); + if ( d->size == size ) + return; + + d->size = size; + if ( d->sizeList->count() != 0 ) { + int i; + for ( i = 0 ; i < (int)d->sizeList->count() - 1 ; i++ ) { + if ( d->sizeList->text(i).toInt() >= d->size ) + break; + } + d->sizeList->blockSignals( TRUE ); + d->sizeList->setCurrentItem( i ); + d->sizeList->blockSignals( FALSE ); + } + updateSample(); +} + +/*! + \internal + Sets the font highlighted in the QFontDialog to font \a f. + + \sa font() +*/ + +void QFontDialog::setFont( const QFont &f ) +{ + d->family = f.family(); + d->style = d->fdb.styleString( f ); + d->size = f.pointSize(); + if ( d->size == -1 ) { + QFontInfo fi( f ); + d->size = fi.pointSize(); + } + d->strikeout->setChecked( f.strikeOut() ); + d->underline->setChecked( f.underline() ); + + updateFamilies(); +} + +/*! + \internal + Returns the font which the user has chosen. + + \sa setFont() +*/ + +QFont QFontDialog::font() const +{ + int pSize = d->sizeEdit->text().toInt(); + + QFont f = d->fdb.font( d->familyList->currentText(), d->style, pSize ); + f.setStrikeOut( d->strikeout->isChecked() ); + f.setUnderline( d->underline->isChecked() ); + return f; +} + +#endif diff --git a/src/dialogs/qfontdialog.h b/src/dialogs/qfontdialog.h new file mode 100644 index 0000000..0f02f8c --- /dev/null +++ b/src/dialogs/qfontdialog.h @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Definition of QFontDialog +** +** Created : 970605 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QFONTDIALOG_H +#define QFONTDIALOG_H + +#include "qwindowdefs.h" + +#ifndef QT_NO_FONTDIALOG + +// +// W A R N I N G +// ------------- +// +// This class is under development and has private constructors. +// +// You may use the public static getFont() functions which are guaranteed +// to be available in the future. +// + +#ifndef QT_H +#include "qdialog.h" +#include "qfont.h" +#endif // QT_H + +class QFontDialogPrivate; + +class Q_EXPORT QFontDialog: public QDialog +{ + Q_OBJECT + +public: + static QFont getFont( bool *ok, const QFont &def, + QWidget* parent=0, const char* name=0); + static QFont getFont( bool *ok, QWidget* parent=0, const char* name=0); + +private: + static QFont getFont( bool *ok, const QFont *def, + QWidget* parent=0, const char* name=0); + + QFontDialog( QWidget* parent=0, const char* name=0, bool modal=FALSE, + WFlags f=0 ); + ~QFontDialog(); + + QFont font() const; + void setFont( const QFont &font ); + + bool eventFilter( QObject *, QEvent * ); + + void updateFamilies(); + void updateStyles(); + void updateSizes(); + +private slots: + void sizeChanged( const QString &); + void familyHighlighted( int ); + void scriptHighlighted( int ); + void styleHighlighted( int ); + void sizeHighlighted( const QString & ); + void updateSample(); + +private: + friend class QFontDialogPrivate; + QFontDialogPrivate * d; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QFontDialog( const QFontDialog & ); + QFontDialog& operator=( const QFontDialog & ); +#endif +}; + +#endif + +#endif // QFONTDIALOG_H diff --git a/src/dialogs/qinputdialog.cpp b/src/dialogs/qinputdialog.cpp new file mode 100644 index 0000000..fd73e0a --- /dev/null +++ b/src/dialogs/qinputdialog.cpp @@ -0,0 +1,532 @@ +/**************************************************************************** +** +** Implementation of QInputDialog class +** +** Created : 991212 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qinputdialog.h" + +#ifndef QT_NO_INPUTDIALOG + +#include "qlayout.h" +#include "qlabel.h" +#include "qlineedit.h" +#include "qpushbutton.h" +#include "qspinbox.h" +#include "qcombobox.h" +#include "qwidgetstack.h" +#include "qvalidator.h" +#include "qapplication.h" + +class QInputDialogPrivate +{ +public: + friend class QInputDialog; + QLabel *label; + QLineEdit *lineEdit; + QSpinBox *spinBox; + QComboBox *comboBox, *editComboBox; + QPushButton *ok; + QWidgetStack *stack; + QInputDialog::Type type; +}; + +/*! + \class QInputDialog + \brief The QInputDialog class provides a simple convenience dialog to get a single value from the user. + \ingroup dialogs + \mainclass + + The input value can be a string, a number or an item from a list. A + label must be set to tell the user what they should enter. + + Four static convenience functions are provided: + getText(), getInteger(), getDouble() and getItem(). All the + functions can be used in a similar way, for example: + \code + bool ok; + QString text = QInputDialog::getText( + "MyApp 3000", "Enter your name:", QLineEdit::Normal, + QString::null, &ok, this ); + if ( ok && !text.isEmpty() ) { + // user entered something and pressed OK + } else { + // user entered nothing or pressed Cancel + } + \endcode + + \img inputdialogs.png Input Dialogs +*/ + +/*! + \enum QInputDialog::Type + + This enum specifies the type of the dialog, i.e. what kind of data you + want the user to input: + + \value LineEdit A QLineEdit is used for obtaining string or numeric + input. The QLineEdit can be accessed using lineEdit(). + + \value SpinBox A QSpinBox is used for obtaining integer input. + Use spinBox() to access the QSpinBox. + + \value ComboBox A read-only QComboBox is used to provide a fixed + list of choices from which the user can choose. + Use comboBox() to access the QComboBox. + + \value EditableComboBox An editable QComboBox is used to provide a fixed + list of choices from which the user can choose, but which also + allows the user to enter their own value instead. + Use editableComboBox() to access the QComboBox. +*/ + +/*! + Constructs the dialog. The \a label is the text which is shown to the user + (it should tell the user what they are expected to enter). The \a parent + is the dialog's parent widget. The widget is called \a name. If \a + modal is TRUE (the default) the dialog will be modal. The \a type + parameter is used to specify which type of dialog to construct. + + \sa getText(), getInteger(), getDouble(), getItem() +*/ + +QInputDialog::QInputDialog( const QString &label, QWidget* parent, + const char* name, bool modal, Type type ) + : QDialog( parent, name, modal ) +{ + d = new QInputDialogPrivate; + d->lineEdit = 0; + d->spinBox = 0; + d->comboBox = 0; + + QVBoxLayout *vbox = new QVBoxLayout( this, 6, 6 ); + + d->label = new QLabel( label, this, "qt_inputdlg_lbl" ); + vbox->addWidget( d->label ); + + d->stack = new QWidgetStack( this, "qt_inputdlg_ws" ); + vbox->addWidget( d->stack ); + d->lineEdit = new QLineEdit( d->stack, "qt_inputdlg_le" ); + d->spinBox = new QSpinBox( d->stack, "qt_inputdlg_sb" ); + d->comboBox = new QComboBox( FALSE, d->stack, "qt_inputdlg_cb" ); + d->editComboBox = new QComboBox( TRUE, d->stack, "qt_inputdlg_editcb" ); + + QHBoxLayout *hbox = new QHBoxLayout( 6 ); + vbox->addLayout( hbox, AlignRight ); + + d->ok = new QPushButton( tr( "OK" ), this, "qt_ok_btn" ); + d->ok->setDefault( TRUE ); + QPushButton *cancel = new QPushButton( tr( "Cancel" ), this, "qt_cancel_btn" ); + + QSize bs = d->ok->sizeHint().expandedTo( cancel->sizeHint() ); + d->ok->setFixedSize( bs ); + cancel->setFixedSize( bs ); + + hbox->addStretch(); + hbox->addWidget( d->ok ); + hbox->addWidget( cancel ); + + connect( d->lineEdit, SIGNAL( returnPressed() ), + this, SLOT( tryAccept() ) ); + connect( d->lineEdit, SIGNAL( textChanged(const QString&) ), + this, SLOT( textChanged(const QString&) ) ); + + connect( d->ok, SIGNAL( clicked() ), this, SLOT( accept() ) ); + connect( cancel, SIGNAL( clicked() ), this, SLOT( reject() ) ); + + QSize sh = sizeHint().expandedTo( QSize(400, 10) ); + setType( type ); + resize( sh.width(), vbox->heightForWidth(sh.width()) ); +} + +/*! + Returns the line edit which is used in LineEdit mode. +*/ + +QLineEdit *QInputDialog::lineEdit() const +{ + return d->lineEdit; +} + +/*! + Returns the spinbox which is used in SpinBox mode. +*/ + +QSpinBox *QInputDialog::spinBox() const +{ + return d->spinBox; +} + +/*! + Returns the combobox which is used in ComboBox mode. +*/ + +QComboBox *QInputDialog::comboBox() const +{ + return d->comboBox; +} + +/*! + Returns the combobox which is used in EditableComboBox mode. +*/ + +QComboBox *QInputDialog::editableComboBox() const +{ + return d->editComboBox; +} + +/*! + Sets the input type of the dialog to \a t. +*/ + +void QInputDialog::setType( Type t ) +{ + QWidget *input = 0; + switch ( t ) { + case LineEdit: + input = d->lineEdit; + break; + case SpinBox: + input = d->spinBox; + break; + case ComboBox: + input = d->comboBox; + break; + case EditableComboBox: + input = d->editComboBox; + break; + default: +#if defined(QT_CHECK_STATE) + qWarning( "QInputDialog::setType: Invalid type" ); +#endif + break; + } + if ( input ) { + d->stack->raiseWidget( input ); + d->stack->setFixedHeight( input->sizeHint().height() ); + input->setFocus(); +#ifndef QT_NO_ACCEL + d->label->setBuddy( input ); +#endif + } + + d->type = t; +} + +/*! + Returns the input type of the dialog. + + \sa setType() +*/ + +QInputDialog::Type QInputDialog::type() const +{ + return d->type; +} + +/*! + Destructor. +*/ + +QInputDialog::~QInputDialog() +{ + delete d; +} + +/*! + Static convenience function to get a string from the user. \a + caption is the text which is displayed in the title bar of the + dialog. \a label is the text which is shown to the user (it should + say what should be entered). \a text is the default text which is + placed in the line edit. The \a mode is the echo mode the line edit + will use. If \a ok is not-null \e *\a ok will be set to TRUE if the + user pressed OK and to FALSE if the user pressed Cancel. The + dialog's parent is \a parent; the dialog is called \a name. The + dialog will be modal. + + This function returns the text which has been entered in the line + edit. It will not return an empty string. + + Use this static function like this: + + \code + bool ok; + QString text = QInputDialog::getText( + "MyApp 3000", "Enter your name:", QLineEdit::Normal, + QString::null, &ok, this ); + if ( ok && !text.isEmpty() ) { + // user entered something and pressed OK + } else { + // user entered nothing or pressed Cancel + } + \endcode +*/ + +QString QInputDialog::getText( const QString &caption, const QString &label, + QLineEdit::EchoMode mode, const QString &text, + bool *ok, QWidget *parent, const char *name ) +{ + QInputDialog *dlg = new QInputDialog( label, parent, + name ? name : "qt_inputdlg_gettext", + TRUE, LineEdit ); + +#ifndef QT_NO_WIDGET_TOPEXTRA + dlg->setCaption( caption ); +#endif + dlg->lineEdit()->setText( text ); + dlg->lineEdit()->setEchoMode( mode ); + + bool ok_ = FALSE; + QString result; + ok_ = dlg->exec() == QDialog::Accepted; + if ( ok ) + *ok = ok_; + if ( ok_ ) + result = dlg->lineEdit()->text(); + + delete dlg; + return result; +} + +/*! + Static convenience function to get an integer input from the + user. \a caption is the text which is displayed in the title bar + of the dialog. \a label is the text which is shown to the user + (it should say what should be entered). \a value is the default + integer which the spinbox will be set to. \a minValue and \a + maxValue are the minimum and maximum values the user may choose, + and \a step is the amount by which the values change as the user + presses the arrow buttons to increment or decrement the value. + + If \a ok is not-null *\a ok will be set to TRUE if the user + pressed OK and to FALSE if the user pressed Cancel. The dialog's + parent is \a parent; the dialog is called \a name. The dialog will + be modal. + + This function returns the integer which has been entered by the user. + + Use this static function like this: + + \code + bool ok; + int res = QInputDialog::getInteger( + "MyApp 3000", "Enter a number:", 22, 0, 1000, 2, + &ok, this ); + if ( ok ) { + // user entered something and pressed OK + } else { + // user pressed Cancel + } + \endcode +*/ + +int QInputDialog::getInteger( const QString &caption, const QString &label, + int value, int minValue, int maxValue, int step, bool *ok, + QWidget *parent, const char *name ) +{ + QInputDialog *dlg = new QInputDialog( label, parent, + name ? name : "qt_inputdlg_getint", + TRUE, SpinBox ); +#ifndef QT_NO_WIDGET_TOPEXTRA + dlg->setCaption( caption ); +#endif + dlg->spinBox()->setRange( minValue, maxValue ); + dlg->spinBox()->setSteps( step, 0 ); + dlg->spinBox()->setValue( value ); + + bool ok_ = FALSE; + int result; + ok_ = dlg->exec() == QDialog::Accepted; + if ( ok ) + *ok = ok_; + result = dlg->spinBox()->value(); + + delete dlg; + return result; +} + +/*! + Static convenience function to get a floating point number from + the user. \a caption is the text which is displayed in the title + bar of the dialog. \a label is the text which is shown to the user + (it should say what should be entered). \a value is the default + floating point number that the line edit will be set to. \a + minValue and \a maxValue are the minimum and maximum values the + user may choose, and \a decimals is the maximum number of decimal + places the number may have. + + If \a ok is not-null \e *\a ok will be set to TRUE if the user + pressed OK and to FALSE if the user pressed Cancel. The dialog's + parent is \a parent; the dialog is called \a name. The dialog will + be modal. + + This function returns the floating point number which has been + entered by the user. + + Use this static function like this: + + \code + bool ok; + double res = QInputDialog::getDouble( + "MyApp 3000", "Enter a decimal number:", 33.7, 0, + 1000, 2, &ok, this ); + if ( ok ) { + // user entered something and pressed OK + } else { + // user pressed Cancel + } + \endcode +*/ + +double QInputDialog::getDouble( const QString &caption, const QString &label, + double value, double minValue, double maxValue, + int decimals, bool *ok, QWidget *parent, + const char *name ) +{ + QInputDialog dlg( label, parent, + name ? name : "qt_inputdlg_getdbl", TRUE, LineEdit ); +#ifndef QT_NO_WIDGET_TOPEXTRA + dlg.setCaption( caption ); +#endif + dlg.lineEdit()->setValidator( new QDoubleValidator( minValue, maxValue, decimals, dlg.lineEdit() ) ); + dlg.lineEdit()->setText( QString::number( value, 'f', decimals ) ); + dlg.lineEdit()->selectAll(); + + bool accepted = ( dlg.exec() == QDialog::Accepted ); + if ( ok ) + *ok = accepted; + return dlg.lineEdit()->text().toDouble(); +} + +/*! + Static convenience function to let the user select an item from a + string list. \a caption is the text which is displayed in the title + bar of the dialog. \a label is the text which is shown to the user (it + should say what should be entered). \a list is the + string list which is inserted into the combobox, and \a current is the number + of the item which should be the current item. If \a editable is TRUE + the user can enter their own text; if \a editable is FALSE the user + may only select one of the existing items. + + If \a ok is not-null \e *\a ok will be set to TRUE if the user + pressed OK and to FALSE if the user pressed Cancel. The dialog's + parent is \a parent; the dialog is called \a name. The dialog will + be modal. + + This function returns the text of the current item, or if \a + editable is TRUE, the current text of the combobox. + + Use this static function like this: + + \code + QStringList lst; + lst << "First" << "Second" << "Third" << "Fourth" << "Fifth"; + bool ok; + QString res = QInputDialog::getItem( + "MyApp 3000", "Select an item:", lst, 1, TRUE, &ok, + this ); + if ( ok ) { + // user selected an item and pressed OK + } else { + // user pressed Cancel + } + \endcode +*/ + +QString QInputDialog::getItem( const QString &caption, const QString &label, const QStringList &list, + int current, bool editable, + bool *ok, QWidget *parent, const char *name ) +{ + QInputDialog *dlg = new QInputDialog( label, parent, name ? name : "qt_inputdlg_getitem", TRUE, editable ? EditableComboBox : ComboBox ); +#ifndef QT_NO_WIDGET_TOPEXTRA + dlg->setCaption( caption ); +#endif + if ( editable ) { + dlg->editableComboBox()->insertStringList( list ); + dlg->editableComboBox()->setCurrentItem( current ); + } else { + dlg->comboBox()->insertStringList( list ); + dlg->comboBox()->setCurrentItem( current ); + } + + bool ok_ = FALSE; + QString result; + ok_ = dlg->exec() == QDialog::Accepted; + if ( ok ) + *ok = ok_; + if ( editable ) + result = dlg->editableComboBox()->currentText(); + else + result = dlg->comboBox()->currentText(); + + delete dlg; + return result; +} + +/*! + \internal + + This slot is invoked when the text is changed; the new text is passed + in \a s. +*/ + +void QInputDialog::textChanged( const QString &s ) +{ + bool on = TRUE; + + if ( d->lineEdit->validator() ) { + QString str = d->lineEdit->text(); + int index = d->lineEdit->cursorPosition(); + on = ( d->lineEdit->validator()->validate(str, index) == + QValidator::Acceptable ); + } else if ( type() != LineEdit ) { + on = !s.isEmpty(); + } + d->ok->setEnabled( on ); +} + +/*! + \internal +*/ + +void QInputDialog::tryAccept() +{ + if ( !d->lineEdit->text().isEmpty() ) + accept(); +} + +#endif diff --git a/src/dialogs/qinputdialog.h b/src/dialogs/qinputdialog.h new file mode 100644 index 0000000..8014a86 --- /dev/null +++ b/src/dialogs/qinputdialog.h @@ -0,0 +1,107 @@ +/**************************************************************************** +** +** Definition of QInputDialog class +** +** Created : 991212 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QINPUTDIALOG_H +#define QINPUTDIALOG_H + +#ifndef QT_H +#include "qdialog.h" +#include "qstring.h" +#include "qlineedit.h" +#endif // QT_H + +#ifndef QT_NO_INPUTDIALOG + +class QSpinBox; +class QComboBox; +class QInputDialogPrivate; + +class Q_EXPORT QInputDialog : public QDialog +{ + Q_OBJECT + +private: + enum Type { LineEdit, SpinBox, ComboBox, EditableComboBox }; + + QInputDialog( const QString &label, QWidget* parent=0, const char* name=0, + bool modal = TRUE, Type type = LineEdit ); //### 4.0: widget flag! + ~QInputDialog(); + + QLineEdit *lineEdit() const; + QSpinBox *spinBox() const; + QComboBox *comboBox() const; + QComboBox *editableComboBox() const; + + void setType( Type t ); + Type type() const; + +public: + //### 4.0: widget flag! + static QString getText( const QString &caption, const QString &label, QLineEdit::EchoMode echo = QLineEdit::Normal, + const QString &text = QString::null, bool *ok = 0, QWidget *parent = 0, const char *name = 0 ); + static int getInteger( const QString &caption, const QString &label, int value = 0, int minValue = -2147483647, + int maxValue = 2147483647, + int step = 1, bool *ok = 0, QWidget *parent = 0, const char *name = 0 ); + static double getDouble( const QString &caption, const QString &label, double value = 0, + double minValue = -2147483647, double maxValue = 2147483647, + int decimals = 1, bool *ok = 0, QWidget *parent = 0, const char *name = 0 ); + static QString getItem( const QString &caption, const QString &label, const QStringList &list, + int current = 0, bool editable = TRUE, + bool *ok = 0, QWidget *parent = 0, const char *name = 0 ); + +private slots: + void textChanged( const QString &s ); + void tryAccept(); + +private: + QInputDialogPrivate *d; + friend class QInputDialogPrivate; /* to avoid 'has no friends' warnings... */ + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QInputDialog( const QInputDialog & ); + QInputDialog &operator=( const QInputDialog & ); +#endif +}; + +#endif // QT_NO_INPUTDIALOG + +#endif // QINPUTDIALOG_H + diff --git a/src/dialogs/qmessagebox.cpp b/src/dialogs/qmessagebox.cpp new file mode 100644 index 0000000..848c008 --- /dev/null +++ b/src/dialogs/qmessagebox.cpp @@ -0,0 +1,1632 @@ +/**************************************************************************** +** +** Implementation of QMessageBox class +** +** Created : 950503 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qmessagebox.h" + +#ifndef QT_NO_MESSAGEBOX + +#include "qaccel.h" +#include "qlabel.h" +#include "qpushbutton.h" +#include "qimage.h" +#include "qapplication.h" +#include "qstyle.h" +#include "qobjectlist.h" +#if defined(QT_ACCESSIBILITY_SUPPORT) +#include "qaccessible.h" +#endif +#if defined QT_NON_COMMERCIAL +#include "qnc_win.h" +#endif + + +// Internal class - don't touch + +class QMessageBoxLabel : public QLabel +{ + Q_OBJECT +public: + QMessageBoxLabel( QWidget* parent ) : QLabel( parent, "messageBoxText") + { + setAlignment( AlignAuto|ExpandTabs ); + } +}; +#include "qmessagebox.moc" + + + +// the Qt logo, for aboutQt +/* XPM */ +static const char * const qtlogo_xpm[] = { +/* width height ncolors chars_per_pixel */ +"50 50 17 1", +/* colors */ +" c #000000", +". c #495808", +"X c #2A3304", +"o c #242B04", +"O c #030401", +"+ c #9EC011", +"@ c #93B310", +"# c #748E0C", +"$ c #A2C511", +"% c #8BA90E", +"& c #99BA10", +"* c #060701", +"= c #181D02", +"- c #212804", +"; c #61770A", +": c #0B0D01", +"/ c None", +/* pixels */ +"/$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$/", +"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$$$$$+++$$$$$$$$$$$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$@;.o=::=o.;@$$$$$$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$$$$+#X* **X#+$$$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$$$#oO* O **o#+$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$&.* OO O*.&$$$$$$$$$$$$$", +"$$$$$$$$$$$$@XOO * OO X&$$$$$$$$$$$$", +"$$$$$$$$$$$@XO OO O **:::OOO OOO X@$$$$$$$$$$$", +"$$$$$$$$$$&XO O-;#@++@%.oOO X&$$$$$$$$$$", +"$$$$$$$$$$.O : *-#+$$$$$$$$+#- : O O*.$$$$$$$$$$", +"$$$$$$$$$#*OO O*.&$$$$$$$$$$$$+.OOOO **#$$$$$$$$$", +"$$$$$$$$+-OO O *;$$$$$$$$$$$&$$$$;* o+$$$$$$$$", +"$$$$$$$$#O* O .+$$$$$$$$$$@X;$$$+.O *#$$$$$$$$", +"$$$$$$$$X* -&$$$$$$$$$$@- :;$$$&- OX$$$$$$$$", +"$$$$$$$@*O *O#$$$$$$$$$$@oOO**;$$$# O*%$$$$$$$", +"$$$$$$$; -+$$$$$$$$$@o O OO ;+$$-O *;$$$$$$$", +"$$$$$$$. ;$$$$$$$$$@-OO OO X&$$;O .$$$$$$$", +"$$$$$$$o *#$$$$$$$$@o O O O-@$$$#O *o$$$$$$$", +"$$$$$$+= *@$$$$$$$@o* OO -@$$$$&: =$$$$$$$", +"$$$$$$+: :+$$$$$$@- *-@$$$$$$: :+$$$$$$", +"$$$$$$+: :+$$$$$@o* O *-@$$$$$$: :+$$$$$$", +"$$$$$$$= :@$$$$@o*OOO -@$$$$@: =+$$$$$$", +"$$$$$$$- O%$$$@o* O O O O-@$$$#* OX$$$$$$$", +"$$$$$$$. O *O;$$&o O*O* *O -@$$; O.$$$$$$$", +"$$$$$$$;* Oo+$$;O*O:OO-- Oo@+= *;$$$$$$$", +"$$$$$$$@* O O#$$$;*OOOo@@-O Oo;O* **@$$$$$$$", +"$$$$$$$$X* OOO-+$$$;O o@$$@- O O OX$$$$$$$$", +"$$$$$$$$#* * O.$$$$;X@$$$$@-O O O#$$$$$$$$", +"$$$$$$$$+oO O OO.+$$+&$$$$$$@-O o+$$$$$$$$", +"$$$$$$$$$#* **.&$$$$$$$$$$@o OO:#$$$$$$$$$", +"$$$$$$$$$+. O* O-#+$$$$$$$$+;O OOO:@$$$$$$$$$", +"$$$$$$$$$$&X *O -;#@++@#;=O O -@$$$$$$$$", +"$$$$$$$$$$$&X O O*O::::O OO Oo@$$$$$$$", +"$$$$$$$$$$$$@XOO OO O*X+$$$$$$", +"$$$$$$$$$$$$$&.* ** O :: *:#$$$$$$$", +"$$$$$$$$$$$$$$$#o*OO O Oo#@-OOO=#$$$$$$$$", +"$$$$$$$$$$$$$$$$+#X:* * O**X#+$$@-*:#$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$%;.o=::=o.#@$$$$$$@X#$$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$$$$$$+++$$$$$$$$$$$+$$$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", +"$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$", +"/$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$/", +}; + + +/*! + \class QMessageBox + \brief The QMessageBox class provides a modal dialog with a short message, an icon, and some buttons. + \ingroup dialogs + \mainclass + + Message boxes are used to provide informative messages and to ask + simple questions. + + QMessageBox provides a range of different messages, arranged + roughly along two axes: severity and complexity. + + Severity is + \table + \row + \i \img qmessagebox-quest.png + \i Question + \i For message boxes that ask a question as part of normal + operation. Some style guides recommend using Information for this + purpose. + \row + \i \img qmessagebox-info.png + \i Information + \i For message boxes that are part of normal operation. + \row + \i \img qmessagebox-warn.png + \i Warning + \i For message boxes that tell the user about unusual errors. + \row + \i \img qmessagebox-crit.png + \i Critical + \i For message boxes that tell the user about critical errors. + \endtable + + The message box has a different icon for each of the severity levels. + + Complexity is one button (OK) for simple messages, or two or even + three buttons for questions. + + There are static functions for the most common cases. + + Examples: + + If a program is unable to find a supporting file, but can do perfectly + well without it: + + \code + QMessageBox::information( this, "Application name", + "Unable to find the user preferences file.\n" + "The factory default will be used instead." ); + \endcode + + question() is useful for simple yes/no questions: + + \code + if ( QFile::exists( filename ) && + QMessageBox::question( + this, + tr("Overwrite File? -- Application Name"), + tr("A file called %1 already exists." + "Do you want to overwrite it?") + .arg( filename ), + tr("&Yes"), tr("&No"), + QString::null, 0, 1 ) ) + return false; + \endcode + + warning() can be used to tell the user about unusual errors, or + errors which can't be easily fixed: + + \code + switch( QMessageBox::warning( this, "Application name", + "Could not connect to the <mumble> server.\n" + "This program can't function correctly " + "without the server.\n\n", + "Retry", + "Quit", 0, 0, 1 ) ) { + case 0: // The user clicked the Retry again button or pressed Enter + // try again + break; + case 1: // The user clicked the Quit or pressed Escape + // exit + break; + } + \endcode + + The text part of all message box messages can be either rich text + or plain text. If you specify a rich text formatted string, it + will be rendered using the default stylesheet. See + QStyleSheet::defaultSheet() for details. With certain strings that + contain XML meta characters, the auto-rich text detection may + fail, interpreting plain text incorrectly as rich text. In these + rare cases, use QStyleSheet::convertFromPlainText() to convert + your plain text string to a visually equivalent rich text string + or set the text format explicitly with setTextFormat(). + + Note that the Microsoft Windows User Interface Guidelines + recommend using the application name as the window's caption. + + Below are more examples of how to use the static member functions. + After these examples you will find an overview of the non-static + member functions. + + Exiting a program is part of its normal operation. If there is + unsaved data the user probably should be asked if they want to + save the data. For example: + + \code + switch( QMessageBox::information( this, "Application name here", + "The document contains unsaved changes\n" + "Do you want to save the changes before exiting?", + "&Save", "&Discard", "Cancel", + 0, // Enter == button 0 + 2 ) ) { // Escape == button 2 + case 0: // Save clicked or Alt+S pressed or Enter pressed. + // save + break; + case 1: // Discard clicked or Alt+D pressed + // don't save but exit + break; + case 2: // Cancel clicked or Escape pressed + // don't exit + break; + } + \endcode + + The Escape button cancels the entire exit operation, and pressing + Enter causes the changes to be saved before the exit occurs. + + Disk full errors are unusual and they certainly can be hard to + correct. This example uses predefined buttons instead of + hard-coded button texts: + + \code + switch( QMessageBox::warning( this, "Application name here", + "Could not save the user preferences,\n" + "because the disk is full. You can delete\n" + "some files and press Retry, or you can\n" + "abort the Save Preferences operation.", + QMessageBox::Retry | QMessageBox::Default, + QMessageBox::Abort | QMessageBox::Escape )) { + case QMessageBox::Retry: // Retry clicked or Enter pressed + // try again + break; + case QMessageBox::Abort: // Abort clicked or Escape pressed + // abort + break; + } + \endcode + + The critical() function should be reserved for critical errors. In + this example errorDetails is a QString or const char*, and QString + is used to concatenate several strings: + + \code + QMessageBox::critical( 0, "Application name here", + QString("An internal error occurred. Please ") + + "call technical support at 1234-56789 and report\n"+ + "these numbers:\n\n" + errorDetails + + "\n\nApplication will now exit." ); + \endcode + + In this example an OK button is displayed. + + QMessageBox provides a very simple About box which displays an + appropriate icon and the string you provide: + + \code + QMessageBox::about( this, "About <Application>", + "<Application> is a <one-paragraph blurb>\n\n" + "Copyright 1991-2003 Such-and-such. " + "<License words here.>\n\n" + "For technical support, call 1234-56789 or see\n" + "http://www.such-and-such.com/Application/\n" ); + \endcode + + See about() for more information. + + If you want your users to know that the application is built using + Qt (so they know that you use high quality tools) you might like + to add an "About Qt" menu option under the Help menu to invoke + aboutQt(). + + If none of the standard message boxes is suitable, you can create a + QMessageBox from scratch and use custom button texts: + + \code + QMessageBox mb( "Application name here", + "Saving the file will overwrite the original file on the disk.\n" + "Do you really want to save?", + QMessageBox::Information, + QMessageBox::Yes | QMessageBox::Default, + QMessageBox::No, + QMessageBox::Cancel | QMessageBox::Escape ); + mb.setButtonText( QMessageBox::Yes, "Save" ); + mb.setButtonText( QMessageBox::No, "Discard" ); + switch( mb.exec() ) { + case QMessageBox::Yes: + // save and exit + break; + case QMessageBox::No: + // exit without saving + break; + case QMessageBox::Cancel: + // don't save and don't exit + break; + } + \endcode + + QMessageBox defines two enum types: Icon and an unnamed button type. + Icon defines the \c Question, \c Information, \c Warning, and \c + Critical icons for each GUI style. It is used by the constructor + and by the static member functions question(), information(), + warning() and critical(). A function called standardIcon() gives + you access to the various icons. + + The button types are: + \list + \i Ok - the default for single-button message boxes + \i Cancel - note that this is \e not automatically Escape + \i Yes + \i No + \i Abort + \i Retry + \i Ignore + \i YesAll + \i NoAll + \endlist + + Button types can be combined with two modifiers by using OR, '|': + \list + \i Default - makes pressing Enter equivalent to + clicking this button. Normally used with Ok, Yes or similar. + \i Escape - makes pressing Escape equivalent to clicking this button. + Normally used with Abort, Cancel or similar. + \endlist + + The text(), icon() and iconPixmap() functions provide access to the + current text and pixmap of the message box. The setText(), setIcon() + and setIconPixmap() let you change it. The difference between + setIcon() and setIconPixmap() is that the former accepts a + QMessageBox::Icon and can be used to set standard icons, whereas the + latter accepts a QPixmap and can be used to set custom icons. + + setButtonText() and buttonText() provide access to the buttons. + + QMessageBox has no signals or slots. + + <img src=qmsgbox-m.png> <img src=qmsgbox-w.png> + + \sa QDialog, + \link http://www.iarchitect.com/errormsg.htm + Isys on error messages \endlink, + \link guibooks.html#fowler GUI Design Handbook: Message Box \endlink +*/ + + +/*! + \enum QMessageBox::Icon + + This enum has the following values: + + \value NoIcon the message box does not have any icon. + + \value Question an icon indicating that + the message is asking a question. + + \value Information an icon indicating that + the message is nothing out of the ordinary. + + \value Warning an icon indicating that the + message is a warning, but can be dealt with. + + \value Critical an icon indicating that + the message represents a critical problem. + +*/ + + +struct QMessageBoxData { + QMessageBoxData(QMessageBox* parent) : + iconLabel( parent, "icon" ) + { + } + + int numButtons; // number of buttons + QMessageBox::Icon icon; // message box icon + QLabel iconLabel; // label holding any icon + int button[3]; // button types + int defButton; // default button (index) + int escButton; // escape button (index) + QSize buttonSize; // button size + QPushButton *pb[3]; // buttons +}; + +static const int LastButton = QMessageBox::NoAll; + +/* + NOTE: The table of button texts correspond to the button enum. +*/ + +#ifndef Q_OS_TEMP +static const char * const mb_texts[] = { +#else +const char * mb_texts[] = { +#endif + 0, + QT_TRANSLATE_NOOP("QMessageBox","OK"), + QT_TRANSLATE_NOOP("QMessageBox","Cancel"), + QT_TRANSLATE_NOOP("QMessageBox","&Yes"), + QT_TRANSLATE_NOOP("QMessageBox","&No"), + QT_TRANSLATE_NOOP("QMessageBox","&Abort"), + QT_TRANSLATE_NOOP("QMessageBox","&Retry"), + QT_TRANSLATE_NOOP("QMessageBox","&Ignore"), + QT_TRANSLATE_NOOP("QMessageBox","Yes to &All"), + QT_TRANSLATE_NOOP("QMessageBox","N&o to All"), + 0 +}; + +/*! + Constructs a message box with no text and a button with the label + "OK". + + If \a parent is 0, the message box becomes an application-global + modal dialog box. If \a parent is a widget, the message box + becomes modal relative to \a parent. + + The \a parent and \a name arguments are passed to the QDialog + constructor. +*/ + +QMessageBox::QMessageBox( QWidget *parent, const char *name ) + : QDialog( parent, name, TRUE, WStyle_Customize | WStyle_DialogBorder | WStyle_Title | WStyle_SysMenu ) +{ + init( Ok, 0, 0 ); +} + + +/*! + Constructs a message box with a \a caption, a \a text, an \a icon, + and up to three buttons. + + The \a icon must be one of the following: + \list + \i QMessageBox::NoIcon + \i QMessageBox::Question + \i QMessageBox::Information + \i QMessageBox::Warning + \i QMessageBox::Critical + \endlist + + Each button, \a button0, \a button1 and \a button2, can have one + of the following values: + \list + \i QMessageBox::NoButton + \i QMessageBox::Ok + \i QMessageBox::Cancel + \i QMessageBox::Yes + \i QMessageBox::No + \i QMessageBox::Abort + \i QMessageBox::Retry + \i QMessageBox::Ignore + \i QMessageBox::YesAll + \i QMessageBox::NoAll + \endlist + + Use QMessageBox::NoButton for the later parameters to have fewer + than three buttons in your message box. If you don't specify any + buttons at all, QMessageBox will provide an Ok button. + + One of the buttons can be OR-ed with the \c QMessageBox::Default + flag to make it the default button (clicked when Enter is + pressed). + + One of the buttons can be OR-ed with the \c QMessageBox::Escape + flag to make it the cancel or close button (clicked when Escape is + pressed). + + Example: + \code + QMessageBox mb( "Application Name", + "Hardware failure.\n\nDisk error detected\nDo you want to stop?", + QMessageBox::Question, + QMessageBox::Yes | QMessageBox::Default, + QMessageBox::No | QMessageBox::Escape, + QMessageBox::NoButton ); + if ( mb.exec() == QMessageBox::No ) + // try again + \endcode + + If \a parent is 0, the message box becomes an application-global + modal dialog box. If \a parent is a widget, the message box + becomes modal relative to \a parent. + + If \a modal is TRUE the message box is modal; otherwise it + is modeless. + + The \a parent, \a name, \a modal, and \a f arguments are passed to + the QDialog constructor. + + \sa setCaption(), setText(), setIcon() +*/ + +QMessageBox::QMessageBox( const QString& caption, + const QString &text, Icon icon, + int button0, int button1, int button2, + QWidget *parent, const char *name, + bool modal, WFlags f ) + : QDialog( parent, name, modal, f | WStyle_Customize | WStyle_DialogBorder | WStyle_Title | WStyle_SysMenu ) +{ + init( button0, button1, button2 ); +#ifndef QT_NO_WIDGET_TOPEXTRA + setCaption( caption ); +#endif + setText( text ); + setIcon( icon ); +} + + +/*! + Destroys the message box. +*/ + +QMessageBox::~QMessageBox() +{ + delete mbd; +} + +static QString * translatedTextAboutQt = 0; + +void QMessageBox::init( int button0, int button1, int button2 ) +{ + if ( !translatedTextAboutQt ) { + translatedTextAboutQt = new QString; + +#if defined(QT_NON_COMMERCIAL) + QT_NC_MSGBOX +#else + *translatedTextAboutQt = tr( + "<h3>About Qt</h3>" + "<p>This program uses Qt version %1.</p>" + "<p>Qt is a C++ toolkit for multiplatform GUI & " + "application development.</p>" + "<p>Qt provides single-source " + "portability across MS Windows, Mac OS X, " + "Linux, and all major commercial Unix variants." + "<br>Qt is also available for embedded devices.</p>" + "<p>Qt is a Trolltech product. " + "See <tt>http://www.trolltech.com/qt/</tt> " + "for more information.</p>" + ).arg( QT_VERSION_STR ); +#endif + + } + label = new QMessageBoxLabel( this ); + Q_CHECK_PTR( label ); + + if ( (button2 && !button1) || (button1 && !button0) ) { +#if defined(QT_CHECK_RANGE) + qWarning( "QMessageBox: Inconsistent button parameters" ); +#endif + button0 = button1 = button2 = 0; + } + mbd = new QMessageBoxData(this); + Q_CHECK_PTR( mbd ); + mbd->icon = NoIcon; + mbd->iconLabel.setPixmap( QPixmap() ); + mbd->numButtons = 0; + mbd->button[0] = button0; + mbd->button[1] = button1; + mbd->button[2] = button2; + mbd->defButton = -1; + mbd->escButton = -1; + int i; + for ( i=0; i<3; i++ ) { + int b = mbd->button[i]; + if ( (b & Default) ) { + if ( mbd->defButton >= 0 ) { +#if defined(QT_CHECK_RANGE) + qWarning( "QMessageBox: There can be at most one " + "default button" ); +#endif + } else { + mbd->defButton = i; + } + } + if ( (b & Escape) ) { + if ( mbd->escButton >= 0 ) { +#if defined(QT_CHECK_RANGE) + qWarning( "QMessageBox: There can be at most one " + "escape button" ); +#endif + } else { + mbd->escButton = i; + } + } + b &= ButtonMask; + if ( b == 0 ) { + if ( i == 0 ) // no buttons, add an Ok button + b = Ok; + } else if ( b < 0 || b > LastButton ) { +#if defined(QT_CHECK_RANGE) + qWarning( "QMessageBox: Invalid button specifier" ); +#endif + b = Ok; + } else { + if ( i > 0 && mbd->button[i-1] == 0 ) { +#if defined(QT_CHECK_RANGE) + qWarning( "QMessageBox: Inconsistent button parameters; " + "button %d defined but not button %d", + i+1, i ); +#endif + b = 0; + } + } + mbd->button[i] = b; + if ( b ) + mbd->numButtons++; + } + for ( i=0; i<3; i++ ) { + if ( i >= mbd->numButtons ) { + mbd->pb[i] = 0; + } else { + QCString buttonName; + buttonName.sprintf( "button%d", i+1 ); + mbd->pb[i] = new QPushButton( + tr(mb_texts[mbd->button[i]]), + this, buttonName ); + if ( mbd->defButton == i ) { + mbd->pb[i]->setDefault( TRUE ); + mbd->pb[i]->setFocus(); + } + mbd->pb[i]->setAutoDefault( TRUE ); + mbd->pb[i]->setFocusPolicy( QWidget::StrongFocus ); + connect( mbd->pb[i], SIGNAL(clicked()), SLOT(buttonClicked()) ); + } + } + resizeButtons(); + reserved1 = reserved2 = 0; +} + + +int QMessageBox::indexOf( int button ) const +{ + int index = -1; + for ( int i=0; i<mbd->numButtons; i++ ) { + if ( mbd->button[i] == button ) { + index = i; + break; + } + } + return index; +} + + +void QMessageBox::resizeButtons() +{ + int i; + QSize maxSize; + for ( i=0; i<mbd->numButtons; i++ ) { + QSize s = mbd->pb[i]->sizeHint(); + maxSize.setWidth( QMAX(maxSize.width(), s.width()) ); + maxSize.setHeight( QMAX(maxSize.height(),s.height()) ); + } + mbd->buttonSize = maxSize; + for ( i=0; i<mbd->numButtons; i++ ) + mbd->pb[i]->resize( maxSize ); +} + + +/*! + \property QMessageBox::text + \brief the message box text to be displayed. + + The text will be interpreted either as a plain text or as rich + text, depending on the text format setting (\l + QMessageBox::textFormat). The default setting is \c AutoText, i.e. + the message box will try to auto-detect the format of the text. + + The default value of this property is QString::null. + + \sa textFormat +*/ +QString QMessageBox::text() const +{ + return label->text(); +} + + +void QMessageBox::setText( const QString &text ) +{ + label->setText( text ); +} + + +/*! + \property QMessageBox::icon + \brief the message box's icon + + The icon of the message box can be one of the following predefined + icons: + \list + \i QMessageBox::NoIcon + \i QMessageBox::Question + \i QMessageBox::Information + \i QMessageBox::Warning + \i QMessageBox::Critical + \endlist + + The actual pixmap used for displaying the icon depends on the + current \link QWidget::style() GUI style\endlink. You can also set + a custom pixmap icon using the \l QMessageBox::iconPixmap + property. The default icon is QMessageBox::NoIcon. + + \sa iconPixmap +*/ + +QMessageBox::Icon QMessageBox::icon() const +{ + return mbd->icon; +} + +void QMessageBox::setIcon( Icon icon ) +{ + setIconPixmap( standardIcon(icon) ); + mbd->icon = icon; +} + +/*! + \obsolete + + Returns the pixmap used for a standard icon. This + allows the pixmaps to be used in more complex message boxes. + \a icon specifies the required icon, e.g. QMessageBox::Information, + QMessageBox::Warning or QMessageBox::Critical. + + \a style is unused. +*/ + +QPixmap QMessageBox::standardIcon( Icon icon, GUIStyle style) +{ + Q_UNUSED(style); + return QMessageBox::standardIcon(icon); +} + + +/*! + Returns the pixmap used for a standard icon. This allows the + pixmaps to be used in more complex message boxes. \a icon + specifies the required icon, e.g. QMessageBox::Question, + QMessageBox::Information, QMessageBox::Warning or + QMessageBox::Critical. +*/ + +QPixmap QMessageBox::standardIcon( Icon icon ) +{ + QPixmap pm; + switch ( icon ) { + case Information: + pm = QApplication::style().stylePixmap( QStyle::SP_MessageBoxInformation ); + break; + case Warning: + pm = QApplication::style().stylePixmap( QStyle::SP_MessageBoxWarning ); + break; + case Critical: + pm = QApplication::style().stylePixmap( QStyle::SP_MessageBoxCritical ); + break; + case Question: + pm = QApplication::style().stylePixmap( QStyle::SP_MessageBoxQuestion ); + default: + break; + } + return pm; +} + + +/*! + \property QMessageBox::iconPixmap + \brief the current icon + + The icon currently used by the message box. Note that it's often + hard to draw one pixmap that looks appropriate in both Motif and + Windows GUI styles; you may want to draw two pixmaps. + + \sa icon +*/ + +const QPixmap *QMessageBox::iconPixmap() const +{ + return mbd->iconLabel.pixmap(); +} + + +void QMessageBox::setIconPixmap( const QPixmap &pixmap ) +{ + mbd->iconLabel.setPixmap(pixmap); + mbd->icon = NoIcon; +} + + +/*! + Returns the text of the message box button \a button, or + QString::null if the message box does not contain the button. + + \sa setButtonText() +*/ + +QString QMessageBox::buttonText( int button ) const +{ + int index = indexOf(button); + return index >= 0 && mbd->pb[index] + ? mbd->pb[index]->text() + : QString::null; +} + + +/*! + Sets the text of the message box button \a button to \a text. + Setting the text of a button that is not in the message box is + silently ignored. + + \sa buttonText() +*/ + +void QMessageBox::setButtonText( int button, const QString &text ) +{ + int index = indexOf(button); + if ( index >= 0 && mbd->pb[index] ) { + mbd->pb[index]->setText( text ); + resizeButtons(); + } +} + + +/*! + \internal + Internal slot to handle button clicks. +*/ + +void QMessageBox::buttonClicked() +{ + int reply = 0; + const QObject *s = sender(); + for ( int i=0; i<mbd->numButtons; i++ ) { + if ( mbd->pb[i] == s ) + reply = mbd->button[i]; + } + done( reply ); +} + + +/*! + Adjusts the size of the message box to fit the contents just before + QDialog::exec() or QDialog::show() is called. + + This function will not be called if the message box has been explicitly + resized before showing it. +*/ +void QMessageBox::adjustSize() +{ + if ( !testWState(WState_Polished) ) + polish(); + resizeButtons(); + label->adjustSize(); + QSize labelSize( label->size() ); + int n = mbd->numButtons; + int bw = mbd->buttonSize.width(); + int bh = mbd->buttonSize.height(); + int border = bh / 2 - style().pixelMetric(QStyle::PM_ButtonDefaultIndicator); + if ( border <= 0 ) + border = 10; + int btn_spacing = 7; + if ( style().styleHint(QStyle::SH_GUIStyle) == MotifStyle ) + btn_spacing = border; +#ifndef Q_OS_TEMP + int buttons = mbd->numButtons * bw + (n-1) * btn_spacing; + int h = bh; +#else + int visibleButtons = 0; + for ( int i = 0; i < mbd->numButtons; ++i ) + visibleButtons += mbd->pb[i]->isVisible() ? 1 : 0; + int buttons = visibleButtons == 0 ? 0 : visibleButtons * bw + (visibleButtons-1) * btn_spacing; + int h = visibleButtons == 0 ? 0 : bh; + n = visibleButtons; +#endif + if ( labelSize.height() ) + h += labelSize.height() + 3*border; + else + h += 2*border; + int lmargin = 0; + if ( mbd->iconLabel.pixmap() && mbd->iconLabel.pixmap()->width() ) { + mbd->iconLabel.adjustSize(); + lmargin += mbd->iconLabel.width() + border; + if ( h < mbd->iconLabel.height() + 3*border + bh && n ) + h = mbd->iconLabel.height() + 3*border + bh; + } + int w = QMAX( buttons, labelSize.width() + lmargin ) + 2*border; + QRect screen = QApplication::desktop()->screenGeometry( pos() ); + if ( w > screen.width() ) + w = screen.width(); + resize( w, h ); + setMinimumSize( size() ); +#ifdef Q_WS_MAC + setMaximumSize(size()); +#endif +} + + +/*!\reimp +*/ +void QMessageBox::resizeEvent( QResizeEvent * ) +{ + int i; + int n = mbd->numButtons; + int bw = mbd->buttonSize.width(); + int bh = mbd->buttonSize.height(); +#ifdef Q_OS_TEMP + int visibleButtons = 0; + for ( i = 0; i < n; ++i ) + visibleButtons += mbd->pb[i]->isVisible() ? 1 : 0; + n = visibleButtons; + bw = visibleButtons == 0 ? 0 : bw; + bh = visibleButtons == 0 ? 0 : bh; +#endif + int border = bh / 2 - style().pixelMetric(QStyle::PM_ButtonDefaultIndicator); + if ( border <= 0 ) + border = 10; + int btn_spacing = 7; + if ( style().styleHint(QStyle::SH_GUIStyle) == MotifStyle ) + btn_spacing = border; + int lmargin = 0; + mbd->iconLabel.adjustSize(); + bool rtl = QApplication::reverseLayout(); + if (rtl) + mbd->iconLabel.move(width() - border - mbd->iconLabel.width(), border); + else + mbd->iconLabel.move(border, border); + if ( mbd->iconLabel.pixmap() && mbd->iconLabel.pixmap()->width() ) + lmargin += mbd->iconLabel.width() + border; + label->setGeometry((rtl ? 0 : lmargin) + border, + border, + width() - lmargin -2*border, + height() - 3*border - bh); + int extra_space = (width() - bw*n - 2*border - (n-1)*btn_spacing); + if ( style().styleHint(QStyle::SH_GUIStyle) == MotifStyle ) + for ( i=0; i<n; i++ ) + mbd->pb[rtl ? n - i - 1 : i]->move(border + i*bw + i*btn_spacing + extra_space*(i+1)/(n+1), + height() - border - bh ); + else + for ( i=0; i<n; i++ ) + mbd->pb[rtl ? n - i - 1 : i]->move(border + i*bw + extra_space/2 + i*btn_spacing, + height() - border - bh ); +} + + +/*!\reimp +*/ +void QMessageBox::keyPressEvent( QKeyEvent *e ) +{ + if ( e->key() == Key_Escape ) { + if ( mbd->escButton >= 0 ) { + QPushButton *pb = mbd->pb[mbd->escButton]; + pb->animateClick(); + e->accept(); + return; + } + } +#ifndef QT_NO_ACCEL + if ( !( e->state() & AltButton ) ) { + QObjectList *list = queryList( "QPushButton" ); + QObjectListIt it( *list ); + QPushButton *pb; + while ( (pb = (QPushButton*)it.current()) ) { + int key = e->key() & ~(MODIFIER_MASK|UNICODE_ACCEL); + int acc = pb->accel() & ~(MODIFIER_MASK|UNICODE_ACCEL); + if ( key && acc && acc == key ) { + delete list; + emit pb->animateClick(); + return; + } + ++it; + } + delete list; + } +#endif + QDialog::keyPressEvent( e ); +} + +/*!\reimp +*/ +void QMessageBox::showEvent( QShowEvent *e ) +{ +#if defined(QT_ACCESSIBILITY_SUPPORT) + QAccessible::updateAccessibility( this, 0, QAccessible::Alert ); +#endif + QDialog::showEvent( e ); +} + +/*!\reimp +*/ +void QMessageBox::closeEvent( QCloseEvent *e ) +{ + QDialog::closeEvent( e ); + if ( mbd->escButton != -1 ) + setResult( mbd->button[mbd->escButton] ); +} + +/***************************************************************************** + Static QMessageBox functions + *****************************************************************************/ + +/*!\fn int QMessageBox::message( const QString &,const QString&,const QString&,QWidget*,const char * ) + \obsolete + Opens a modal message box directly using the specified parameters. + + Please use information(), warning(), question(), or critical() instead. +*/ + +/*! \fn bool QMessageBox::query( const QString &,const QString&,const QString&,const QString&,QWidget *, const char * ) + \obsolete + Queries the user using a modal message box with two buttons. + Note that \a caption is not always shown, it depends on the window manager. + + Please use information(), question(), warning(), or critical() instead. +*/ + +/*! + Opens an information message box with the caption \a caption and + the text \a text. The dialog may have up to three buttons. Each of + the buttons, \a button0, \a button1 and \a button2 may be set to + one of the following values: + + \list + \i QMessageBox::NoButton + \i QMessageBox::Ok + \i QMessageBox::Cancel + \i QMessageBox::Yes + \i QMessageBox::No + \i QMessageBox::Abort + \i QMessageBox::Retry + \i QMessageBox::Ignore + \i QMessageBox::YesAll + \i QMessageBox::NoAll + \endlist + + If you don't want all three buttons, set the last button, or last + two buttons to QMessageBox::NoButton. + + One button can be OR-ed with \c QMessageBox::Default, and one + button can be OR-ed with \c QMessageBox::Escape. + + Returns the identity (QMessageBox::Ok, or QMessageBox::No, etc.) + of the button that was clicked. + + If \a parent is 0, the message box becomes an application-global + modal dialog box. If \a parent is a widget, the message box + becomes modal relative to \a parent. + + \sa question(), warning(), critical() +*/ + +int QMessageBox::information( QWidget *parent, + const QString& caption, const QString& text, + int button0, int button1, int button2 ) +{ + QMessageBox *mb = new QMessageBox( caption, text, Information, + button0, button1, button2, + parent, "qt_msgbox_information", TRUE, + WDestructiveClose); + Q_CHECK_PTR( mb ); + return mb->exec(); +} + +/*! + Opens a question message box with the caption \a caption and the + text \a text. The dialog may have up to three buttons. Each of the + buttons, \a button0, \a button1 and \a button2 may be set to one + of the following values: + + \list + \i QMessageBox::NoButton + \i QMessageBox::Ok + \i QMessageBox::Cancel + \i QMessageBox::Yes + \i QMessageBox::No + \i QMessageBox::Abort + \i QMessageBox::Retry + \i QMessageBox::Ignore + \i QMessageBox::YesAll + \i QMessageBox::NoAll + \endlist + + If you don't want all three buttons, set the last button, or last + two buttons to QMessageBox::NoButton. + + One button can be OR-ed with \c QMessageBox::Default, and one + button can be OR-ed with \c QMessageBox::Escape. + + Returns the identity (QMessageBox::Yes, or QMessageBox::No, etc.) + of the button that was clicked. + + If \a parent is 0, the message box becomes an application-global + modal dialog box. If \a parent is a widget, the message box + becomes modal relative to \a parent. + + \sa information(), warning(), critical() +*/ + +int QMessageBox::question( QWidget *parent, + const QString& caption, const QString& text, + int button0, int button1, int button2 ) +{ + QMessageBox *mb = new QMessageBox( caption, text, Question, + button0, button1, button2, + parent, "qt_msgbox_information", TRUE, + WDestructiveClose); + Q_CHECK_PTR( mb ); + return mb->exec(); +} + + +/*! + Opens a warning message box with the caption \a caption and the + text \a text. The dialog may have up to three buttons. Each of the + button parameters, \a button0, \a button1 and \a button2 may be + set to one of the following values: + + \list + \i QMessageBox::NoButton + \i QMessageBox::Ok + \i QMessageBox::Cancel + \i QMessageBox::Yes + \i QMessageBox::No + \i QMessageBox::Abort + \i QMessageBox::Retry + \i QMessageBox::Ignore + \i QMessageBox::YesAll + \i QMessageBox::NoAll + \endlist + + If you don't want all three buttons, set the last button, or last + two buttons to QMessageBox::NoButton. + + One button can be OR-ed with \c QMessageBox::Default, and one + button can be OR-ed with \c QMessageBox::Escape. + + Returns the identity (QMessageBox::Ok, or QMessageBox::No, etc.) + of the button that was clicked. + + If \a parent is 0, the message box becomes an application-global + modal dialog box. If \a parent is a widget, the message box + becomes modal relative to \a parent. + + \sa information(), question(), critical() +*/ + +int QMessageBox::warning( QWidget *parent, + const QString& caption, const QString& text, + int button0, int button1, int button2 ) +{ + QMessageBox *mb = new QMessageBox( caption, text, Warning, + button0, button1, button2, + parent, "qt_msgbox_warning", TRUE, + WDestructiveClose); + Q_CHECK_PTR( mb ); + return mb->exec(); +} + + +/*! + Opens a critical message box with the caption \a caption and the + text \a text. The dialog may have up to three buttons. Each of the + button parameters, \a button0, \a button1 and \a button2 may be + set to one of the following values: + + \list + \i QMessageBox::NoButton + \i QMessageBox::Ok + \i QMessageBox::Cancel + \i QMessageBox::Yes + \i QMessageBox::No + \i QMessageBox::Abort + \i QMessageBox::Retry + \i QMessageBox::Ignore + \i QMessageBox::YesAll + \i QMessageBox::NoAll + \endlist + + If you don't want all three buttons, set the last button, or last + two buttons to QMessageBox::NoButton. + + One button can be OR-ed with \c QMessageBox::Default, and one + button can be OR-ed with \c QMessageBox::Escape. + + Returns the identity (QMessageBox::Ok, or QMessageBox::No, etc.) + of the button that was clicked. + + If \a parent is 0, the message box becomes an application-global + modal dialog box. If \a parent is a widget, the message box + becomes modal relative to \a parent. + + \sa information(), question(), warning() +*/ + +int QMessageBox::critical( QWidget *parent, + const QString& caption, const QString& text, + int button0, int button1, int button2 ) +{ + QMessageBox *mb = new QMessageBox( caption, text, Critical, + button0, button1, button2, + parent, "qt_msgbox_critical", TRUE, + WDestructiveClose); + Q_CHECK_PTR( mb ); + return mb->exec(); +} + + +/*! + Displays a simple about box with caption \a caption and text \a + text. The about box's parent is \a parent. + + about() looks for a suitable icon in four locations: + \list 1 + \i It prefers \link QWidget::icon() parent->icon() \endlink if that exists. + \i If not, it tries the top-level widget containing \a parent. + \i If that fails, it tries the \link + QApplication::mainWidget() main widget. \endlink + \i As a last resort it uses the Information icon. + \endlist + + The about box has a single button labelled "OK". + + \sa QWidget::icon() QApplication::mainWidget() +*/ + +void QMessageBox::about( QWidget *parent, const QString &caption, + const QString& text ) +{ + QMessageBox *mb = new QMessageBox( caption, text, + Information, + Ok + Default, 0, 0, + parent, "qt_msgbox_simple_about_box", TRUE, + WDestructiveClose); + Q_CHECK_PTR( mb ); +#ifndef QT_NO_WIDGET_TOPEXTRA + const QPixmap *pm = parent ? parent->icon() : 0; + if ( pm && !pm->isNull() ) + mb->setIconPixmap( *pm ); + else { + pm = parent ? parent->topLevelWidget()->icon() : 0; + if ( pm && !pm->isNull() ) + mb->setIconPixmap( *pm ); + else { + pm = qApp && qApp->mainWidget() ? qApp->mainWidget()->icon() : 0; + if ( pm && !pm->isNull() ) + mb->setIconPixmap( *pm ); + } + } +#endif + mb->exec(); +} + + +/*! \reimp +*/ + +void QMessageBox::styleChanged( QStyle& ) +{ + if ( mbd->icon != NoIcon ) { + // Reload icon for new style + setIcon( mbd->icon ); + } +} + + +static int textBox( QWidget *parent, QMessageBox::Icon severity, + const QString& caption, const QString& text, + const QString& button0Text, + const QString& button1Text, + const QString& button2Text, + int defaultButtonNumber, + int escapeButtonNumber ) +{ + int b[3]; + b[0] = 1; + b[1] = button1Text.isEmpty() ? 0 : 2; + b[2] = button2Text.isEmpty() ? 0 : 3; + + int i; + for( i=0; i<3; i++ ) { + if ( b[i] && defaultButtonNumber == i ) + b[i] += QMessageBox::Default; + if ( b[i] && escapeButtonNumber == i ) + b[i] += QMessageBox::Escape; + } + + QMessageBox *mb = new QMessageBox( caption, text, severity, + b[0], b[1], b[2], + parent, "qt_msgbox_information", TRUE, + Qt::WDestructiveClose); + Q_CHECK_PTR( mb ); + if ( button0Text.isEmpty() ) + mb->setButtonText( 1, QMessageBox::tr(mb_texts[QMessageBox::Ok]) ); + else + mb->setButtonText( 1, button0Text ); + if ( b[1] ) + mb->setButtonText( 2, button1Text ); + if ( b[2] ) + mb->setButtonText( 3, button2Text ); + +#ifndef QT_NO_CURSOR + mb->setCursor( Qt::arrowCursor ); +#endif + return mb->exec() - 1; +} + + +/*! + \overload + + Displays an information message box with caption \a caption, text + \a text and one, two or three buttons. Returns the index of the + button that was clicked (0, 1 or 2). + + \a button0Text is the text of the first button, and is optional. + If \a button0Text is not supplied, "OK" (translated) will be used. + \a button1Text is the text of the second button, and is optional. + \a button2Text is the text of the third button, and is optional. + \a defaultButtonNumber (0, 1 or 2) is the index of the default + button; pressing Return or Enter is the same as clicking the + default button. It defaults to 0 (the first button). \a + escapeButtonNumber is the index of the Escape button; pressing + Escape is the same as clicking this button. It defaults to -1; + supply 0, 1 or 2 to make pressing Escape equivalent to clicking + the relevant button. + + If \a parent is 0, the message box becomes an application-global + modal dialog box. If \a parent is a widget, the message box + becomes modal relative to \a parent. + + Note: If you do not specify an Escape button then if the Escape + button is pressed then -1 will be returned. It is suggested that + you specify an Escape button to prevent this from happening. + + \sa question(), warning(), critical() +*/ + +int QMessageBox::information( QWidget *parent, const QString &caption, + const QString& text, + const QString& button0Text, + const QString& button1Text, + const QString& button2Text, + int defaultButtonNumber, + int escapeButtonNumber ) +{ + return textBox( parent, Information, caption, text, + button0Text, button1Text, button2Text, + defaultButtonNumber, escapeButtonNumber ); +} + +/*! + \overload + + Displays a question message box with caption \a caption, text \a + text and one, two or three buttons. Returns the index of the + button that was clicked (0, 1 or 2). + + \a button0Text is the text of the first button, and is optional. + If \a button0Text is not supplied, "OK" (translated) will be used. + \a button1Text is the text of the second button, and is optional. + \a button2Text is the text of the third button, and is optional. + \a defaultButtonNumber (0, 1 or 2) is the index of the default + button; pressing Return or Enter is the same as clicking the + default button. It defaults to 0 (the first button). \a + escapeButtonNumber is the index of the Escape button; pressing + Escape is the same as clicking this button. It defaults to -1; + supply 0, 1 or 2 to make pressing Escape equivalent to clicking + the relevant button. + + If \a parent is 0, the message box becomes an application-global + modal dialog box. If \a parent is a widget, the message box + becomes modal relative to \a parent. + + Note: If you do not specify an Escape button then if the Escape + button is pressed then -1 will be returned. It is suggested that + you specify an Escape button to prevent this from happening. + + \sa information(), warning(), critical() +*/ +int QMessageBox::question( QWidget *parent, const QString &caption, + const QString& text, + const QString& button0Text, + const QString& button1Text, + const QString& button2Text, + int defaultButtonNumber, + int escapeButtonNumber ) +{ + return textBox( parent, Question, caption, text, + button0Text, button1Text, button2Text, + defaultButtonNumber, escapeButtonNumber ); +} + + +/*! + \overload + + Displays a warning message box with a caption, a text, and 1, 2 or + 3 buttons. Returns the number of the button that was clicked (0, + 1, or 2). + + \a button0Text is the text of the first button, and is optional. + If \a button0Text is not supplied, "OK" (translated) will be used. + \a button1Text is the text of the second button, and is optional, + and \a button2Text is the text of the third button, and is + optional. \a defaultButtonNumber (0, 1 or 2) is the index of the + default button; pressing Return or Enter is the same as clicking + the default button. It defaults to 0 (the first button). \a + escapeButtonNumber is the index of the Escape button; pressing + Escape is the same as clicking this button. It defaults to -1; + supply 0, 1, or 2 to make pressing Escape equivalent to clicking + the relevant button. + + If \a parent is 0, the message box becomes an application-global + modal dialog box. If \a parent is a widget, the message box + becomes modal relative to \a parent. + + Note: If you do not specify an Escape button then if the Escape + button is pressed then -1 will be returned. It is suggested that + you specify an Escape button to prevent this from happening. + + \sa information(), question(), critical() +*/ + +int QMessageBox::warning( QWidget *parent, const QString &caption, + const QString& text, + const QString& button0Text, + const QString& button1Text, + const QString& button2Text, + int defaultButtonNumber, + int escapeButtonNumber ) +{ + return textBox( parent, Warning, caption, text, + button0Text, button1Text, button2Text, + defaultButtonNumber, escapeButtonNumber ); +} + + +/*! + \overload + + Displays a critical error message box with a caption, a text, and + 1, 2 or 3 buttons. Returns the number of the button that was + clicked (0, 1 or 2). + + \a button0Text is the text of the first button, and is optional. + If \a button0Text is not supplied, "OK" (translated) will be used. + \a button1Text is the text of the second button, and is optional, + and \a button2Text is the text of the third button, and is + optional. \a defaultButtonNumber (0, 1 or 2) is the index of the + default button; pressing Return or Enter is the same as clicking + the default button. It defaults to 0 (the first button). \a + escapeButtonNumber is the index of the Escape button; pressing + Escape is the same as clicking this button. It defaults to -1; + supply 0, 1, or 2 to make pressing Escape equivalent to clicking + the relevant button. + + If \a parent is 0, the message box becomes an application-global + modal dialog box. If \a parent is a widget, the message box + becomes modal relative to \a parent. + + \sa information(), question(), warning() +*/ + +int QMessageBox::critical( QWidget *parent, const QString &caption, + const QString& text, + const QString& button0Text, + const QString& button1Text, + const QString& button2Text, + int defaultButtonNumber, + int escapeButtonNumber ) +{ + return textBox( parent, Critical, caption, text, + button0Text, button1Text, button2Text, + defaultButtonNumber, escapeButtonNumber ); +} + + +/*! + Displays a simple message box about Qt, with caption \a caption + and centered over \a parent (if \a parent is not 0). The message + includes the version number of Qt being used by the application. + + This is useful for inclusion in the Help menu of an application. + See the examples/menu/menu.cpp example. + + QApplication provides this functionality as a slot. + + \sa QApplication::aboutQt() +*/ + +void QMessageBox::aboutQt( QWidget *parent, const QString &caption ) +{ + QMessageBox *mb = new QMessageBox( parent, "qt_msgbox_about_qt" ); + Q_CHECK_PTR( mb ); + mb->setWFlags( WDestructiveClose ); + +#ifndef QT_NO_WIDGET_TOPEXTRA + QString c = caption; + if ( c.isNull() ) + c = tr( "About Qt" ); + mb->setCaption( c ); +#endif + mb->setText( *translatedTextAboutQt ); +#ifndef QT_NO_IMAGEIO + QPixmap pm; + QImage logo( (const char **)qtlogo_xpm); + if ( qGray(mb->palette().active().text().rgb()) > + qGray(mb->palette().active().base().rgb()) ) + { + // light on dark, adjust some colors (where's 10?) + logo.setColor( 0, 0xffffffff ); + logo.setColor( 1, 0xff666666 ); + logo.setColor( 2, 0xffcccc66 ); + logo.setColor( 4, 0xffcccccc ); + logo.setColor( 6, 0xffffff66 ); + logo.setColor( 7, 0xff999999 ); + logo.setColor( 8, 0xff3333ff ); + logo.setColor( 9, 0xffffff33 ); + logo.setColor( 11, 0xffcccc99 ); + } + if ( pm.convertFromImage( logo ) ) + mb->setIconPixmap( pm ); +#endif + mb->setButtonText( 0, tr("OK") ); + if ( mb->mbd && mb->mbd->pb[0] ) { + mb->mbd->pb[0]->setAutoDefault( TRUE ); + mb->mbd->pb[0]->setFocusPolicy( QWidget::StrongFocus ); + mb->mbd->pb[0]->setDefault( TRUE ); + mb->mbd->pb[0]->setFocus(); + } + mb->exec(); +} + +/*! + \reimp +*/ + +void QMessageBox::setIcon( const QPixmap &pix ) +{ + //reimplemented to avoid compiler warning. +#ifndef QT_NO_WIDGET_TOPEXTRA + QDialog::setIcon( pix ); +#endif +} + + +/*! + \property QMessageBox::textFormat + \brief the format of the text displayed by the message box + + The current text format used by the message box. See the \l + Qt::TextFormat enum for an explanation of the possible options. + + The default format is \c AutoText. + + \sa setText() +*/ + +Qt::TextFormat QMessageBox::textFormat() const +{ + return label->textFormat(); +} + + +void QMessageBox::setTextFormat( Qt::TextFormat format ) +{ + label->setTextFormat( format ); +} + + +#endif diff --git a/src/dialogs/qmessagebox.h b/src/dialogs/qmessagebox.h new file mode 100644 index 0000000..338525b --- /dev/null +++ b/src/dialogs/qmessagebox.h @@ -0,0 +1,223 @@ +/**************************************************************************** +** +** Definition of QMessageBox class +** +** Created : 950503 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QMESSAGEBOX_H +#define QMESSAGEBOX_H + +#ifndef QT_H +#include "qdialog.h" +#endif // QT_H + +#ifndef QT_NO_MESSAGEBOX + +class QLabel; +class QPushButton; +struct QMessageBoxData; + +class Q_EXPORT QMessageBox : public QDialog +{ + Q_OBJECT + Q_ENUMS( Icon ) + Q_PROPERTY( QString text READ text WRITE setText ) + Q_PROPERTY( Icon icon READ icon WRITE setIcon ) + Q_PROPERTY( QPixmap iconPixmap READ iconPixmap WRITE setIconPixmap ) + Q_PROPERTY( TextFormat textFormat READ textFormat WRITE setTextFormat ) + +public: + enum Icon { NoIcon = 0, Information = 1, Warning = 2, Critical = 3, + Question = 4 }; + + QMessageBox( QWidget* parent=0, const char* name=0 ); + QMessageBox( const QString& caption, const QString &text, Icon icon, + int button0, int button1, int button2, + QWidget* parent=0, const char* name=0, bool modal=TRUE, + WFlags f=WStyle_DialogBorder ); + ~QMessageBox(); + + enum { NoButton = 0, Ok = 1, Cancel = 2, Yes = 3, No = 4, Abort = 5, + Retry = 6, Ignore = 7, YesAll = 8, NoAll = 9, ButtonMask = 0xff, + Default = 0x100, Escape = 0x200, FlagMask = 0x300 }; + + static int information( QWidget *parent, const QString &caption, + const QString& text, + int button0, int button1=0, int button2=0 ); + static int information( QWidget *parent, const QString &caption, + const QString& text, + const QString& button0Text = QString::null, + const QString& button1Text = QString::null, + const QString& button2Text = QString::null, + int defaultButtonNumber = 0, + int escapeButtonNumber = -1 ); + + static int question( QWidget *parent, const QString &caption, + const QString& text, + int button0, int button1=0, int button2=0 ); + static int question( QWidget *parent, const QString &caption, + const QString& text, + const QString& button0Text = QString::null, + const QString& button1Text = QString::null, + const QString& button2Text = QString::null, + int defaultButtonNumber = 0, + int escapeButtonNumber = -1 ); + + static int warning( QWidget *parent, const QString &caption, + const QString& text, + int button0, int button1, int button2=0 ); + static int warning( QWidget *parent, const QString &caption, + const QString& text, + const QString& button0Text = QString::null, + const QString& button1Text = QString::null, + const QString& button2Text = QString::null, + int defaultButtonNumber = 0, + int escapeButtonNumber = -1 ); + + static int critical( QWidget *parent, const QString &caption, + const QString& text, + int button0, int button1, int button2=0 ); + static int critical( QWidget *parent, const QString &caption, + const QString& text, + const QString& button0Text = QString::null, + const QString& button1Text = QString::null, + const QString& button2Text = QString::null, + int defaultButtonNumber = 0, + int escapeButtonNumber = -1 ); + + static void about( QWidget *parent, const QString &caption, + const QString& text ); + + static void aboutQt( QWidget *parent, + const QString& caption=QString::null ); + +/* OBSOLETE */ + static int message( const QString &caption, + const QString& text, + const QString& buttonText=QString::null, + QWidget *parent=0, const char * =0 ) { + return QMessageBox::information( parent, caption, text, + buttonText.isEmpty() + ? tr("OK") : buttonText ) == 0; + } + +/* OBSOLETE */ + static bool query( const QString &caption, + const QString& text, + const QString& yesButtonText=QString::null, + const QString& noButtonText=QString::null, + QWidget *parent=0, const char * = 0 ) { + return QMessageBox::information( parent, caption, text, + yesButtonText.isEmpty() + ? tr("OK") : yesButtonText, + noButtonText ) == 0; + } + + QString text() const; + void setText( const QString &); + + Icon icon() const; + + void setIcon( Icon ); + void setIcon( const QPixmap & ); + + const QPixmap *iconPixmap() const; + void setIconPixmap( const QPixmap & ); + + QString buttonText( int button ) const; + void setButtonText( int button, const QString &); + + void adjustSize(); + +/* OBSOLETE */ + static QPixmap standardIcon( Icon icon, GUIStyle ); + + static QPixmap standardIcon( Icon icon ); + + TextFormat textFormat() const; + void setTextFormat( TextFormat ); + +protected: + void resizeEvent( QResizeEvent * ); + void showEvent( QShowEvent * ); + void closeEvent( QCloseEvent * ); + void keyPressEvent( QKeyEvent * ); + void styleChanged( QStyle& ); + +private slots: + void buttonClicked(); + +private: + void init( int, int, int ); + int indexOf( int ) const; + void resizeButtons(); + QLabel *label; + QMessageBoxData *mbd; + void *reserved1; + void *reserved2; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QMessageBox( const QMessageBox & ); + QMessageBox &operator=( const QMessageBox & ); +#endif +}; + +/* +* Macro to be used at the beginning of main(), e.g. +* +* #include <qapplication.h> +* #include <qmessagebox.h> +* int main( int argc, char**argv ) +* { +* QT_REQUIRE_VERSION( argc, argv, "3.0.5" ) +* ... +* } +*/ +#define QT_REQUIRE_VERSION( argc, argv, str ) { QString s=QString::fromLatin1(str);\ +QString sq=QString::fromLatin1(qVersion()); if ( (sq.section('.',0,0).toInt()<<16)+\ +(sq.section('.',1,1).toInt()<<8)+sq.section('.',2,2).toInt()<(s.section('.',0,0).toInt()<<16)+\ +(s.section('.',1,1).toInt()<<8)+s.section('.',2,2).toInt() ){if ( !qApp){ int c=0; new \ +QApplication(argc,argv);} QString s = QApplication::tr("Executable '%1' requires Qt "\ + "%2, found Qt %3.").arg(QString::fromLatin1(qAppName())).arg(QString::fromLatin1(\ +str)).arg(QString::fromLatin1(qVersion()) ); QMessageBox::critical( 0, QApplication::tr(\ +"Incompatible Qt Library Error" ), s, QMessageBox::Abort,0 ); qFatal(s.ascii()); }} + + +#endif // QT_NO_MESSAGEBOX + +#endif // QMESSAGEBOX_H diff --git a/src/dialogs/qprintdialog.cpp b/src/dialogs/qprintdialog.cpp new file mode 100644 index 0000000..3f3e2a1 --- /dev/null +++ b/src/dialogs/qprintdialog.cpp @@ -0,0 +1,1672 @@ +/**************************************************************************** +** +** Implementation of internal print dialog (X11) used by QPrinter::select(). +** +** Created : 950829 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qprintdialog.h" + +#ifndef QT_NO_PRINTDIALOG + +#include "qfiledialog.h" +#include "qfile.h" +#include "qtextstream.h" +#include "qcombobox.h" +#include "qframe.h" +#include "qlabel.h" +#include "qlineedit.h" +#include "qpushbutton.h" +#include "qprinter.h" +#include "qlistview.h" +#include "qlayout.h" +#include "qbuttongroup.h" +#include "qradiobutton.h" +#include "qspinbox.h" +#include "qapplication.h" +#include "qheader.h" +#include "qstyle.h" +#include "qstring.h" +#include "qregexp.h" +#if !defined(QT_NO_CUPS) || !defined(QT_NO_NIS) +#include "qlibrary.h" +#endif + +#ifndef QT_NO_NIS + +#ifndef BOOL_DEFINED +#define BOOL_DEFINED +#endif + +#include <rpcsvc/ypclnt.h> +#include <rpcsvc/yp_prot.h> + +// Solaris redefines connect -> __xnet_connect with _XOPEN_SOURCE_EXTENDED. +#if defined(connect) +# undef connect +#endif + +#endif // QT_NO_NIS + +// UNIX Large File Support redefines open -> open64 +#if defined(open) +# undef open +#endif + +#include <ctype.h> +#include <stdlib.h> + + +class QPrintDialogSpinBox : public QSpinBox +{ +public: + QPrintDialogSpinBox(int min, int max, int steps, QWidget *parent, const char *name) + : QSpinBox(min, max, steps, parent, name) + {} + + void interpretText() + { + QSpinBox::interpretText(); + } +}; + + + + +enum { Success = 's', Unavail = 'u', NotFound = 'n', TryAgain = 't' }; +enum { Continue = 'c', Return = 'r' }; + +class QPrintDialogPrivate +{ +public: + QPrinter * printer; + + QButtonGroup * printerOrFile; + + bool outputToFile; + QListView * printers; + QLineEdit * fileName; + QPushButton * browse, *ok; + + QButtonGroup * printRange; + QLabel * firstPageLabel; + QPrintDialogSpinBox * firstPage; + QLabel * lastPageLabel; + QPrintDialogSpinBox * lastPage; + QRadioButton * printAllButton; + QRadioButton * printRangeButton; + QRadioButton * printSelectionButton; + QRadioButton * printToFileButton; + QComboBox *orientationCombo, *sizeCombo; + + QPrinter::PageSize pageSize; + QPrinter::Orientation orientation; + + QButtonGroup * pageOrder; + QPrinter::PageOrder pageOrder2; + + QButtonGroup * colorMode; + QPrinter::ColorMode colorMode2; + + QPrintDialogSpinBox * copies; + int numCopies; + + QBoxLayout *customLayout; + + QPrinter::PageSize indexToPageSize[QPrinter::NPageSize]; +}; + + +typedef void (*Q_PrintDialogHook)(QListView *); +static Q_PrintDialogHook addPrinterHook = 0; + +void qt_set_printdialog_hook( Q_PrintDialogHook hook ) +{ + addPrinterHook = hook; +} + +static void isc( QPrintDialogPrivate * d, const QString & text, + QPrinter::PageSize ps ); + +class QPrinterListViewItem : public QListViewItem +{ +public: + QPrinterListViewItem( QListView * printers, const QString& name, + const QString& host, const QString& comment, + const QStringList& aliases ) + : QListViewItem( printers, name, host, comment ), ali( aliases ) { } + + bool samePrinter( const QString& name ) { + return text( 0 ) == name || ali.find( name ) != ali.end(); + } + + QStringList ali; +}; + +static void perhapsAddPrinter( QListView * printers, const QString &name, + QString host, QString comment, + QStringList aliases = QStringList() ) +{ + const QListViewItem * i = printers->firstChild(); + while ( i && !((QPrinterListViewItem *) i)->samePrinter(name) ) + i = i->nextSibling(); + if ( i ) + return; + if ( host.isEmpty() ) + host = QPrintDialog::tr( "locally connected" ); + (void)new QPrinterListViewItem( printers, + name.simplifyWhiteSpace(), + host.simplifyWhiteSpace(), + comment.simplifyWhiteSpace(), aliases ); +} + +static void parsePrinterDesc( QString printerDesc, QListView * printers ) +{ + if ( printerDesc.length() < 1 ) + return; + + printerDesc = printerDesc.simplifyWhiteSpace(); + int i = printerDesc.find( ':' ); + QString printerName, printerComment, printerHost; + QStringList aliases; + + if ( i >= 0 ) { + // have ':' want '|' + int j = printerDesc.find( '|' ); + if ( j > 0 && j < i ) { + printerName = printerDesc.left( j ); + aliases = QStringList::split( '|', + printerDesc.mid(j + 1, i - j - 1) ); + // try extracting a comment from the aliases + printerComment = QPrintDialog::tr( "Aliases: %1" ) + .arg( aliases.join(", ") ); + } else { + printerName = printerDesc.left( i ); + } + // look for lprng pseudo all printers entry + i = printerDesc.find( QRegExp(QString::fromLatin1(": *all *=")) ); + if ( i >= 0 ) + printerName = ""; + // look for signs of this being a remote printer + i = printerDesc.find( QRegExp(QString::fromLatin1(": *rm *=")) ); + if ( i >= 0 ) { + // point k at the end of remote host name + while ( printerDesc[i] != '=' ) + i++; + while ( printerDesc[i] == '=' || printerDesc[i].isSpace() ) + i++; + j = i; + while ( j < (int)printerDesc.length() && printerDesc[j] != ':' ) + j++; + + // and stuff that into the string + printerHost = printerDesc.mid( i, j - i ); + } + } + if ( printerName.length() ) + perhapsAddPrinter( printers, printerName, printerHost, printerComment, + aliases ); +} + +static int parsePrintcap( QListView * printers, const QString& fileName ) +{ + QFile printcap( fileName ); + if ( !printcap.open( IO_ReadOnly ) ) + return NotFound; + + char * line_ascii = new char[1025]; + line_ascii[1024] = '\0'; + + QString printerDesc; + bool atEnd = FALSE; + + while ( !atEnd ) { + if ( printcap.atEnd() || printcap.readLine( line_ascii, 1024 ) <= 0 ) + atEnd = TRUE; + QString line = line_ascii; + line = line.stripWhiteSpace(); + if ( line.length() >= 1 && line[int(line.length()) - 1] == '\\' ) + line.truncate( line.length() - 1 ); + if ( line[0] == '#' ) { + if ( !atEnd ) + continue; + } else if ( line[0] == '|' || line[0] == ':' ) { + printerDesc += line; + if ( !atEnd ) + continue; + } + + parsePrinterDesc( printerDesc, printers ); + + // add the first line of the new printer definition + printerDesc = line; + } + delete[] line_ascii; + return Success; +} + + +// solaris, not 2.6 +static void parseEtcLpPrinters( QListView * printers ) +{ + QDir lp( QString::fromLatin1("/etc/lp/printers") ); + const QFileInfoList * dirs = lp.entryInfoList(); + if ( !dirs ) + return; + + QFileInfoListIterator it( *dirs ); + QFileInfo *printer; + QString tmp; + while ( (printer = it.current()) != 0 ) { + ++it; + if ( printer->isDir() ) { + tmp.sprintf( "/etc/lp/printers/%s/configuration", + printer->fileName().ascii() ); + QFile configuration( tmp ); + char * line = new char[1025]; + QString remote( QString::fromLatin1("Remote:") ); + QString contentType( QString::fromLatin1("Content types:") ); + QString printerHost; + bool canPrintPostscript = FALSE; + if ( configuration.open( IO_ReadOnly ) ) { + while ( !configuration.atEnd() && + configuration.readLine( line, 1024 ) > 0 ) { + if ( QString::fromLatin1(line).startsWith( remote ) ) { + const char * p = line; + while ( *p != ':' ) + p++; + p++; + while ( isspace((uchar) *p) ) + p++; + printerHost = QString::fromLocal8Bit(p); + printerHost = printerHost.simplifyWhiteSpace(); + } else if ( QString::fromLatin1(line).startsWith( contentType ) ) { + char * p = line; + while ( *p != ':' ) + p++; + p++; + char * e; + while ( *p ) { + while ( isspace((uchar) *p) ) + p++; + if ( *p ) { + char s; + e = p; + while ( isalnum((uchar) *e) ) + e++; + s = *e; + *e = '\0'; + if ( !qstrcmp( p, "postscript" ) || + !qstrcmp( p, "any" ) ) + canPrintPostscript = TRUE; + *e = s; + if ( s == ',' ) + e++; + p = e; + } + } + } + } + if ( canPrintPostscript ) + perhapsAddPrinter( printers, printer->fileName(), + printerHost, QString::fromLatin1("") ); + } + delete[] line; + } + } +} + + +// solaris 2.6 +static char * parsePrintersConf( QListView * printers, bool *found = 0 ) +{ + QFile pc( QString::fromLatin1("/etc/printers.conf") ); + if ( !pc.open( IO_ReadOnly ) ) { + if ( found ) + *found = FALSE; + return 0; + } + if ( found ) + *found = TRUE; + + char * line = new char[1025]; + line[1024] = '\0'; + + QString printerDesc; + int lineLength = 0; + + char * defaultPrinter = 0; + + while ( !pc.atEnd() && + (lineLength=pc.readLine( line, 1024 )) > 0 ) { + if ( *line == '#' ) { + *line = '\0'; + lineLength = 0; + } + if ( lineLength >= 2 && line[lineLength-2] == '\\' ) { + line[lineLength-2] = '\0'; + printerDesc += QString::fromLocal8Bit(line); + } else { + printerDesc += QString::fromLocal8Bit(line); + printerDesc = printerDesc.simplifyWhiteSpace(); + int i = printerDesc.find( ':' ); + QString printerName, printerHost, printerComment; + QStringList aliases; + if ( i >= 0 ) { + // have : want | + int j = printerDesc.find( '|', 0 ); + if ( j >= i ) + j = -1; + printerName = printerDesc.mid( 0, j < 0 ? i : j ); + if ( printerName == QString::fromLatin1("_default") ) { + i = printerDesc.find( + QRegExp( QString::fromLatin1(": *use *=") ) ); + while ( printerDesc[i] != '=' ) + i++; + while ( printerDesc[i] == '=' || printerDesc[i].isSpace() ) + i++; + j = i; + while ( j < (int)printerDesc.length() && + printerDesc[j] != ':' && printerDesc[j] != ',' ) + j++; + // that's our default printer + defaultPrinter = + qstrdup( printerDesc.mid( i, j-i ).ascii() ); + printerName = ""; + printerDesc = ""; + } else if ( printerName == QString::fromLatin1("_all") ) { + // skip it.. any other cases we want to skip? + printerName = ""; + printerDesc = ""; + } + + if ( j > 0 ) { + // try extracting a comment from the aliases + aliases = QStringList::split( '|', + printerDesc.mid(j + 1, i - j - 1) ); + printerComment = QPrintDialog::tr( "Aliases: %1" ) + .arg( aliases.join(", ") ); + } + // look for signs of this being a remote printer + i = printerDesc.find( + QRegExp( QString::fromLatin1(": *bsdaddr *=") ) ); + if ( i >= 0 ) { + // point k at the end of remote host name + while ( printerDesc[i] != '=' ) + i++; + while ( printerDesc[i] == '=' || printerDesc[i].isSpace() ) + i++; + j = i; + while ( j < (int)printerDesc.length() && + printerDesc[j] != ':' && printerDesc[j] != ',' ) + j++; + // and stuff that into the string + printerHost = printerDesc.mid( i, j-i ); + // maybe stick the remote printer name into the comment + if ( printerDesc[j] == ',' ) { + i = ++j; + while ( printerDesc[i].isSpace() ) + i++; + j = i; + while ( j < (int)printerDesc.length() && + printerDesc[j] != ':' && printerDesc[j] != ',' ) + j++; + if ( printerName != printerDesc.mid( i, j-i ) ) { + printerComment = + QString::fromLatin1("Remote name: "); + printerComment += printerDesc.mid( i, j-i ); + } + } + } + } + if ( printerComment == ":" ) + printerComment = ""; // for cups + if ( printerName.length() ) + perhapsAddPrinter( printers, printerName, printerHost, + printerComment, aliases ); + // chop away the line, for processing the next one + printerDesc = ""; + } + } + delete[] line; + return defaultPrinter; +} + +#ifndef QT_NO_NIS + +#if defined(Q_C_CALLBACKS) +extern "C" { +#endif + +static int foreach( int /* status */, char * /* key */, int /* keyLen */, + char * val, int valLen, char * data ) +{ + parsePrinterDesc( QString::fromLatin1(val, valLen), (QListView *) data ); + return 0; +} + +#if defined(Q_C_CALLBACKS) +} +#endif + +static int retrieveNisPrinters( QListView * printers ) +{ + typedef int (*WildCast)( int, char *, int, char *, int, char * ); + char printersConfByname[] = "printers.conf.byname"; + char *domain; + int err; + + QLibrary lib( "nsl" ); + typedef int (*ypGetDefaultDomain)(char **); + ypGetDefaultDomain _ypGetDefaultDomain = (ypGetDefaultDomain)lib.resolve( "yp_get_default_domain" ); + typedef int (*ypAll)(const char *, const char *, const struct ypall_callback *); + ypAll _ypAll = (ypAll)lib.resolve( "yp_all" ); + + if ( _ypGetDefaultDomain && _ypAll ) { + err = _ypGetDefaultDomain( &domain ); + if ( err == 0 ) { + ypall_callback cb; + // wild cast to support K&R-style system headers + (WildCast &) cb.foreach = (WildCast) foreach; + cb.data = (char *) printers; + err = _ypAll( domain, printersConfByname, &cb ); + } + if ( !err ) + return Success; + } + return Unavail; +} + +#endif // QT_NO_NIS + +static char *parseNsswitchPrintersEntry( QListView * printers, char *line ) +{ +#define skipSpaces() \ + while ( isspace((uchar) line[k]) ) \ + k++ + + char *defaultPrinter = 0; + bool stop = FALSE; + int lastStatus = NotFound; + + int k = 8; + skipSpaces(); + if ( line[k] != ':' ) + return 0; + k++; + + char *cp = strchr( line, '#' ); + if ( cp != 0 ) + *cp = '\0'; + + while ( line[k] != '\0' ) { + if ( isspace((uchar) line[k]) ) { + k++; + } else if ( line[k] == '[' ) { + k++; + skipSpaces(); + while ( line[k] != '\0' ) { + char status = tolower( line[k] ); + char action = '?'; + + while ( line[k] != '=' && line[k] != ']' && + line[k] != '\0' ) + k++; + if ( line[k] == '=' ) { + k++; + skipSpaces(); + action = tolower( line[k] ); + while ( line[k] != '\0' && !isspace((uchar) line[k]) && line[k] != ']' ) + k++; + } else if ( line[k] == ']' ) { + k++; + break; + } + skipSpaces(); + + if ( lastStatus == status ) + stop = ( action == (char) Return ); + } + } else { + if ( stop ) + break; + + QCString source; + while ( line[k] != '\0' && !isspace((uchar) line[k]) && line[k] != '[' ) { + source += line[k]; + k++; + } + + if ( source == "user" ) { + lastStatus = parsePrintcap( printers, + QDir::homeDirPath() + "/.printers" ); + } else if ( source == "files" ) { + bool found; + defaultPrinter = parsePrintersConf( printers, &found ); + if ( found ) + lastStatus = Success; +#ifndef QT_NO_NIS + } else if ( source == "nis" ) { + lastStatus = retrieveNisPrinters( printers ); +#endif + } else { + // nisplus, dns, etc., are not implemented yet + lastStatus = NotFound; + } + stop = ( lastStatus == Success ); + } + } + return defaultPrinter; +} + +static char *parseNsswitchConf( QListView * printers ) +{ + QFile nc( QString::fromLatin1("/etc/nsswitch.conf") ); + if ( !nc.open(IO_ReadOnly) ) + return 0; + + char *defaultPrinter = 0; + + char *line = new char[1025]; + line[1024] = '\0'; + + while ( !nc.atEnd() && + nc.readLine(line, 1024) > 0 ) { + if ( strncmp(line, "printers", 8) == 0 ) { + defaultPrinter = parseNsswitchPrintersEntry( printers, line ); + delete[] line; + return defaultPrinter; + } + } + + strcpy( line, "printers: user files nis nisplus xfn" ); + defaultPrinter = parseNsswitchPrintersEntry( printers, line ); + delete[] line; + return defaultPrinter; +} + +// HP-UX +static void parseEtcLpMember( QListView * printers ) +{ + QDir lp( QString::fromLatin1("/etc/lp/member") ); + if ( !lp.exists() ) + return; + const QFileInfoList * dirs = lp.entryInfoList(); + if ( !dirs ) + return; + + QFileInfoListIterator it( *dirs ); + QFileInfo *printer; + QString tmp; + while ( (printer = it.current()) != 0 ) { + ++it; + // I haven't found any real documentation, so I'm guessing that + // since lpstat uses /etc/lp/member rather than one of the + // other directories, it's the one to use. I did not find a + // decent way to locate aliases and remote printers. + if ( printer->isFile() ) + perhapsAddPrinter( printers, printer->fileName(), + QPrintDialog::tr("unknown"), + QString::fromLatin1("") ); + } +} + +// IRIX 6.x +static void parseSpoolInterface( QListView * printers ) +{ + QDir lp( QString::fromLatin1("/usr/spool/lp/interface") ); + if ( !lp.exists() ) + return; + const QFileInfoList * files = lp.entryInfoList(); + if( !files ) + return; + + QFileInfoListIterator it( *files ); + QFileInfo *printer; + while ( (printer = it.current()) != 0) { + ++it; + + if ( !printer->isFile() ) + continue; + + // parse out some information + QFile configFile( printer->filePath() ); + if ( !configFile.open( IO_ReadOnly ) ) + continue; + + QCString line( 1025 ); + QString namePrinter; + QString hostName; + QString hostPrinter; + QString printerType; + + QString nameKey( QString::fromLatin1("NAME=") ); + QString typeKey( QString::fromLatin1("TYPE=") ); + QString hostKey( QString::fromLatin1("HOSTNAME=") ); + QString hostPrinterKey( QString::fromLatin1("HOSTPRINTER=") ); + + while ( !configFile.atEnd() && + (configFile.readLine(line.data(), 1024)) > 0 ) { + QString uline = line; + if ( uline.startsWith( typeKey ) ) { + printerType = line.mid( nameKey.length() ); + printerType = printerType.simplifyWhiteSpace(); + } else if ( uline.startsWith( hostKey ) ) { + hostName = line.mid( hostKey.length() ); + hostName = hostName.simplifyWhiteSpace(); + } else if ( uline.startsWith( hostPrinterKey ) ) { + hostPrinter = line.mid( hostPrinterKey.length() ); + hostPrinter = hostPrinter.simplifyWhiteSpace(); + } else if ( uline.startsWith( nameKey ) ) { + namePrinter = line.mid( nameKey.length() ); + namePrinter = namePrinter.simplifyWhiteSpace(); + } + } + configFile.close(); + + printerType = printerType.stripWhiteSpace(); + if ( printerType.find("postscript", 0, FALSE) < 0 ) + continue; + + int ii = 0; + while ( (ii = namePrinter.find('"', ii)) >= 0 ) + namePrinter.remove( ii, 1 ); + + if ( hostName.isEmpty() || hostPrinter.isEmpty() ) { + perhapsAddPrinter( printers, printer->fileName(), + QString::fromLatin1(""), namePrinter ); + } else { + QString comment; + comment = namePrinter; + comment += " ("; + comment += hostPrinter; + comment += ")"; + perhapsAddPrinter( printers, printer->fileName(), + hostName, comment ); + } + } +} + + +// Every unix must have its own. It's a standard. Here is AIX. +static void parseQconfig( QListView * printers ) +{ + QFile qconfig( QString::fromLatin1("/etc/qconfig") ); + if ( !qconfig.open( IO_ReadOnly ) ) + return; + + QTextStream ts( &qconfig ); + QString line; + + QString stanzaName; // either a queue or a device name + bool up = TRUE; // queue up? default TRUE, can be FALSE + QString remoteHost; // null if local + QString deviceName; // null if remote + + QRegExp newStanza( QString::fromLatin1("^[0-z\\-]+:$") ); + + // our basic strategy here is to process each line, detecting new + // stanzas. each time we see a new stanza, we check if the + // previous stanza was a valid queue for a) a remote printer or b) + // a local printer. if it wasn't, we assume that what we see is + // the start of the first stanza, or that the previous stanza was + // a device stanza, or that there is some syntax error (we don't + // report those). + + do { + line = ts.readLine(); + bool indented = line[0].isSpace(); + line = line.simplifyWhiteSpace(); + + int i = line.find('='); + if ( indented && i != -1 ) { // line in stanza + QString variable = line.left( i ).simplifyWhiteSpace(); + QString value=line.mid( i+1, line.length() ).simplifyWhiteSpace(); + if ( variable == QString::fromLatin1("device") ) + deviceName = value; + else if ( variable == QString::fromLatin1("host") ) + remoteHost = value; + else if ( variable == QString::fromLatin1("up") ) + up = !(value.lower() == QString::fromLatin1("false")); + } else if ( line[0] == '*' ) { // comment + // nothing to do + } else if ( ts.atEnd() || // end of file, or beginning of new stanza + ( !indented && line.find( newStanza ) != -1 ) ) { + if ( up && stanzaName.length() > 0 && stanzaName.length() < 21 ) { + if ( remoteHost.length() ) // remote printer + perhapsAddPrinter( printers, stanzaName, remoteHost, + QString::null ); + else if ( deviceName.length() ) // local printer + perhapsAddPrinter( printers, stanzaName, QString::null, + QString::null ); + } + line.truncate( line.length()-1 ); + if ( line.length() >= 1 && line.length() <= 20 ) + stanzaName = line; + up = TRUE; + remoteHost = QString::null; + deviceName = QString::null; + } else { + // syntax error? ignore. + } + } while ( !ts.atEnd() ); +} + + +#ifndef QT_NO_CUPS +#include <cups/cups.h> + +static char * parseCupsOutput( QListView * printers ) +{ + char * defaultPrinter = 0; + int nd; + cups_dest_t * d; + QLibrary lib( "cups" ); + typedef int (*CupsGetDests)(cups_dest_t **dests); + CupsGetDests _cupsGetDests = (CupsGetDests)lib.resolve( "cupsGetDests" ); + if ( _cupsGetDests ) { + nd = _cupsGetDests( &d ); + if ( nd < 1 ) + return 0; + + int n = 0; + while ( n < nd ) { + perhapsAddPrinter( printers, d[n].name, + QPrintDialog::tr("Unknown Location"), 0 ); + if ( d[n].is_default && !defaultPrinter ) + defaultPrinter = qstrdup( d[n].instance ); + n++; + } + } + return defaultPrinter; +} +#endif + +static QPrintDialog * globalPrintDialog = 0; + +static void qpd_cleanup_globaldialog() +{ + if ( globalPrintDialog != 0 ) + delete globalPrintDialog; + globalPrintDialog = 0; +} + +/*! + \class QPrintDialog qprintdialog.h + + \brief The QPrintDialog class provides a dialog for specifying + the printer's configuration. + + \internal + + \warning The use of this class is not recommended since it is not + present on all platforms; use QPrinter::setup() instead. + + \omit + + (ingroup dialogs) + + THIS DOCUMENTATION IS Not Revised. It must be revised before + becoming public API. + + It encompasses both the sort of details needed for doing a simple + print-out and some print configuration setup. + + The easiest way to use the class is through the static + function getPrinterSetup(). You can also subclass the QPrintDialog + and add some custom buttons with addButton() to extend the + functionality of the print dialog. + + <img src="qprintdlg-m.png"><br clear=all> + The printer dialog, on a large screen, in Motif style. +*/ + + +/*! Constructs a new modal printer dialog that configures \a prn and is a + child of \a parent named \a name. +*/ + +QPrintDialog::QPrintDialog( QPrinter *prn, QWidget *parent, const char *name ) + : QDialog( parent, name, TRUE ) +{ + d = new QPrintDialogPrivate; + d->numCopies = 1; + + QBoxLayout * tll = new QBoxLayout( this, QBoxLayout::Down, 12, 0 ); + + // destination + QGroupBox * g; + g = setupDestination(); + tll->addWidget( g, 1 ); + + tll->addSpacing( 12 ); + + // printer and paper settings + QBoxLayout * lay = new QBoxLayout( QBoxLayout::LeftToRight ); + tll->addLayout( lay ); + + g = setupPrinterSettings(); + lay->addWidget( g, 1 ); + + lay->addSpacing( 12 ); + + g = setupPaper(); + lay->addWidget( g ); + + tll->addSpacing( 12 ); + + // options + g = setupOptions(); + tll->addWidget( g ); + tll->addSpacing( 12 ); + + QBoxLayout *l = new QBoxLayout( QBoxLayout::LeftToRight ); + d->customLayout = new QBoxLayout( QBoxLayout::LeftToRight ); + tll->addLayout( l ); + l->addLayout( d->customLayout ); + l->addStretch(); + tll->addSpacing( 12 ); + + // buttons + QBoxLayout *horiz = new QBoxLayout( QBoxLayout::LeftToRight ); + tll->addLayout( horiz ); + + bool rightalign = + bool(style().styleHint(QStyle::SH_PrintDialog_RightAlignButtons, this)); + + if (rightalign) + horiz->addStretch( 1 ); + + d->ok = new QPushButton( this, "ok" ); + d->ok->setText( tr("OK") ); + d->ok->setDefault( TRUE ); + horiz->addWidget( d->ok ); + if (! rightalign) + horiz->addStretch( 1 ); + horiz->addSpacing( 6 ); + + QPushButton * cancel = new QPushButton( this, "cancel" ); + cancel->setText( tr("Cancel") ); + horiz->addWidget( cancel ); + + QSize s1 = d->ok->sizeHint(); + QSize s2 = cancel->sizeHint(); + s1 = QSize( QMAX(s1.width(), s2.width()), + QMAX(s1.height(), s2.height()) ); + + d->ok->setFixedSize( s1 ); + cancel->setFixedSize( s1 ); + + tll->activate(); + + connect( d->ok, SIGNAL(clicked()), SLOT(okClicked()) ); + connect( cancel, SIGNAL(clicked()), SLOT(reject()) ); + + QSize ms( minimumSize() ); + QSize ss( QApplication::desktop()->screenGeometry( pos() ).size() ); + if ( ms.height() < 512 && ss.height() >= 600 ) + ms.setHeight( 512 ); + else if ( ms.height() < 460 && ss.height() >= 480 ) + ms.setHeight( 460 ); + resize( ms ); + + setPrinter( prn, TRUE ); + d->printers->setFocus(); +} + + +/*! Destroys the object and frees any allocated resources. Does not + delete the associated QPrinter object. +*/ + +QPrintDialog::~QPrintDialog() +{ + if ( this == globalPrintDialog ) + globalPrintDialog = 0; + delete d; +} + +/*! + This method allows you to specify a global print dialog, given in \a + pd, that will be used instead of the default dialog provided by Qt. + + This is useful, since there are many different printing systems on + Unix, and we cannot support all of them. Calling this method before + using a printer for the first time allows you to set up your own + print dialog. + + \sa setupPrinters() +*/ +void QPrintDialog::setGlobalPrintDialog( QPrintDialog *pd ) +{ + QPrintDialog *oldPd = globalPrintDialog; + globalPrintDialog = pd; + if ( oldPd ) + delete oldPd; + else + qAddPostRoutine( qpd_cleanup_globaldialog ); + globalPrintDialog->adjustSize(); +} + +QGroupBox * QPrintDialog::setupPrinterSettings() +{ + QGroupBox * g = new QGroupBox( 1, Horizontal, tr( "Printer settings"), + this, "settings group box" ); + + d->colorMode = new QButtonGroup( this ); + d->colorMode->hide(); + connect( d->colorMode, SIGNAL(clicked(int)), + this, SLOT(colorModeSelected(int)) ); + + QRadioButton *rb; + rb = new QRadioButton( tr( "Print in color if available" ), + g, "color" ); + d->colorMode->insert( rb, QPrinter::Color ); + rb->setChecked( TRUE ); + + rb = new QRadioButton( tr("Print in grayscale"), + g, "graysacle" ); + d->colorMode->insert( rb, QPrinter::GrayScale ); + + return g; +} + +QGroupBox * QPrintDialog::setupDestination() +{ + QGroupBox * g = new QGroupBox( 0, Horizontal, tr( "Print destination"), + this, "destination group box" ); + + QBoxLayout * tll = new QBoxLayout( g->layout(), QBoxLayout::Down ); + + d->printerOrFile = new QButtonGroup( this ); + d->printerOrFile->hide(); + connect( d->printerOrFile, SIGNAL(clicked(int)), + this, SLOT(printerOrFileSelected(int)) ); + + // printer radio button, list + QRadioButton * rb = new QRadioButton( tr( "Print to printer:" ), g, + "printer" ); + tll->addWidget( rb ); + d->printerOrFile->insert( rb, 0 ); + rb->setChecked( TRUE ); + d->outputToFile = FALSE; + + QBoxLayout * horiz = new QBoxLayout( QBoxLayout::LeftToRight ); + tll->addLayout( horiz, 3 ); + horiz->addSpacing( 19 ); + + d->printers = new QListView( g, "list of printers" ); + d->printers->setAllColumnsShowFocus( TRUE ); + d->printers->addColumn( tr("Printer"), 125 ); + d->printers->addColumn( tr("Host"), 125 ); + d->printers->addColumn( tr("Comment"), 150 ); + +#if defined(Q_OS_UNIX) + char * etcLpDefault = 0; + +#ifndef QT_NO_CUPS + etcLpDefault = parseCupsOutput( d->printers ); +#endif + if ( d->printers->childCount() == 0 ) { + // we only use other schemes when cups fails. + + parsePrintcap( d->printers, QString::fromLatin1("/etc/printcap") ); + parseEtcLpMember( d->printers ); + parseSpoolInterface( d->printers ); + parseQconfig( d->printers ); + if ( addPrinterHook ) + (*addPrinterHook)( d->printers ); + + QFileInfo f; + f.setFile( QString::fromLatin1("/etc/lp/printers") ); + if ( f.isDir() ) { + parseEtcLpPrinters( d->printers ); + QFile def( QString::fromLatin1("/etc/lp/default") ); + if ( def.open( IO_ReadOnly ) ) { + if ( etcLpDefault ) + delete[] etcLpDefault; + etcLpDefault = new char[1025]; + def.readLine( etcLpDefault, 1024 ); + char * p = etcLpDefault; + while ( p && *p ) { + if ( !isprint((uchar) *p) || isspace((uchar) *p) ) + *p = 0; + else + p++; + } + } + } + + char * def = 0; + f.setFile( QString::fromLatin1("/etc/nsswitch.conf") ); + if ( f.isFile() ) { + def = parseNsswitchConf( d->printers ); + } else { + f.setFile( QString::fromLatin1("/etc/printers.conf") ); + if ( f.isFile() ) + def = parsePrintersConf( d->printers ); + } + + if ( def ) { + if ( etcLpDefault ) + delete[] etcLpDefault; + etcLpDefault = def; + } + } + + // all printers hopefully known. try to find a good default + QString dollarPrinter; + { + const char * t = getenv( "PRINTER" ); + if ( !t || !*t ) + t = getenv( "LPDEST" ); + dollarPrinter = QString::fromLatin1( t ); + if ( !dollarPrinter.isEmpty() ) + perhapsAddPrinter( d->printers, dollarPrinter, + QPrintDialog::tr("unknown"), + QString::fromLatin1("") ); + } + int quality = 0; + + // bang the best default into the listview + const QListViewItem * lvi = d->printers->firstChild(); + d->printers->setCurrentItem( (QListViewItem *)lvi ); + while ( lvi ) { + QRegExp ps( QString::fromLatin1("[^a-z]ps(?:[^a-z]|$)") ); + QRegExp lp( QString::fromLatin1("[^a-z]lp(?:[^a-z]|$)") ); + + if ( quality < 4 && lvi->text(0) == dollarPrinter ) { + d->printers->setCurrentItem( (QListViewItem *)lvi ); + quality = 4; + } else if ( quality < 3 && etcLpDefault && + lvi->text(0) == QString::fromLatin1(etcLpDefault) ) { + d->printers->setCurrentItem( (QListViewItem *)lvi ); + quality = 3; + } else if ( quality < 2 && + ( lvi->text(0) == QString::fromLatin1("ps") || + ps.search(lvi->text(2)) != -1 ) ) { + d->printers->setCurrentItem( (QListViewItem *)lvi ); + quality = 2; + } else if ( quality < 1 && + ( lvi->text(0) == QString::fromLatin1("lp") || + lp.search(lvi->text(2)) > -1 ) ) { + d->printers->setCurrentItem( (QListViewItem *)lvi ); + quality = 1; + } + lvi = lvi->nextSibling(); + } + + if ( d->printers->currentItem() ) + d->printers->setSelected( d->printers->currentItem(), TRUE ); + + if ( etcLpDefault ) // Avoid purify complaint + delete[] etcLpDefault; +#endif + + int h = fontMetrics().height(); + if ( d->printers->firstChild() ) + h = d->printers->firstChild()->height(); + d->printers->setMinimumSize( d->printers->sizeHint().width(), + d->printers->header()->height() + + 3 * h ); + horiz->addWidget( d->printers, 3 ); + + tll->addSpacing( 6 ); + + // file radio button, edit/browse + d->printToFileButton = new QRadioButton( tr( "Print to file:" ), g, "file" ); + tll->addWidget( d->printToFileButton ); + d->printerOrFile->insert( d->printToFileButton, 1 ); + + horiz = new QBoxLayout( QBoxLayout::LeftToRight ); + tll->addLayout( horiz ); + horiz->addSpacing( 19 ); + + d->fileName = new QLineEdit( g, "file name" ); + connect( d->fileName, SIGNAL( textChanged(const QString&) ), + this, SLOT( fileNameEditChanged(const QString&) ) ); + horiz->addWidget( d->fileName, 1 ); + horiz->addSpacing( 6 ); + d->browse = new QPushButton( tr("Browse..."), g, "browse files" ); + d->browse->setAutoDefault( FALSE ); +#ifdef QT_NO_FILEDIALOG + d->browse->setEnabled( FALSE ); +#endif + connect( d->browse, SIGNAL(clicked()), + this, SLOT(browseClicked()) ); + horiz->addWidget( d->browse ); + + d->fileName->setEnabled( FALSE ); + d->browse->setEnabled( FALSE ); + + tll->activate(); + + return g; +} + + +QGroupBox * QPrintDialog::setupOptions() +{ + QGroupBox * g = new QGroupBox( 0, Horizontal, tr( "Options"), + this, "options group box" ); + + QBoxLayout * tll = new QBoxLayout( g->layout(), QBoxLayout::Down ); + + QBoxLayout *lay = new QBoxLayout( QBoxLayout::LeftToRight ); + tll->addLayout( lay ); + + tll = new QBoxLayout( lay, QBoxLayout::Down ); + + d->printRange = new QButtonGroup( this ); + d->printRange->hide(); + connect( d->printRange, SIGNAL(clicked(int)), + this, SLOT(printRangeSelected(int)) ); + + d->pageOrder = new QButtonGroup( this ); + d->pageOrder->hide(); + connect( d->pageOrder, SIGNAL(clicked(int)), + this, SLOT(pageOrderSelected(int)) ); + + d->printAllButton = new QRadioButton( tr("Print all"), g, "print all" ); + d->printRange->insert( d->printAllButton, 0 ); + tll->addWidget( d->printAllButton ); + + d->printSelectionButton = new QRadioButton( tr("Print selection"), + g, "print selection" ); + d->printRange->insert( d->printSelectionButton, 1 ); + tll->addWidget( d->printSelectionButton ); + + d->printRangeButton = new QRadioButton( tr("Print range"), + g, "print range" ); + d->printRange->insert( d->printRangeButton, 2 ); + tll->addWidget( d->printRangeButton ); + + QBoxLayout * horiz = new QBoxLayout( QBoxLayout::LeftToRight ); + tll->addLayout( horiz ); + + d->firstPageLabel = new QLabel( tr("From page:"), g, "first page" ); + horiz->addSpacing( 19 ); + horiz->addWidget( d->firstPageLabel ); + + d->firstPage = new QPrintDialogSpinBox( 1, 9999, 1, g, "first page" ); + d->firstPage->setValue( 1 ); + horiz->addWidget( d->firstPage, 1 ); + connect( d->firstPage, SIGNAL(valueChanged(int)), + this, SLOT(setFirstPage(int)) ); + + horiz = new QBoxLayout( QBoxLayout::LeftToRight ); + tll->addLayout( horiz ); + + d->lastPageLabel = new QLabel( tr("To page:"), g, "last page" ); + horiz->addSpacing( 19 ); + horiz->addWidget( d->lastPageLabel ); + + d->lastPage = new QPrintDialogSpinBox( 1, 9999, 1, g, "last page" ); + d->lastPage->setValue( 9999 ); + horiz->addWidget( d->lastPage, 1 ); + connect( d->lastPage, SIGNAL(valueChanged(int)), + this, SLOT(setLastPage(int)) ); + + lay->addSpacing( 25 ); + tll = new QBoxLayout( lay, QBoxLayout::Down ); + + // print order + QRadioButton * rb = new QRadioButton( tr("Print first page first"), + g, "first page first" ); + tll->addWidget( rb ); + d->pageOrder->insert( rb, QPrinter::FirstPageFirst ); + rb->setChecked( TRUE ); + + rb = new QRadioButton( tr("Print last page first"), + g, "last page first" ); + tll->addWidget( rb ); + d->pageOrder->insert( rb, QPrinter::LastPageFirst ); + + tll->addStretch(); + + // copies + + horiz = new QBoxLayout( QBoxLayout::LeftToRight ); + tll->addLayout( horiz ); + + QLabel * l = new QLabel( tr("Number of copies:"), g, "Number of copies" ); + horiz->addWidget( l ); + + d->copies = new QPrintDialogSpinBox( 1, 99, 1, g, "copies" ); + d->copies->setValue( 1 ); + horiz->addWidget( d->copies, 1 ); + connect( d->copies, SIGNAL(valueChanged(int)), + this, SLOT(setNumCopies(int)) ); + + QSize s = d->firstPageLabel->sizeHint() + .expandedTo( d->lastPageLabel->sizeHint() ) + .expandedTo( l->sizeHint() ); + d->firstPageLabel->setMinimumSize( s ); + d->lastPageLabel->setMinimumSize( s ); + l->setMinimumSize( s.width() + 19, s.height() ); + + tll->activate(); + + return g; +} + + +void isc( QPrintDialogPrivate * d, + const QString & text, + QPrinter::PageSize ps ) +{ + if ( d && text && ps < QPrinter::NPageSize ) { + d->sizeCombo->insertItem( text, -1 ); + int index = d->sizeCombo->count()-1; + if ( index >= 0 && index < QPrinter::NPageSize ) + d->indexToPageSize[index] = ps; + } +} + +QGroupBox * QPrintDialog::setupPaper() +{ + QGroupBox * g = new QGroupBox( 1, Horizontal, tr( "Paper format"), + this, "Paper format" ); + d->pageSize = QPrinter::A4; + + // page orientation + d->orientationCombo = new QComboBox( FALSE, g ); + d->orientationCombo->insertItem( tr( "Portrait" ), -1 ); + d->orientationCombo->insertItem( tr( "Landscape" ), -1 ); + + d->orientation = QPrinter::Portrait; + + g->addSpace( 8 ); + + connect( d->orientationCombo, SIGNAL( activated(int) ), + this, SLOT( orientSelected(int) ) ); + + // paper size + d->sizeCombo = new QComboBox( FALSE, g ); + + int n; + for( n=0; n<QPrinter::NPageSize; n++ ) + d->indexToPageSize[n] = QPrinter::A4; + + isc( d, tr( "A0 (841 x 1189 mm)" ), QPrinter::A0 ); + isc( d, tr( "A1 (594 x 841 mm)" ), QPrinter::A1 ); + isc( d, tr( "A2 (420 x 594 mm)" ), QPrinter::A2 ); + isc( d, tr( "A3 (297 x 420 mm)" ), QPrinter::A3 ); + isc( d, tr( "A4 (210x297 mm, 8.26x11.7 inches)" ), QPrinter::A4 ); + isc( d, tr( "A5 (148 x 210 mm)" ), QPrinter::A5 ); + isc( d, tr( "A6 (105 x 148 mm)" ), QPrinter::A6 ); + isc( d, tr( "A7 (74 x 105 mm)" ), QPrinter::A7 ); + isc( d, tr( "A8 (52 x 74 mm)" ), QPrinter::A8 ); + isc( d, tr( "A9 (37 x 52 mm)" ), QPrinter::A9 ); + isc( d, tr( "B0 (1000 x 1414 mm)" ), QPrinter::B0 ); + isc( d, tr( "B1 (707 x 1000 mm)" ), QPrinter::B1 ); + isc( d, tr( "B2 (500 x 707 mm)" ), QPrinter::B2 ); + isc( d, tr( "B3 (353 x 500 mm)" ), QPrinter::B3 ); + isc( d, tr( "B4 (250 x 353 mm)" ), QPrinter::B4 ); + isc( d, tr( "B5 (176 x 250 mm, 6.93x9.84 inches)" ), QPrinter::B5 ); + isc( d, tr( "B6 (125 x 176 mm)" ), QPrinter::B6 ); + isc( d, tr( "B7 (88 x 125 mm)" ), QPrinter::B7 ); + isc( d, tr( "B8 (62 x 88 mm)" ), QPrinter::B8 ); + isc( d, tr( "B9 (44 x 62 mm)" ), QPrinter::B9 ); + isc( d, tr( "B10 (31 x 44 mm)" ), QPrinter::B10 ); + isc( d, tr( "C5E (163 x 229 mm)" ), QPrinter::C5E ); + isc( d, tr( "DLE (110 x 220 mm)" ), QPrinter::DLE ); + isc( d, tr( "Executive (7.5x10 inches, 191x254 mm)" ), QPrinter::Executive ); + isc( d, tr( "Folio (210 x 330 mm)" ), QPrinter::Folio ); + isc( d, tr( "Ledger (432 x 279 mm)" ), QPrinter::Ledger ); + isc( d, tr( "Legal (8.5x14 inches, 216x356 mm)" ), QPrinter::Legal ); + isc( d, tr( "Letter (8.5x11 inches, 216x279 mm)" ), QPrinter::Letter ); + isc( d, tr( "Tabloid (279 x 432 mm)" ), QPrinter::Tabloid ); + isc( d, tr( "US Common #10 Envelope (105 x 241 mm)" ), QPrinter::Comm10E ); + + connect( d->sizeCombo, SIGNAL( activated(int) ), + this, SLOT( paperSizeSelected(int) ) ); + + return g; +} + + +/*! + Display a dialog and allow the user to configure the QPrinter \a + p for an optional widget \a w. Returns TRUE if the user clicks OK or + presses Enter, FALSE if the user clicks Cancel or presses Esc. + + getPrinterSetup() remembers the settings and provides the same + settings the next time the dialog is shown. +*/ + +bool QPrintDialog::getPrinterSetup( QPrinter * p, QWidget* w ) +{ + if ( !globalPrintDialog ) { + globalPrintDialog = new QPrintDialog( 0, 0, "global print dialog" ); +#ifndef QT_NO_WIDGET_TOPEXTRA + globalPrintDialog->setCaption( QPrintDialog::tr( "Setup Printer" ) ); +#endif + qAddPostRoutine( qpd_cleanup_globaldialog ); + globalPrintDialog->setPrinter( p, TRUE ); + globalPrintDialog->adjustSize(); + } else { + globalPrintDialog->setPrinter( p, TRUE ); + } + globalPrintDialog->adjustPosition( w ); + #ifndef QT_NO_WIDGET_TOPEXTRA + if ( w ) { + const QPixmap *pm = w->icon(); + if ( pm && !pm->isNull() ) + globalPrintDialog->setIcon( *pm ); + else { + w = w ? w->topLevelWidget() : 0; + pm = w ? w->icon() : 0; + if ( pm && !pm->isNull() ) + globalPrintDialog->setIcon( *pm ); + } + } +#endif + bool r = globalPrintDialog->exec() == QDialog::Accepted; + globalPrintDialog->setPrinter( 0 ); + return r; +} + + +void QPrintDialog::printerOrFileSelected( int id ) +{ + d->outputToFile = id ? TRUE : FALSE; + if ( d->outputToFile ) { + d->ok->setEnabled( TRUE ); + fileNameEditChanged( d->fileName->text() ); + if ( !d->fileName->edited() && d->fileName->text().isEmpty() ) { + QString home = QString::fromLatin1( ::getenv( "HOME" ) ); + QString cur = QDir::currentDirPath(); + if ( home.at(home.length()-1) != '/' ) + home += '/'; + if ( cur.at(cur.length()-1) != '/' ) + cur += '/'; + if ( cur.left( home.length() ) != home ) + cur = home; +#ifdef Q_WS_X11 + cur += "print.ps"; +#endif + d->fileName->setText( cur ); + d->fileName->setCursorPosition( cur.length() ); + d->fileName->selectAll(); + } + d->browse->setEnabled( TRUE ); + d->fileName->setEnabled( TRUE ); + d->fileName->setFocus(); + d->printers->setEnabled( FALSE ); + } else { + d->ok->setEnabled( d->printers->childCount() != 0 ); + d->printers->setEnabled( TRUE ); + if ( d->fileName->hasFocus() || d->browse->hasFocus() ) + d->printers->setFocus(); + d->browse->setEnabled( FALSE ); + d->fileName->setEnabled( FALSE ); + } +} + + +void QPrintDialog::landscapeSelected( int id ) +{ + d->orientation = (QPrinter::Orientation)id; +} + + +void QPrintDialog::paperSizeSelected( int id ) +{ + if ( id < QPrinter::NPageSize ) + d->pageSize = QPrinter::PageSize( d->indexToPageSize[id] ); +} + + +void QPrintDialog::orientSelected( int id ) +{ + d->orientation = (QPrinter::Orientation)id; +} + + +void QPrintDialog::pageOrderSelected( int id ) +{ + d->pageOrder2 = (QPrinter::PageOrder)id; +} + + +void QPrintDialog::setNumCopies( int copies ) +{ + d->numCopies = copies; +} + + +void QPrintDialog::browseClicked() +{ +#ifndef QT_NO_FILEDIALOG + QString fn = QFileDialog::getSaveFileName( d->fileName->text(), tr( "PostScript Files (*.ps);;All Files (*)" ), this ); + if ( !fn.isNull() ) + d->fileName->setText( fn ); +#endif +} + + +void QPrintDialog::okClicked() +{ + d->lastPage->interpretText(); + d->firstPage->interpretText(); + d->copies->interpretText(); + if ( d->outputToFile ) { + d->printer->setOutputToFile( TRUE ); + d->printer->setOutputFileName( d->fileName->text() ); + } else { + d->printer->setOutputToFile( FALSE ); + QListViewItem * l = d->printers->currentItem(); + if ( l ) + d->printer->setPrinterName( l->text( 0 ) ); + } + + d->printer->setOrientation( d->orientation ); + d->printer->setPageSize( d->pageSize ); + d->printer->setPageOrder( d->pageOrder2 ); + d->printer->setColorMode( d->colorMode2 ); + d->printer->setNumCopies( d->numCopies ); + if ( d->printAllButton->isChecked() ) { + d->printer->setPrintRange(QPrinter::AllPages); + d->printer->setFromTo( d->printer->minPage(), d->printer->maxPage() ); + } else { + if (d->printSelectionButton->isChecked()) + d->printer->setPrintRange(QPrinter::Selection); + else + d->printer->setPrintRange(QPrinter::PageRange); + d->printer->setFromTo( d->firstPage->value(), d->lastPage->value() ); + } + + accept(); +} + + +void QPrintDialog::printRangeSelected( int id ) +{ + bool enable = id == 2 ? TRUE : FALSE; + d->firstPage->setEnabled( enable ); + d->lastPage->setEnabled( enable ); + d->firstPageLabel->setEnabled( enable ); + d->lastPageLabel->setEnabled( enable ); +} + + +void QPrintDialog::setFirstPage( int fp ) +{ + if ( d->printer ) + d->lastPage->setRange( fp, QMAX(fp, QPrintDialog::d->printer->maxPage()) ); +} + + +void QPrintDialog::setLastPage( int lp ) +{ + if ( d->printer ) + d->firstPage->setRange( QMIN(lp, QPrintDialog::d->printer->minPage()), lp ); +} + + +/*! + Sets this dialog to configure printer \a p, or no printer if \a p + is null. If \a pickUpSettings is TRUE, the dialog reads most of + its settings from \a p. If \a pickUpSettings is FALSE (the + default) the dialog keeps its old settings. +*/ + +void QPrintDialog::setPrinter( QPrinter * p, bool pickUpSettings ) +{ + d->printer = p; + + if ( p && pickUpSettings ) { + // top to botton in the old dialog. + // printer or file + d->printerOrFile->setButton( p->outputToFile() ); + printerOrFileSelected( p->outputToFile() ); + + // printer name + if ( !!p->printerName() ) { + QListViewItem * i = d->printers->firstChild(); + while ( i && i->text( 0 ) != p->printerName() ) + i = i->nextSibling(); + if ( i ) { + d->printers->setSelected( i, TRUE ); + d->ok->setEnabled( TRUE ); + } else if ( d->fileName->text().isEmpty() ) { + d->ok->setEnabled( d->printers->childCount() != 0 ); + } + } + + // print command does not exist any more + + // file name + d->printToFileButton->setEnabled( d->printer->isOptionEnabled( QPrinter::PrintToFile ) ); + d->fileName->setText( p->outputFileName() ); + + // orientation + d->orientationCombo->setCurrentItem( (int)p->orientation() ); + orientSelected( p->orientation() ); + + // page size + int n = 0; + while ( n < QPrinter::NPageSize && + d->indexToPageSize[n] != p->pageSize() ) + n++; + d->sizeCombo->setCurrentItem( n ); + paperSizeSelected( n ); + + // New stuff (Options) + + // page order + d->pageOrder->setButton( (int)p->pageOrder() ); + pageOrderSelected( p->pageOrder() ); + + // color mode + d->colorMode->setButton( (int)p->colorMode() ); + colorModeSelected( p->colorMode() ); + + // number of copies + d->copies->setValue( p->numCopies() ); + setNumCopies( p->numCopies() ); + } + + if( p ) { + d->printAllButton->setEnabled( TRUE ); + d->printSelectionButton + ->setEnabled( d->printer->isOptionEnabled( QPrinter::PrintSelection ) ); + d->printRangeButton + ->setEnabled( d->printer->isOptionEnabled( QPrinter::PrintPageRange ) ); + + QPrinter::PrintRange range = p->printRange(); + switch ( range ) { + case QPrinter::AllPages: + d->printAllButton->setChecked(TRUE); + printRangeSelected( d->printRange->id( d->printAllButton ) ); + break; + case QPrinter::Selection: + d->printSelectionButton->setChecked(TRUE); + printRangeSelected( d->printRange->id( d->printSelectionButton ) ); + break; + case QPrinter::PageRange: + d->printRangeButton->setChecked(TRUE); + printRangeSelected( d->printRange->id( d->printRangeButton ) ); + break; + } + } + + if ( p && p->maxPage() ) { + d->firstPage->setRange( p->minPage(), p->maxPage() ); + d->lastPage->setRange( p->minPage(), p->maxPage() ); + if ( p->fromPage() || p->toPage() ) { + setFirstPage( p->fromPage() ); + setLastPage( p->toPage() ); + d->firstPage->setValue(p->fromPage()); + d->lastPage->setValue(p->toPage()); + } + } +} + + +/*! Returns a pointer to the printer this dialog configures, or 0 if + this dialog does not operate on any printer. */ + +QPrinter * QPrintDialog::printer() const +{ + return d->printer; +} + + +void QPrintDialog::colorModeSelected( int id ) +{ + d->colorMode2 = (QPrinter::ColorMode)id; +} + +/*! + Adds the button \a but to the layout of the print dialog. The added + buttons are arranged from the left to the right below the + last groupbox of the printdialog. +*/ + +void QPrintDialog::addButton( QPushButton *but ) +{ + d->customLayout->addWidget( but ); +} + +void QPrintDialog::fileNameEditChanged( const QString &text ) +{ + if ( d->fileName->isEnabled() ) + d->ok->setEnabled( !text.isEmpty() ); +} + +#endif diff --git a/src/dialogs/qprintdialog.h b/src/dialogs/qprintdialog.h new file mode 100644 index 0000000..ea41d02 --- /dev/null +++ b/src/dialogs/qprintdialog.h @@ -0,0 +1,103 @@ +/**************************************************************************** +** +** Definition of print dialog. +** +** Created : 950829 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QPRINTDIALOG_H +#define QPRINTDIALOG_H + +#ifndef QT_H +#include "qdialog.h" +#endif // QT_H + +#ifndef QT_NO_PRINTDIALOG + +class QGroupBox; +class QPrintDialogPrivate; +class QListView; + +class Q_EXPORT QPrintDialog : public QDialog +{ + Q_OBJECT +public: + QPrintDialog( QPrinter *, QWidget* parent=0, const char* name=0 ); + ~QPrintDialog(); + + static bool getPrinterSetup( QPrinter *, QWidget* = 0 ); + static void setGlobalPrintDialog( QPrintDialog * ); + + void setPrinter( QPrinter *, bool = FALSE ); + QPrinter * printer() const; + + void addButton( QPushButton *but ); + +private slots: + void browseClicked(); + void okClicked(); + + void printerOrFileSelected( int ); + void landscapeSelected( int ); + void paperSizeSelected( int ); + void orientSelected( int ); + void pageOrderSelected( int ); + void colorModeSelected( int ); + void setNumCopies( int ); + void printRangeSelected( int ); + void setFirstPage( int ); + void setLastPage( int ); + + void fileNameEditChanged( const QString &text ); + +private: + QPrintDialogPrivate *d; + + QGroupBox * setupDestination(); + QGroupBox * setupOptions(); + QGroupBox * setupPaper(); + QGroupBox * setupPrinterSettings(); + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QPrintDialog( const QPrintDialog & ); + QPrintDialog &operator=( const QPrintDialog & ); +#endif +}; + +#endif + +#endif // QPRINTDIALOG_H diff --git a/src/dialogs/qprogressdialog.cpp b/src/dialogs/qprogressdialog.cpp new file mode 100644 index 0000000..bdae310 --- /dev/null +++ b/src/dialogs/qprogressdialog.cpp @@ -0,0 +1,826 @@ +/**************************************************************************** +** +** Implementation of QProgressDialog class +** +** Created : 970521 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qprogressdialog.h" + +#ifndef QT_NO_PROGRESSDIALOG + +#include "qaccel.h" +#include "qpainter.h" +#include "qdrawutil.h" +#include "qdatetime.h" +#include "qapplication.h" +#include "qstyle.h" +#include "qpushbutton.h" +#include "qcursor.h" +#include "qtimer.h" +#include <limits.h> + +// If the operation is expected to take this long (as predicted by +// progress time), show the progress dialog. +static const int defaultShowTime = 4000; +// Wait at least this long before attempting to make a prediction. +static const int minWaitTime = 50; + +// Various layout values +static const int margin_lr = 10; +static const int margin_tb = 10; +static const int spacing = 4; + + +class QProgressDialogData +{ +public: + QProgressDialogData( QProgressDialog* that, QWidget* parent, + const QString& labelText, + int totalSteps ) : + creator( parent ), + label( new QLabel(labelText,that,"label") ), + cancel( 0 ), + bar( new QProgressBar(totalSteps,that,"bar") ), + shown_once( FALSE ), + cancellation_flag( FALSE ), + showTime( defaultShowTime ) + { + label->setAlignment(that->style().styleHint(QStyle::SH_ProgressDialog_TextLabelAlignment, that)); + } + + QWidget *creator; + QLabel *label; + QPushButton *cancel; + QProgressBar *bar; + bool shown_once; + bool cancellation_flag; + QTime starttime; +#ifndef QT_NO_CURSOR + QCursor parentCursor; +#endif + int showTime; + bool autoClose; + bool autoReset; + bool forceHide; +}; + + +/*! + \class QProgressDialog qprogressdialog.h + \brief The QProgressDialog class provides feedback on the progress of a slow operation. + \ingroup dialogs + \mainclass + + A progress dialog is used to give the user an indication of how long + an operation is going to take, and to demonstrate that the + application has not frozen. It can also give the user an opportunity + to abort the operation. + + A common problem with progress dialogs is that it is difficult to know + when to use them; operations take different amounts of time on different + hardware. QProgressDialog offers a solution to this problem: + it estimates the time the operation will take (based on time for + steps), and only shows itself if that estimate is beyond minimumDuration() + (4 seconds by default). + + Use setTotalSteps() (or the constructor) to set the number of + "steps" in the operation and call setProgress() as the operation + progresses. The step value can be chosen arbitrarily. It can be the + number of files copied, the number of bytes received, the number of + iterations through the main loop of your algorithm, or some other + suitable unit. Progress starts at 0, and the progress dialog shows + that the operation has finished when you call setProgress() with + totalSteps() as its argument. + + The dialog automatically resets and hides itself at the end of the + operation. Use setAutoReset() and setAutoClose() to change this + behavior. + + There are two ways of using QProgressDialog: modal and modeless. + + Using a modal QProgressDialog is simpler for the programmer, but you + must call QApplication::processEvents() or + QEventLoop::processEvents(ExcludeUserInput) to keep the event loop + running to ensure that the application doesn't freeze. Do the + operation in a loop, call \l setProgress() at intervals, and check + for cancellation with wasCanceled(). For example: +\code +QProgressDialog progress( "Copying files...", "Abort Copy", numFiles, + this, "progress", TRUE ); +for ( int i = 0; i < numFiles; i++ ) { + progress.setProgress( i ); + qApp->processEvents(); + + if ( progress.wasCanceled() ) + break; + //... copy one file +} +progress.setProgress( numFiles ); +\endcode + + A modeless progress dialog is suitable for operations that take + place in the background, where the user is able to interact with the + application. Such operations are typically based on QTimer (or + QObject::timerEvent()), QSocketNotifier, or QUrlOperator; or performed + in a separate thread. A QProgressBar in the status bar of your main window + is often an alternative to a modeless progress dialog. + + You need to have an event loop to be running, connect the + canceled() signal to a slot that stops the operation, and call \l + setProgress() at intervals. For example: +\code +Operation::Operation( QObject *parent = 0 ) + : QObject( parent ), steps( 0 ) +{ + pd = new QProgressDialog( "Operation in progress.", "Cancel", 100 ); + connect( pd, SIGNAL(canceled()), this, SLOT(cancel()) ); + t = new QTimer( this ); + connect( t, SIGNAL(timeout()), this, SLOT(perform()) ); + t->start( 0 ); +} + +void Operation::perform() +{ + pd->setProgress( steps ); + //... perform one percent of the operation + steps++; + if ( steps > pd->totalSteps() ) + t->stop(); +} + +void Operation::cancel() +{ + t->stop(); + //... cleanup +} +\endcode + + + In both modes the progress dialog may be customized by + replacing the child widgets with custom widgets by using setLabel(), + setBar(), and setCancelButton(). + The functions setLabelText() and setCancelButtonText() + set the texts shown. + + <img src=qprogdlg-m.png> <img src=qprogdlg-w.png> + + \sa QDialog QProgressBar + \link guibooks.html#fowler GUI Design Handbook: Progress Indicator\endlink +*/ + + +/*! + Returns the QLabel currently being displayed above the progress bar. + This QLabel is owned by the QProgressDialog. + + \sa setLabel() +*/ +QLabel *QProgressDialog::label() const +{ + return d->label; +} + +/*! + Returns the QProgressBar currently being used to display progress. + This QProgressBar is owned by the QProgressDialog. + + \sa setBar() +*/ +QProgressBar *QProgressDialog::bar() const +{ + return d->bar; +} + + +/*! + Constructs a progress dialog. + + Default settings: + \list + \i The label text is empty. + \i The cancel button text is (translated) "Cancel". + \i The total number of steps is 100. + \endlist + + The \a creator argument is the widget to use as the dialog's parent. + The \a name, \a modal, and the widget flags, \a f, are + passed to the QDialog::QDialog() constructor. If \a modal is FALSE (the + default), you must have an event loop proceeding for any redrawing + of the dialog to occur. If \a modal is TRUE, the dialog ensures that + events are processed when needed. + + \sa setLabelText(), setLabel(), setCancelButtonText(), setCancelButton(), + setTotalSteps() +*/ + +QProgressDialog::QProgressDialog( QWidget *creator, const char *name, + bool modal, WFlags f ) + : QDialog( creator, name, modal, f) +{ + init( creator, QString::fromLatin1(""), tr("Cancel"), 100 ); +} + +/*! + Constructs a progress dialog. + + The \a labelText is text used to remind the user what is progressing. + + The \a cancelButtonText is the text to display on the cancel button, + or 0 if no cancel button is to be shown. + + The \a totalSteps is the total number of steps in the operation for + which this progress dialog shows progress. For example, if the + operation is to examine 50 files, this value would be 50. Before + examining the first file, call setProgress(0). As each file is + processed call setProgress(1), setProgress(2), etc., finally + calling setProgress(50) after examining the last file. + + The \a creator argument is the widget to use as the dialog's parent. + The \a name, \a modal, and widget flags, \a f, are passed to the + QDialog::QDialog() constructor. If \a modal is FALSE (the default), + you will must have an event loop proceeding for any redrawing of + the dialog to occur. If \a modal is TRUE, the dialog ensures that + events are processed when needed. + + + \sa setLabelText(), setLabel(), setCancelButtonText(), setCancelButton(), + setTotalSteps() +*/ + +QProgressDialog::QProgressDialog( const QString &labelText, + const QString &cancelButtonText, + int totalSteps, + QWidget *creator, const char *name, + bool modal, WFlags f ) + : QDialog( creator, name, modal, f) +{ + init( creator, labelText, cancelButtonText, totalSteps ); +} + + +/*! + Destroys the progress dialog. +*/ + +QProgressDialog::~QProgressDialog() +{ +#ifndef QT_NO_CURSOR + if ( d->creator ) + d->creator->setCursor( d->parentCursor ); +#endif + delete d; +} + +void QProgressDialog::init( QWidget *creator, + const QString& lbl, const QString& canc, + int totstps) +{ + d = new QProgressDialogData(this, creator, lbl, totstps); + d->autoClose = TRUE; + d->autoReset = TRUE; + d->forceHide = FALSE; + setCancelButtonText( canc ); + connect( this, SIGNAL(canceled()), this, SIGNAL(cancelled()) ); + connect( this, SIGNAL(canceled()), this, SLOT(cancel()) ); + forceTimer = new QTimer( this ); + connect( forceTimer, SIGNAL(timeout()), this, SLOT(forceShow()) ); + layout(); +} + +/*! + \fn void QProgressDialog::canceled() + + This signal is emitted when the cancel button is clicked. + It is connected to the cancel() slot by default. + + \sa wasCanceled() +*/ + +/*! + \fn void QProgressDialog::cancelled() + + \obsolete + + Use canceled() instead. +*/ + + +/*! + Sets the label to \a label. The progress dialog resizes to fit. The + label becomes owned by the progress dialog and will be deleted when + necessary, so do not pass the address of an object on the stack. + + \sa setLabelText() +*/ + +void QProgressDialog::setLabel( QLabel *label ) +{ + delete d->label; + d->label = label; + if (label) { + if ( label->parentWidget() == this ) { + label->hide(); // until we resize + } else { + label->reparent( this, 0, QPoint(0,0), FALSE ); + } + } + int w = QMAX( isVisible() ? width() : 0, sizeHint().width() ); + int h = QMAX( isVisible() ? height() : 0, sizeHint().height() ); + resize( w, h ); + if (label) + label->show(); +} + + +/*! + \property QProgressDialog::labelText + \brief the label's text + + The default text is QString::null. +*/ + +QString QProgressDialog::labelText() const +{ + if ( label() ) + return label()->text(); + return QString::null; +} + +void QProgressDialog::setLabelText( const QString &text ) +{ + if ( label() ) { + label()->setText( text ); + int w = QMAX( isVisible() ? width() : 0, sizeHint().width() ); + int h = QMAX( isVisible() ? height() : 0, sizeHint().height() ); + resize( w, h ); + } +} + + +/*! + Sets the cancel button to the push button, \a cancelButton. The + progress dialog takes ownership of this button which will be deleted + when necessary, so do not pass the address of an object that is on + the stack, i.e. use new() to create the button. + + \sa setCancelButtonText() +*/ + +void QProgressDialog::setCancelButton( QPushButton *cancelButton ) +{ + delete d->cancel; + d->cancel = cancelButton; + if (cancelButton) { + if ( cancelButton->parentWidget() == this ) { + cancelButton->hide(); // until we resize + } else { + cancelButton->reparent( this, 0, QPoint(0,0), FALSE ); + } + connect( d->cancel, SIGNAL(clicked()), this, SIGNAL(canceled()) ); +#ifndef QT_NO_ACCEL + QAccel *accel = new QAccel( this ); + accel->connectItem( accel->insertItem(Key_Escape), + d->cancel, SIGNAL(clicked()) ); +#endif + } + int w = QMAX( isVisible() ? width() : 0, sizeHint().width() ); + int h = QMAX( isVisible() ? height() : 0, sizeHint().height() ); + resize( w, h ); + if (cancelButton) + cancelButton->show(); +} + +/*! + Sets the cancel button's text to \a cancelButtonText. + \sa setCancelButton() +*/ + +void QProgressDialog::setCancelButtonText( const QString &cancelButtonText ) +{ + if ( !cancelButtonText.isNull() ) { + if ( d->cancel ) + d->cancel->setText(cancelButtonText); + else + setCancelButton(new QPushButton(cancelButtonText, this, "cancel")); + } else { + setCancelButton(0); + } + int w = QMAX( isVisible() ? width() : 0, sizeHint().width() ); + int h = QMAX( isVisible() ? height() : 0, sizeHint().height() ); + resize( w, h ); +} + + +/*! + Sets the progress bar widget to \a bar. The progress dialog resizes to + fit. The progress dialog takes ownership of the progress \a bar which + will be deleted when necessary, so do not use a progress bar + allocated on the stack. +*/ + +void QProgressDialog::setBar( QProgressBar *bar ) +{ + if ( progress() > 0 ) { +#if defined(QT_CHECK_STATE) + qWarning( "QProgrssDialog::setBar: Cannot set a new progress bar " + "while the old one is active" ); +#endif + } + delete d->bar; + d->bar = bar; + int w = QMAX( isVisible() ? width() : 0, sizeHint().width() ); + int h = QMAX( isVisible() ? height() : 0, sizeHint().height() ); + resize( w, h ); +} + + +/*! + \property QProgressDialog::wasCancelled + \brief whether the dialog was canceled + + \obsolete + + Use \l wasCanceled instead. +*/ + +/*! + \property QProgressDialog::wasCanceled + \brief whether the dialog was canceled + + \sa setProgress() +*/ + +bool QProgressDialog::wasCancelled() const +{ + return d->cancellation_flag; +} + + +/*! + \property QProgressDialog::totalSteps + \brief the total number of steps + + The default is 0. +*/ + +int QProgressDialog::totalSteps() const +{ + if ( d && d->bar ) + return bar()->totalSteps(); + return 0; +} + +void QProgressDialog::setTotalSteps( int totalSteps ) +{ + bar()->setTotalSteps( totalSteps ); +} + + +/*! + Resets the progress dialog. + The progress dialog becomes hidden if autoClose() is TRUE. + + \sa setAutoClose(), setAutoReset() +*/ + +void QProgressDialog::reset() +{ +#ifndef QT_NO_CURSOR + if ( progress() >= 0 ) { + if ( d->creator ) + d->creator->setCursor( d->parentCursor ); + } +#endif + if ( d->autoClose || d->forceHide ) + hide(); + bar()->reset(); + d->cancellation_flag = FALSE; + d->shown_once = FALSE; + forceTimer->stop(); +} + +/*! + Resets the progress dialog. wasCanceled() becomes TRUE until + the progress dialog is reset. + The progress dialog becomes hidden. +*/ + +void QProgressDialog::cancel() +{ + d->forceHide = TRUE; + reset(); + d->forceHide = FALSE; + d->cancellation_flag = TRUE; +} + +/*! + \property QProgressDialog::progress + \brief the current amount of progress made. + + For the progress dialog to work as expected, you should initially set + this property to 0 and finally set it to + QProgressDialog::totalSteps(); you can call setProgress() any number of times + in-between. + + \warning If the progress dialog is modal + (see QProgressDialog::QProgressDialog()), + this function calls QApplication::processEvents(), so take care that + this does not cause undesirable re-entrancy in your code. For example, + don't use a QProgressDialog inside a paintEvent()! + + \sa totalSteps +*/ + +int QProgressDialog::progress() const +{ + return bar()->progress(); +} + +void QProgressDialog::setProgress( int progress ) +{ + if ( progress == bar()->progress() || + bar()->progress() == -1 && progress == bar()->totalSteps() ) + return; + + bar()->setProgress(progress); + + if ( d->shown_once ) { + if (testWFlags(WShowModal)) + qApp->processEvents(); + } else { + if ( progress == 0 ) { +#ifndef QT_NO_CURSOR + if ( d->creator ) { + d->parentCursor = d->creator->cursor(); + d->creator->setCursor( waitCursor ); + } +#endif + d->starttime.start(); + forceTimer->start( d->showTime ); + return; + } else { + bool need_show; + int elapsed = d->starttime.elapsed(); + if ( elapsed >= d->showTime ) { + need_show = TRUE; + } else { + if ( elapsed > minWaitTime ) { + int estimate; + if ( (totalSteps() - progress) >= INT_MAX / elapsed ) + estimate = (totalSteps() - progress) / progress * elapsed; + else + estimate = elapsed * (totalSteps() - progress) / progress; + need_show = estimate >= d->showTime; + } else { + need_show = FALSE; + } + } + if ( need_show ) { + int w = QMAX( isVisible() ? width() : 0, sizeHint().width() ); + int h = QMAX( isVisible() ? height() : 0, sizeHint().height() ); + resize( w, h ); + show(); + d->shown_once = TRUE; + } + } +#ifdef Q_WS_MACX + QApplication::flush(); +#endif + } + + if ( progress == bar()->totalSteps() && d->autoReset ) + reset(); +} + +/*! + \overload + + Sets the current amount of progress to \a progress and the total number of + steps to \a totalSteps. + + \sa setTotalSteps() +*/ + +void QProgressDialog::setProgress( int progress, int totalSteps ) +{ + setTotalSteps( totalSteps ); + setProgress( progress ); +} + +/*! + Returns a size that fits the contents of the progress dialog. + The progress dialog resizes itself as required, so you should not + need to call this yourself. +*/ + +QSize QProgressDialog::sizeHint() const +{ + QSize sh = label()->sizeHint(); + QSize bh = bar()->sizeHint(); + int h = margin_tb*2 + bh.height() + sh.height() + spacing; + if ( d->cancel ) + h += d->cancel->sizeHint().height() + spacing; + return QSize( QMAX(200, sh.width() + 2*margin_lr), h ); +} + +/*!\reimp +*/ +void QProgressDialog::resizeEvent( QResizeEvent * ) +{ + layout(); +} + +/*! + \reimp +*/ +void QProgressDialog::styleChange(QStyle& s) +{ + QDialog::styleChange(s); + layout(); +} + +void QProgressDialog::layout() +{ + int sp = spacing; + int mtb = margin_tb; + int mlr = QMIN(width()/10, margin_lr); + const bool centered = + bool(style().styleHint(QStyle::SH_ProgressDialog_CenterCancelButton, this)); + + QSize cs = d->cancel ? d->cancel->sizeHint() : QSize(0,0); + QSize bh = bar()->sizeHint(); + int cspc; + int lh = 0; + + // Find spacing and sizes that fit. It is important that a progress + // dialog can be made very small if the user demands it so. + for (int attempt=5; attempt--; ) { + cspc = d->cancel ? cs.height() + sp : 0; + lh = QMAX(0, height() - mtb - bh.height() - sp - cspc); + + if ( lh < height()/4 ) { + // Getting cramped + sp /= 2; + mtb /= 2; + if ( d->cancel ) { + cs.setHeight(QMAX(4,cs.height()-sp-2)); + } + bh.setHeight(QMAX(4,bh.height()-sp-1)); + } else { + break; + } + } + + if ( d->cancel ) { + d->cancel->setGeometry( + centered ? width()/2 - cs.width()/2 : width() - mlr - cs.width(), + height() - mtb - cs.height() + sp, + cs.width(), cs.height() ); + } + + label()->setGeometry( mlr, 0, width()-mlr*2, lh ); + bar()->setGeometry( mlr, lh+sp, width()-mlr*2, bh.height() ); +} + +/*! + \property QProgressDialog::minimumDuration + \brief the time that must pass before the dialog appears + + If the expected duration of the task is less than the + minimumDuration, the dialog will not appear at all. This prevents + the dialog popping up for tasks that are quickly over. For tasks + that are expected to exceed the minimumDuration, the dialog will + pop up after the minimumDuration time or as soon as any progress + is set. + + If set to 0, the dialog is always shown as soon as any progress is + set. The default is 4000 milliseconds. +*/ +void QProgressDialog::setMinimumDuration( int ms ) +{ + d->showTime = ms; + if ( bar()->progress() == 0 ) { + forceTimer->stop(); + forceTimer->start( ms ); + } +} + +int QProgressDialog::minimumDuration() const +{ + return d->showTime; +} + + +/*! + \reimp +*/ + +void QProgressDialog::closeEvent( QCloseEvent *e ) +{ + emit canceled(); + QDialog::closeEvent( e ); +} + +/*! + \property QProgressDialog::autoReset + \brief whether the progress dialog calls reset() as soon as progress() equals totalSteps() + + The default is TRUE. + + \sa setAutoClose() +*/ + +void QProgressDialog::setAutoReset( bool b ) +{ + d->autoReset = b; +} + +bool QProgressDialog::autoReset() const +{ + return d->autoReset; +} + +/*! + \property QProgressDialog::autoClose + \brief whether the dialog gets hidden by reset() + + The default is TRUE. + + \sa setAutoReset() +*/ + +void QProgressDialog::setAutoClose( bool b ) +{ + d->autoClose = b; +} + +bool QProgressDialog::autoClose() const +{ + return d->autoClose; +} + +/*! + \reimp +*/ + +void QProgressDialog::showEvent( QShowEvent *e ) +{ + QDialog::showEvent( e ); + int w = QMAX( isVisible() ? width() : 0, sizeHint().width() ); + int h = QMAX( isVisible() ? height() : 0, sizeHint().height() ); + resize( w, h ); + forceTimer->stop(); +} + +/*! + Shows the dialog if it is still hidden after the algorithm has been started + and minimumDuration milliseconds have passed. + + \sa setMinimumDuration() +*/ + +void QProgressDialog::forceShow() +{ + if ( d->shown_once || d->cancellation_flag ) + return; + + show(); + d->shown_once = TRUE; +} + + +#endif diff --git a/src/dialogs/qprogressdialog.h b/src/dialogs/qprogressdialog.h new file mode 100644 index 0000000..fb67178 --- /dev/null +++ b/src/dialogs/qprogressdialog.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Definition of QProgressDialog class +** +** Created : 970520 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QPROGRESSDIALOG_H +#define QPROGRESSDIALOG_H + +#ifndef QT_H +#include "qsemimodal.h" +#include "qlabel.h" // ### remove or keep for users' convenience? +#include "qprogressbar.h" // ### remove or keep for users' convenience? +#endif // QT_H + +#ifndef QT_NO_PROGRESSDIALOG + +class QPushButton; +class QTimer; +class QProgressDialogData; + +class Q_EXPORT QProgressDialog : public QDialog +{ + Q_OBJECT + Q_PROPERTY( bool wasCancelled READ wasCancelled DESIGNABLE false STORED false ) // ### remove in 4.0 + Q_PROPERTY( bool wasCanceled READ wasCanceled ) + Q_PROPERTY( int totalSteps READ totalSteps WRITE setTotalSteps ) + Q_PROPERTY( int progress READ progress WRITE setProgress ) + Q_PROPERTY( bool autoReset READ autoReset WRITE setAutoReset ) + Q_PROPERTY( bool autoClose READ autoClose WRITE setAutoClose ) + Q_PROPERTY( int minimumDuration READ minimumDuration WRITE setMinimumDuration ) + Q_PROPERTY( QString labelText READ labelText WRITE setLabelText ) + +public: + QProgressDialog( QWidget* parent=0, const char* name=0, bool modal=FALSE, + WFlags f=0 ); + QProgressDialog( const QString& labelText, const QString &cancelButtonText, + int totalSteps, QWidget* parent=0, const char* name=0, + bool modal=FALSE, WFlags f=0 ); + ~QProgressDialog(); + + void setLabel( QLabel * ); + void setCancelButton( QPushButton * ); + void setBar( QProgressBar * ); + + // ### Qt 4.0: remove wasCancelled() in 4.0 + bool wasCancelled() const; + inline bool wasCanceled() const { return wasCancelled(); } + + int totalSteps() const; + int progress() const; + + QSize sizeHint() const; + + QString labelText() const; + + void setAutoReset( bool b ); + bool autoReset() const; + void setAutoClose( bool b ); + bool autoClose() const; + +public slots: + void cancel(); + void reset(); + void setTotalSteps( int totalSteps ); + void setProgress( int progress ); + void setProgress( int progress, int totalSteps ); + void setLabelText( const QString &); + void setCancelButtonText( const QString &); + + void setMinimumDuration( int ms ); +public: + int minimumDuration() const; + +signals: + // ### remove cancelled() in 4.0 + void cancelled(); + void canceled(); + +protected: + void resizeEvent( QResizeEvent * ); + void closeEvent( QCloseEvent * ); + void styleChange( QStyle& ); + void showEvent( QShowEvent *e ); + +protected slots: + void forceShow(); + +private: + void init( QWidget *creator, const QString& lbl, const QString &canc, + int totstps); + void layout(); + QLabel *label() const; + QProgressBar *bar() const; + QProgressDialogData *d; + QTimer *forceTimer; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QProgressDialog( const QProgressDialog & ); + QProgressDialog &operator=( const QProgressDialog & ); +#endif +}; + +#endif // QT_NO_PROGRESSDIALOG + +#endif // QPROGRESSDIALOG_H diff --git a/src/dialogs/qsemimodal.h b/src/dialogs/qsemimodal.h new file mode 100644 index 0000000..52fa0a9 --- /dev/null +++ b/src/dialogs/qsemimodal.h @@ -0,0 +1,66 @@ +/**************************************************************************** +** +** Definition of QSemiModal class for source compatibility +** +** Created : 001010 +** +** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSEMIMODAL_H +#define QSEMIMODAL_H + +#ifndef QT_H +#include "qdialog.h" +#endif // QT_H + +#ifndef QT_NO_COMPAT +#ifndef QT_NO_SEMIMODAL +class Q_EXPORT QSemiModal : public QDialog +{ + Q_OBJECT +public: + QSemiModal( QWidget* parent=0, const char* name=0, bool modal=FALSE, WFlags f=0 ) + : QDialog( parent, name, modal, f ) { } + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QSemiModal( const QSemiModal & ); + QSemiModal &operator=( const QSemiModal & ); +#endif +}; +#endif +#endif + +#endif // QSEMIMODAL_H diff --git a/src/dialogs/qt_dialogs.pri b/src/dialogs/qt_dialogs.pri new file mode 100644 index 0000000..9bd8992 --- /dev/null +++ b/src/dialogs/qt_dialogs.pri @@ -0,0 +1,33 @@ +# Qt dialogs module + +dialogs { + DIALOGS_P = dialogs + + HEADERS += $$DIALOGS_H/qcolordialog.h \ + $$DIALOGS_H/qdialog.h \ + $$DIALOGS_H/qerrormessage.h \ + $$DIALOGS_H/qfiledialog.h \ + $$DIALOGS_H/qfontdialog.h \ + $$DIALOGS_H/qmessagebox.h \ + $$DIALOGS_H/qprogressdialog.h \ + $$DIALOGS_H/qsemimodal.h \ + $$DIALOGS_H/qtabdialog.h \ + $$DIALOGS_H/qwizard.h \ + $$DIALOGS_H/qinputdialog.h + + !embedded:mac:SOURCES += $$DIALOGS_CPP/qfiledialog_mac.cpp $$DIALOGS_CPP/qcolordialog_mac.cpp + win32:SOURCES += $$DIALOGS_CPP/qfiledialog_win.cpp + unix:SOURCES += $$DIALOGS_CPP/qprintdialog.cpp + unix:HEADERS += $$DIALOGS_H/qprintdialog.h + + SOURCES += $$DIALOGS_CPP/qcolordialog.cpp \ + $$DIALOGS_CPP/qdialog.cpp \ + $$DIALOGS_CPP/qerrormessage.cpp \ + $$DIALOGS_CPP/qfiledialog.cpp \ + $$DIALOGS_CPP/qfontdialog.cpp \ + $$DIALOGS_CPP/qmessagebox.cpp \ + $$DIALOGS_CPP/qprogressdialog.cpp \ + $$DIALOGS_CPP/qtabdialog.cpp \ + $$DIALOGS_CPP/qwizard.cpp \ + $$DIALOGS_CPP/qinputdialog.cpp +} diff --git a/src/dialogs/qtabdialog.cpp b/src/dialogs/qtabdialog.cpp new file mode 100644 index 0000000..e770a4a --- /dev/null +++ b/src/dialogs/qtabdialog.cpp @@ -0,0 +1,1145 @@ +/**************************************************************************** +** +** Implementation of QTabDialog class +** +** Created : 960825 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qtabdialog.h" + +#ifndef QT_NO_TABDIALOG + +#include "qobjectlist.h" +#include "qtabbar.h" +#include "qtabwidget.h" +#include "qpushbutton.h" +#include "qpainter.h" +#include "qpixmap.h" +#include "qapplication.h" +#include "qtabwidget.h" +#include "qwidgetstack.h" +#include "qlayout.h" + +/*! + \class QTabDialog qtabdialog.h + + \brief The QTabDialog class provides a stack of tabbed widgets. + + \ingroup dialogs + \mainclass + + A tabbed dialog is one in which several "tab pages" are available. + By clicking on a tab page's tab or by pressing the indicated + Alt+\e{letter} key combination, the user can select which tab page + they want to use. + + QTabDialog provides a tab bar consisting of single row of tabs at + the top; each tab has an associated widget which is that tab's + tab page. In addition, QTabDialog provides an OK button and the + following optional buttons: Apply, Cancel, Defaults and Help. + + The normal way to use QTabDialog is to do the following in the + constructor: + \list 1 + \i Create a QTabDialog. + \i Create a QWidget for each of the pages in the tab dialog, insert + children into it, set up geometry management for it, and use + addTab() (or insertTab()) to set up a tab and keyboard accelerator + for it. + \i Set up the buttons for the tab dialog using setOkButton(), + setApplyButton(), setDefaultsButton(), setCancelButton() and + setHelpButton(). + \i Connect to the signals and slots. + \endlist + + If you don't call addTab() the page you have created will not be + visible. Don't confuse the object name you supply to the + QWidget constructor and the tab label you supply to addTab(); + addTab() takes user-visible name that appears on the widget's tab + and may identify an accelerator, whereas the widget name is used + primarily for debugging. + + Almost all applications have to connect the applyButtonPressed() + signal to something. applyButtonPressed() is emitted when either OK + or Apply is clicked, and your slot must copy the dialog's state into + the application. + + There are also several other signals which may be useful: + \list + \i cancelButtonPressed() is emitted when the user clicks Cancel. + \i defaultButtonPressed() is emitted when the user clicks Defaults; + the slot it is connected to should reset the state of the dialog to + the application defaults. + \i helpButtonPressed() is emitted when the user clicks Help. + \i aboutToShow() is emitted at the start of show(); if there is any + chance that the state of the application may change between the + creation of the tab dialog and the time show() is called, you must + connect this signal to a slot that resets the state of the dialog. + \i currentChanged() is emitted when the user selects a page. + \endlist + + Each tab is either enabled or disabled at any given time (see + setTabEnabled()). If a tab is enabled the tab text is drawn in + black and the user can select that tab. If it is disabled the tab + is drawn in a different way and the user cannot select that tab. + Note that even if a tab is disabled, the page can still be visible; + for example, if all of the tabs happen to be disabled. + + You can change a tab's label and iconset using changeTab(). A tab + page can be removed with removePage() and shown with showPage(). The + current page is given by currentPage(). + + QTabDialog does not support tabs on the sides or bottom, nor can + you set or retrieve the visible page. If you need more functionality + than QTabDialog provides, consider creating a QDialog and using a + QTabBar with QTabWidgets. + + Most of the functionality in QTabDialog is provided by a QTabWidget. + + <img src=qtabdlg-m.png> <img src=qtabdlg-w.png> + + \sa QDialog +*/ + +/*! + \fn void QTabDialog::selected( const QString & ); + \obsolete + + This signal is emitted whenever a tab is selected (raised), + including during the first show(). + + \sa raise() +*/ + +/*! \fn void QTabDialog::currentChanged( QWidget* ); + + This signal is emitted whenever the current page changes. + + \sa currentPage(), showPage(), tabLabel() +*/ + + +// add comments about delete, ok and apply + +class QTabDialogPrivate +{ +public: + QTabDialogPrivate(); + + QTabWidget* tw; + + QPushButton * ok; + QPushButton * cb; + QPushButton * db; + QPushButton * hb; + QPushButton * ab; + + QBoxLayout * tll; +}; + +QTabDialogPrivate::QTabDialogPrivate() + : tw(0), + ok(0), cb(0), db(0), hb(0), ab(0), + tll(0) +{ } + +/*! + Constructs a QTabDialog with only an OK button. + The \a parent, \a name, \a modal and widget flag, \a f, arguments + are passed on to the QDialog constructor. +*/ + +QTabDialog::QTabDialog( QWidget *parent, const char *name, bool modal, + WFlags f ) + : QDialog( parent, name, modal, f ) +{ + d = new QTabDialogPrivate; + Q_CHECK_PTR( d ); + + d->tw = new QTabWidget( this, "tab widget" ); + connect ( d->tw, SIGNAL ( selected(const QString&) ), this, SIGNAL( selected(const QString&) ) ); + connect ( d->tw, SIGNAL ( currentChanged(QWidget*) ), this, SIGNAL( currentChanged(QWidget*) ) ); + + d->ok = new QPushButton( this, "ok" ); + Q_CHECK_PTR( d->ok ); + d->ok->setText( tr("OK") ); + d->ok->setDefault( TRUE ); + connect( d->ok, SIGNAL(clicked()), + this, SIGNAL(applyButtonPressed()) ); + connect( d->ok, SIGNAL(clicked()), + this, SLOT(accept()) ); +} + + +/*! + Destroys the tab dialog. +*/ + +QTabDialog::~QTabDialog() +{ + delete d; +} + + +/*! + Sets the font for the tabs to \a font. + + If the widget is visible, the display is updated with the new font + immediately. There may be some geometry changes, depending on the + size of the old and new fonts. +*/ + +void QTabDialog::setFont( const QFont & font ) +{ + QDialog::setFont( font ); + setSizes(); +} + + +/*! + \fn void QTabDialog::applyButtonPressed(); + + This signal is emitted when either the Apply or OK button is clicked. + + It should be connected to a slot (or several slots) that change the + application's state according to the state of the dialog. + + \sa cancelButtonPressed() defaultButtonPressed() setApplyButton() +*/ + + +/*! + Returns TRUE if the tab dialog has a Defaults button; otherwise + returns FALSE. + + \sa setDefaultButton() defaultButtonPressed() hasApplyButton() + hasCancelButton() +*/ + +bool QTabDialog::hasDefaultButton() const +{ + return d->db != 0; +} + + +/*! + Returns TRUE if the tab dialog has a Help button; otherwise returns + FALSE. + + \sa setHelpButton() helpButtonPressed() hasApplyButton() + hasCancelButton() +*/ + +bool QTabDialog::hasHelpButton() const +{ + return d->hb != 0; +} + + +/*! + \fn void QTabDialog::cancelButtonPressed(); + + This signal is emitted when the Cancel button is clicked. It is + automatically connected to QDialog::reject(), which will hide the + dialog. + + The Cancel button should not change the application's state at all, + so you should generally not need to connect it to any slot. + + \sa applyButtonPressed() defaultButtonPressed() setCancelButton() +*/ + + +/*! + Returns TRUE if the tab dialog has a Cancel button; otherwise + returns FALSE. + + \sa setCancelButton() cancelButtonPressed() hasApplyButton() + hasDefaultButton() +*/ + +bool QTabDialog::hasCancelButton() const +{ + return d->cb != 0; +} + + +/*! + \fn void QTabDialog::defaultButtonPressed(); + + This signal is emitted when the Defaults button is pressed. It + should reset the dialog (but not the application) to the "factory + defaults". + + The application's state should not be changed until the user clicks + Apply or OK. + + \sa applyButtonPressed() cancelButtonPressed() setDefaultButton() +*/ + + +/*! + \fn void QTabDialog::helpButtonPressed(); + + This signal is emitted when the Help button is pressed. It + could be used to present information about how to use the dialog. + + \sa applyButtonPressed() cancelButtonPressed() setHelpButton() +*/ + + +/*! + Returns TRUE if the tab dialog has an Apply button; otherwise + returns FALSE. + + \sa setApplyButton() applyButtonPressed() hasCancelButton() + hasDefaultButton() +*/ + +bool QTabDialog::hasApplyButton() const +{ + return d->ab != 0; +} + + +/*! + Returns TRUE if the tab dialog has an OK button; otherwise returns + FALSE. + + \sa setOkButton() hasApplyButton() hasCancelButton() + hasDefaultButton() +*/ + +bool QTabDialog::hasOkButton() const +{ + return d->ok != 0; +} + + +/*! + \fn void QTabDialog::aboutToShow() + + This signal is emitted by show() when it is time to set the state of + the dialog's contents. The dialog should reflect the current state + of the application when it appears; if there is any possibility that + the state of the application may change between the time you call + QTabDialog::QTabDialog() and QTabDialog::show(), you should set the + dialog's state in a slot and connect this signal to it. + + This applies mainly to QTabDialog objects that are kept around + hidden, rather than being created, shown, and deleted afterwards. + + \sa applyButtonPressed(), show(), cancelButtonPressed() +*/ + + +/*!\reimp +*/ +void QTabDialog::show() +{ + // Reimplemented in order to delay show()'ing of every page + // except the initially visible one, and in order to emit the + // aboutToShow() signal. + if ( topLevelWidget() == this ) + d->tw->setFocus(); + emit aboutToShow(); + setSizes(); + setUpLayout(); + QDialog::show(); +} + + +/*! + Ensures that tab page \a i is visible and appropriately sized. +*/ + +void QTabDialog::showTab( int i ) +{ + d->tw->showTab( i ); +} + + +/*! + Adds another tab and page to the tab view. + + The new page is \a child; the tab's label is \a label. + Note the difference between the widget name (which you supply to + widget constructors and to setTabEnabled(), for example) and the tab + label. The name is internal to the program and invariant, whereas + the label is shown on-screen and may vary according to language and + other factors. + + If the tab's \a label contains an ampersand, the letter following + the ampersand is used as an accelerator for the tab, e.g. if the + label is "Bro&wse" then Alt+W becomes an accelerator which will + move the focus to this tab. + + If you call addTab() after show() the screen will flicker and the + user may be confused. + + \sa insertTab() +*/ + +void QTabDialog::addTab( QWidget * child, const QString &label ) +{ + d->tw->addTab( child, label ); +} + + + +/*! \overload + + This version of the function shows the \a iconset as well as the \a + label on the tab of \a child. +*/ +void QTabDialog::addTab( QWidget *child, const QIconSet& iconset, const QString &label) +{ + d->tw->addTab( child, iconset, label ); +} + +/*! + \overload + + This is a lower-level method for adding tabs, similar to the other + addTab() method. It is useful if you are using setTabBar() to set a + QTabBar subclass with an overridden QTabBar::paint() function for a + subclass of QTab. + + The \a child is the widget to be placed on the new tab page. The \a + tab is the tab to display on the tab page -- normally this shows a + label or an icon that identifies the tab page. + +*/ +void QTabDialog::addTab( QWidget * child, QTab* tab ) +{ + d->tw->addTab( child, tab ); +} + +/*! + Inserts another tab and page to the tab view. + + The new page is \a child; the tab's label is \a label. + Note the difference between the widget name (which you supply to + widget constructors and to setTabEnabled(), for example) and the tab + label. The name is internal to the program and invariant, whereas + the label is shown on-screen and may vary according to language and + other factors. + + If the tab's \a label contains an ampersand, the letter following + the ampersand is used as an accelerator for the tab, e.g. if the + label is "Bro&wse" then Alt+W becomes an accelerator which will + move the focus to this tab. + + If \a index is not specified, the tab is simply added. Otherwise + it is inserted at the specified position. + + If you call insertTab() after show(), the screen will flicker and the + user may be confused. + + \sa addTab() +*/ + +void QTabDialog::insertTab( QWidget * child, const QString &label, int index ) +{ + d->tw->insertTab( child, label, index ); +} + + +/*! \overload + + This version of the function shows the \a iconset as well as the \a + label on the tab of \a child. + */ +void QTabDialog::insertTab( QWidget *child, const QIconSet& iconset, const QString &label, int index) +{ + d->tw->insertTab( child, iconset, label, index ); +} + +/*! + \overload + + This is a lower-level method for inserting tabs, similar to the other + insertTab() method. It is useful if you are using setTabBar() to set a + QTabBar subclass with an overridden QTabBar::paint() function for a + subclass of QTab. + + The \a child is the widget to be placed on the new tab page. The \a + tab is the tab to display on the tab page -- normally this shows a + label or an icon that identifies the tab page. The \a index is the + position where this tab page should be inserted. + +*/ +void QTabDialog::insertTab( QWidget * child, QTab* tab, int index ) +{ + d->tw->insertTab( child, tab, index ); +} + +/*! + Replaces the QTabBar heading the dialog by the given tab bar, \a tb. + Note that this must be called \e before any tabs have been added, + or the behavior is undefined. + \sa tabBar() +*/ +void QTabDialog::setTabBar( QTabBar* tb ) +{ + d->tw->setTabBar( tb ); + setUpLayout(); +} + +/*! + Returns the currently set QTabBar. + \sa setTabBar() +*/ +QTabBar* QTabDialog::tabBar() const +{ + return d->tw->tabBar(); +} + +/*! Ensures that widget \a w is shown. This is mainly useful for accelerators. + + \warning If used carelessly, this function can easily surprise or + confuse the user. + + \sa QTabBar::setCurrentTab() +*/ + +void QTabDialog::showPage( QWidget * w ) +{ + d->tw->showPage( w ); +} + + +/*! \obsolete + Returns TRUE if the page with object name \a name is enabled and + FALSE if it is disabled. + + If \a name is 0 or not the name of any of the pages, isTabEnabled() + returns FALSE. + + \sa setTabEnabled(), QWidget::isEnabled() +*/ + +bool QTabDialog::isTabEnabled( const char* name ) const +{ + if ( !name ) + return FALSE; + QObjectList * l + = ((QTabDialog *)this)->queryList( "QWidget", name, FALSE, TRUE ); + if ( l && l->first() ) { + QWidget * w; + while( l->current() ) { + while( l->current() && !l->current()->isWidgetType() ) + l->next(); + w = (QWidget *)(l->current()); + if ( w ) { + bool enabled = d->tw->isTabEnabled( w ); + delete l; + return enabled; + } + } + } + delete l; + return FALSE; +} + + +/*!\obsolete + + Finds the page with object name \a name, enables/disables it + according to the value of \a enable and redraws the page's tab + appropriately. + + QTabDialog uses QWidget::setEnabled() internally, rather than keeping a + separate flag. + + Note that even a disabled tab/page may be visible. If the page is + already visible QTabDialog will not hide it; if all the pages + are disabled QTabDialog will show one of them. + + The object name is used (rather than the tab label) because the tab + text may not be invariant in multi-language applications. + + \sa isTabEnabled(), QWidget::setEnabled() +*/ + +void QTabDialog::setTabEnabled( const char* name, bool enable ) +{ + if ( !name ) + return; + QObjectList * l + = ((QTabDialog *)this)->queryList( "QWidget", name, FALSE, TRUE ); + if ( l && l->first() ) { + QObjectListIt it(*l); + QObject *o; + while( (o = it.current()) ) { + ++it; + if( o->isWidgetType() ) + d->tw->setTabEnabled( (QWidget*)o, enable ); + } + } + delete l; +} + + +/* ### SHOULD THIS BE HERE? + Adds an Apply button to the dialog. The button's text is set to \e + text (and defaults to "Apply"). + + The Apply button should apply the current settings in the dialog box + to the application, while keeping the dialog visible. + + When Apply is clicked, the applyButtonPressed() signal is emitted. + + If \a text is a + \link QString::operator!() null string\endlink, + no button is shown. + + \sa setCancelButton() setDefaultButton() applyButtonPressed() +*/ + + +/*! + Returns TRUE if the page \a w is enabled; otherwise returns FALSE. + + \sa setTabEnabled(), QWidget::isEnabled() +*/ + +bool QTabDialog::isTabEnabled( QWidget* w ) const +{ + return d->tw->isTabEnabled( w ); +} + +/*! + If \a enable is TRUE the page \a w is enabled; otherwise \a w is + disabled. The page's tab is redrawn appropriately. + + QTabWidget uses QWidget::setEnabled() internally, rather than keeping a + separate flag. + + Note that even a disabled tab and tab page may be visible. If the + page is already visible QTabWidget will not hide it; if all the + pages are disabled QTabWidget will show one of them. + + \sa isTabEnabled(), QWidget::setEnabled() +*/ + +void QTabDialog::setTabEnabled( QWidget* w, bool enable) +{ + d->tw->setTabEnabled( w, enable ); +} + + +/*! + Adds an Apply button to the dialog. The button's text is set to \a + text. + + The Apply button should apply the current settings in the dialog box + to the application while keeping the dialog visible. + + When Apply is clicked, the applyButtonPressed() signal is emitted. + + If \a text is a + \link QString::operator!() null string\endlink, + no button is shown. + + \sa setCancelButton() setDefaultButton() applyButtonPressed() +*/ +void QTabDialog::setApplyButton( const QString &text ) +{ + if ( !text && d->ab ) { + delete d->ab; + d->ab = 0; + setSizes(); + } else { + if ( !d->ab ) { + d->ab = new QPushButton( this, "apply settings" ); + connect( d->ab, SIGNAL(clicked()), + this, SIGNAL(applyButtonPressed()) ); + setUpLayout(); + } + d->ab->setText( text ); + setSizes(); + //d->ab->show(); + } +} + +/*! + \overload + + Adds an Apply button to the dialog. The button's text is set to + a localizable "Apply". + */ +void QTabDialog::setApplyButton() +{ + setApplyButton( tr("Apply") ); +} + + +/*! + Adds a Help button to the dialog. The button's text is set to \a + text. + + When Help is clicked, the helpButtonPressed() signal is emitted. + + If \a text is a + \link QString::operator!() null string\endlink, + no button is shown. + + \sa setApplyButton() setCancelButton() helpButtonPressed() +*/ + +void QTabDialog::setHelpButton( const QString &text ) +{ + if ( !text ) { + delete d->hb; + d->hb = 0; + setSizes(); + } else { + if ( !d->hb ) { + d->hb = new QPushButton( this, "give help" ); + connect( d->hb, SIGNAL(clicked()), + this, SIGNAL(helpButtonPressed()) ); + setUpLayout(); + } + d->hb->setText( text ); + setSizes(); + //d->hb->show(); + } +} + + +/*! + \overload + + Adds a Help button to the dialog. The button's text is set to + a localizable "Help". + */ +void QTabDialog::setHelpButton() +{ + setHelpButton( tr("Help") ); +} + +/*! + Adds a Defaults button to the dialog. The button's text is set to \a + text. + + The Defaults button should set the dialog (but not the application) + back to the application defaults. + + When Defaults is clicked, the defaultButtonPressed() signal is emitted. + + If \a text is a + \link QString::operator!() null string\endlink, + no button is shown. + + \sa setApplyButton() setCancelButton() defaultButtonPressed() +*/ + +void QTabDialog::setDefaultButton( const QString &text ) +{ + if ( !text ) { + delete d->db; + d->db = 0; + setSizes(); + } else { + if ( !d->db ) { + d->db = new QPushButton( this, "back to default" ); + connect( d->db, SIGNAL(clicked()), + this, SIGNAL(defaultButtonPressed()) ); + setUpLayout(); + } + d->db->setText( text ); + setSizes(); + //d->db->show(); + } +} + + +/*! + \overload + + Adds a Defaults button to the dialog. The button's text is set to + a localizable "Defaults". + */ +void QTabDialog::setDefaultButton() +{ + setDefaultButton( tr("Defaults") ); +} + +/*! + Adds a Cancel button to the dialog. The button's text is set to \a + text. + + The cancel button should always return the application to the state + it was in before the tab view popped up, or if the user has clicked + Apply, back to the state immediately after the last Apply. + + When Cancel is clicked, the cancelButtonPressed() signal is emitted. + The dialog is closed at the same time. + + If \a text is a + \link QString::operator!() null string\endlink, + no button is shown. + + \sa setApplyButton() setDefaultButton() cancelButtonPressed() +*/ + +void QTabDialog::setCancelButton( const QString &text ) +{ + if ( !text ) { + delete d->cb; + d->cb = 0; + setSizes(); + } else { + if ( !d->cb ) { + d->cb = new QPushButton( this, "cancel dialog" ); + connect( d->cb, SIGNAL(clicked()), + this, SIGNAL(cancelButtonPressed()) ); + connect( d->cb, SIGNAL(clicked()), + this, SLOT(reject()) ); + setUpLayout(); + } + d->cb->setText( text ); + setSizes(); + //d->cb->show(); + } +} + + +/*! + \overload + + Adds a Cancel button to the dialog. The button's text is set to + a localizable "Cancel". + */ + +void QTabDialog::setCancelButton() +{ + setCancelButton( tr("Cancel") ); +} + + +/*! Sets up the layout manager for the tab dialog. + + \sa setSizes() setApplyButton() setCancelButton() setDefaultButton() +*/ + +void QTabDialog::setUpLayout() +{ + // the next four are probably the same, really? + const int topMargin = 6; + const int leftMargin = 6; + const int rightMargin = 6; + const int bottomMargin = 6; + const int betweenButtonsMargin = 7; + const int aboveButtonsMargin = 8; + + delete d->tll; + d->tll = new QBoxLayout( this, QBoxLayout::Down ); + + // top margin + d->tll->addSpacing( topMargin ); + + QBoxLayout * tmp = new QHBoxLayout(); + d->tll->addLayout( tmp, 1 ); + tmp->addSpacing( leftMargin ); + tmp->addWidget( d->tw, 1); + tmp->addSpacing( rightMargin + 2 ); + + d->tll->addSpacing( aboveButtonsMargin + 2 ); + QBoxLayout * buttonRow = new QBoxLayout(QBoxLayout::RightToLeft); + d->tll->addLayout( buttonRow, 0 ); + d->tll->addSpacing( bottomMargin ); + + buttonRow->addSpacing( rightMargin ); + if ( d->cb ) { + buttonRow->addWidget( d->cb, 0 ); + buttonRow->addSpacing( betweenButtonsMargin ); + d->cb->raise(); + } + + if ( d->ab ) { + buttonRow->addWidget( d->ab, 0 ); + buttonRow->addSpacing( betweenButtonsMargin ); + d->ab->raise(); + } + + if ( d->db ) { + buttonRow->addWidget( d->db, 0 ); + buttonRow->addSpacing( betweenButtonsMargin ); + d->db->raise(); + } + + if ( d->hb ) { + buttonRow->addWidget( d->hb, 0 ); + buttonRow->addSpacing( betweenButtonsMargin ); + d->hb->raise(); + } + + if ( d->ok ) { + buttonRow->addWidget( d->ok, 0 ); + buttonRow->addSpacing( betweenButtonsMargin ); + d->ok->raise(); + } + + // add one custom widget here + buttonRow->addStretch( 1 ); + // add another custom widget here + + d->tll->activate(); +} + + +/*! Sets up the minimum and maximum sizes for each child widget. + + \sa setUpLayout() setFont() +*/ + +void QTabDialog::setSizes() +{ + // compute largest button size + QSize s( 0, 0 ); + int bw = s.width(); + int bh = s.height(); + + if ( d->ok ) { + s = d->ok->sizeHint(); + if ( s.width() > bw ) + bw = s.width(); + if ( s.height() > bh ) + bh = s.height(); + } + + if ( d->ab ) { + s = d->ab->sizeHint(); + if ( s.width() > bw ) + bw = s.width(); + if ( s.height() > bh ) + bh = s.height(); + } + + if ( d->db ) { + s = d->db->sizeHint(); + if ( s.width() > bw ) + bw = s.width(); + if ( s.height() > bh ) + bh = s.height(); + } + + if ( d->hb ) { + s = d->hb->sizeHint(); + if ( s.width() > bw ) + bw = s.width(); + if ( s.height() > bh ) + bh = s.height(); + } + + if ( d->cb ) { + s = d->cb->sizeHint(); + if ( s.width() > bw ) + bw = s.width(); + if ( s.height() > bh ) + bh = s.height(); + } + + // and set all the buttons to that size + if ( d->ok ) + d->ok->setFixedSize( bw, bh ); + if ( d->ab ) + d->ab->setFixedSize( bw, bh ); + if ( d->db ) + d->db->setFixedSize( bw, bh ); + if ( d->hb ) + d->hb->setFixedSize( bw, bh ); + if ( d->cb ) + d->cb->setFixedSize( bw, bh ); + + // fiddle the tab chain so the buttons are in their natural order + QWidget * w = d->ok; + + if ( d->hb ) { + if ( w ) + setTabOrder( w, d->hb ); + w = d->hb; + } + if ( d->db ) { + if ( w ) + setTabOrder( w, d->db ); + w = d->db; + } + if ( d->ab ) { + if ( w ) + setTabOrder( w, d->ab ); + w = d->ab; + } + if ( d->cb ) { + if ( w ) + setTabOrder( w, d->cb ); + w = d->cb; + } + setTabOrder( w, d->tw ); +} + +/*!\reimp +*/ +void QTabDialog::resizeEvent( QResizeEvent * e ) +{ + QDialog::resizeEvent( e ); +} + + +/*!\reimp +*/ +void QTabDialog::paintEvent( QPaintEvent * ) +{ +} + + +/*! + Adds an OK button to the dialog and sets the button's text to \a text. + + When the OK button is clicked, the applyButtonPressed() signal is emitted, + and the current settings in the dialog box should be applied to + the application. The dialog then closes. + + If \a text is a + \link QString::operator!() null string\endlink, + no button is shown. + + \sa setCancelButton() setDefaultButton() applyButtonPressed() +*/ + +void QTabDialog::setOkButton( const QString &text ) +{ + if ( !text ) { + delete d->ok; + d->ok = 0; + setSizes(); + } else { + if ( !d->ok ) { + d->ok = new QPushButton( this, "ok" ); + connect( d->ok, SIGNAL(clicked()), + this, SIGNAL(applyButtonPressed()) ); + setUpLayout(); + } + d->ok->setText( text ); + setSizes(); + //d->ok->show(); + } +} +/*! + \overload + + Adds an OK button to the dialog. The button's text is set to + a localizable "OK". + */ + +void QTabDialog::setOkButton() +{ + setOkButton( tr("OK") ); +} + + +/* + \overload + Old version of setOkButton(), provided for backward compatibility. +*/ +void QTabDialog::setOKButton( const QString &text ) +{ + // Ugly workaround for original "OK" default argument + QString newText( text ); + if ( text.isNull() ) + newText = QString::fromLatin1( "OK" ); + setOkButton( newText ); +} + + +/*! Returns the text in the tab for page \a w. +*/ + +QString QTabDialog::tabLabel( QWidget * w ) +{ + return d->tw->tabLabel( w ); +} + + +/*! \reimp +*/ +void QTabDialog::styleChange( QStyle& s ) +{ + QDialog::styleChange( s ); + setSizes(); +} + + +/*! Returns a pointer to the page currently being displayed by the +tab dialog. The tab dialog does its best to make sure that this value +is never 0 (but if you try hard enough, it can be). +*/ + +QWidget * QTabDialog::currentPage() const +{ + return d->tw->currentPage(); +} + +/*! + \overload + Defines a new \a label for the tab of page \a w + */ +void QTabDialog::changeTab( QWidget *w, const QString &label) +{ + d->tw->changeTab( w, label ); +} + +/*! + Changes tab page \a w's iconset to \a iconset and label to \a label. + + */ +void QTabDialog::changeTab( QWidget *w, const QIconSet& iconset, const QString &label) +{ + d->tw->changeTab( w, iconset, label ); +} + +/*! Removes page \a w from this stack of widgets. Does not + delete \a w. + \sa showPage(), QTabWidget::removePage(), QWidgetStack::removeWidget() +*/ +void QTabDialog::removePage( QWidget * w ) +{ + d->tw->removePage( w ); +} + +#endif diff --git a/src/dialogs/qtabdialog.h b/src/dialogs/qtabdialog.h new file mode 100644 index 0000000..3ee83fd --- /dev/null +++ b/src/dialogs/qtabdialog.h @@ -0,0 +1,146 @@ +/**************************************************************************** +** +** Definition of QTabDialog class +** +** Created : 960825 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QTABDIALOG_H +#define QTABDIALOG_H + +#ifndef QT_H +#include "qdialog.h" +#include "qiconset.h" +#endif // QT_H + +#ifndef QT_NO_TABDIALOG + +class QTabBar; +class QTab; +class QTabDialogPrivate; + +class Q_EXPORT QTabDialog : public QDialog +{ + Q_OBJECT +public: + QTabDialog( QWidget* parent=0, const char* name=0, bool modal=FALSE, + WFlags f=0 ); + ~QTabDialog(); + + void show(); + void setFont( const QFont & font ); + + void addTab( QWidget *, const QString &); + void addTab( QWidget *child, const QIconSet& iconset, const QString &label); + void addTab( QWidget *, QTab* ); + + void insertTab( QWidget *, const QString &, int index = -1); + void insertTab( QWidget *child, const QIconSet& iconset, const QString &label, int index = -1); + void insertTab( QWidget *, QTab*, int index = -1 ); + + void changeTab( QWidget *, const QString &); + void changeTab( QWidget *child, const QIconSet& iconset, const QString &label); + + bool isTabEnabled( QWidget * ) const; + void setTabEnabled( QWidget *, bool ); + bool isTabEnabled( const char* ) const; // compatibility + void setTabEnabled( const char*, bool ); // compatibility + + void showPage( QWidget * ); + void removePage( QWidget * ); + QString tabLabel( QWidget * ); + + QWidget * currentPage() const; + + void setDefaultButton( const QString &text ); + void setDefaultButton(); + bool hasDefaultButton() const; + + void setHelpButton( const QString &text ); + void setHelpButton(); + bool hasHelpButton() const; + + void setCancelButton( const QString &text ); + void setCancelButton(); + bool hasCancelButton() const; + + void setApplyButton( const QString &text ); + void setApplyButton(); + bool hasApplyButton() const; + +#ifndef Q_QDOC + void setOKButton( const QString &text = QString::null ); +#endif + void setOkButton( const QString &text ); + void setOkButton(); + bool hasOkButton() const; + +protected: + void paintEvent( QPaintEvent * ); + void resizeEvent( QResizeEvent * ); + void styleChange( QStyle& ); + void setTabBar( QTabBar* ); + QTabBar* tabBar() const; + +signals: + void aboutToShow(); + + void applyButtonPressed(); + void cancelButtonPressed(); + void defaultButtonPressed(); + void helpButtonPressed(); + + void currentChanged( QWidget * ); + void selected( const QString& ); // obsolete + +private slots: + void showTab( int i ); + +private: + void setSizes(); + void setUpLayout(); + + QTabDialogPrivate *d; +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QTabDialog( const QTabDialog & ); + QTabDialog& operator=( const QTabDialog & ); +#endif +}; + +#endif // QT_NO_TABDIALOG + +#endif // QTABDIALOG_H diff --git a/src/dialogs/qwizard.cpp b/src/dialogs/qwizard.cpp new file mode 100644 index 0000000..32c386a --- /dev/null +++ b/src/dialogs/qwizard.cpp @@ -0,0 +1,917 @@ +/**************************************************************************** +** +** Implementation of QWizard class. +** +** Created : 990124 +** +** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qwizard.h" + +#ifndef QT_NO_WIZARD + +#include "qlayout.h" +#include "qpushbutton.h" +#include "qcursor.h" +#include "qlabel.h" +#include "qwidgetstack.h" +#include "qapplication.h" +#include "qptrlist.h" +#include "qpainter.h" +#include "qaccel.h" + +/*! \file wizard/wizard.cpp */ +/*! \file wizard/wizard.h */ + +/*! + \class QWizard qwizard.h + \brief The QWizard class provides a framework for wizard dialogs. + + \ingroup abstractwidgets + \ingroup organizers + \ingroup dialogs + \mainclass + + A wizard is a special type of input dialog that consists of a + sequence of dialog pages. A wizard's purpose is to walk the user + through a process step by step. Wizards are useful for complex or + infrequently occurring tasks that people may find difficult to + learn or do. + + QWizard provides page titles and displays Next, Back, Finish, + Cancel, and Help push buttons, as appropriate to the current + position in the page sequence. These buttons can be + enabled/disabled using setBackEnabled(), setNextEnabled(), + setFinishEnabled() and setHelpEnabled(). + + Create and populate dialog pages that inherit from QWidget and add + them to the wizard using addPage(). Use insertPage() to add a + dialog page at a certain position in the page sequence. Use + removePage() to remove a page from the page sequence. + + Use currentPage() to retrieve a pointer to the currently displayed + page. page() returns a pointer to the page at a certain position + in the page sequence. + + Use pageCount() to retrieve the total number of pages in the page + sequence. indexOf() will return the index of a page in the page + sequence. + + QWizard provides functionality to mark pages as appropriate (or + not) in the current context with setAppropriate(). The idea is + that a page may be irrelevant and should be skipped depending on + the data entered by the user on a preceding page. + + It is generally considered good design to provide a greater number + of simple pages with fewer choices rather than a smaller number of + complex pages. + + Example code is available here: \l wizard/wizard.cpp \l wizard/wizard.h + + \img qwizard.png A QWizard page + \caption A QWizard page + +*/ + + +class QWizardPrivate +{ +public: + struct Page { + Page( QWidget * widget, const QString & title ): + w( widget ), t( title ), + backEnabled( TRUE ), nextEnabled( TRUE ), finishEnabled( FALSE ), + helpEnabled( TRUE ), + appropriate( TRUE ) + {} + QWidget * w; + QString t; + bool backEnabled; + bool nextEnabled; + bool finishEnabled; + bool helpEnabled; + bool appropriate; + }; + + QVBoxLayout * v; + Page * current; + QWidgetStack * ws; + QPtrList<Page> pages; + QLabel * title; + QPushButton * backButton; + QPushButton * nextButton; + QPushButton * finishButton; + QPushButton * cancelButton; + QPushButton * helpButton; + + QFrame * hbar1, * hbar2; + +#ifndef QT_NO_ACCEL + QAccel * accel; + int backAccel; + int nextAccel; +#endif + + Page * page( const QWidget * w ) + { + if ( !w ) + return 0; + int i = pages.count(); + while( --i >= 0 && pages.at( i ) && pages.at( i )->w != w ) { } + return i >= 0 ? pages.at( i ) : 0; + } + +}; + + +/*! + Constructs an empty wizard dialog. The \a parent, \a name, \a + modal and \a f arguments are passed to the QDialog constructor. +*/ + +QWizard::QWizard( QWidget *parent, const char *name, bool modal, + WFlags f ) + : QDialog( parent, name, modal, f ) +{ + d = new QWizardPrivate(); + d->current = 0; // not quite true, but... + d->ws = new QWidgetStack( this, "qt_widgetstack" ); + d->pages.setAutoDelete( TRUE ); + d->title = new QLabel( this, "title label" ); + + // create in nice tab order + d->nextButton = new QPushButton( this, "next" ); + d->finishButton = new QPushButton( this, "finish" ); + d->helpButton = new QPushButton( this, "help" ); + d->backButton = new QPushButton( this, "back" ); + d->cancelButton = new QPushButton( this, "cancel" ); + + d->ws->installEventFilter( this ); + + d->v = 0; + d->hbar1 = 0; + d->hbar2 = 0; + + d->cancelButton->setText( tr( "&Cancel" ) ); + d->backButton->setText( tr( "< &Back" ) ); + d->nextButton->setText( tr( "&Next >" ) ); + d->finishButton->setText( tr( "&Finish" ) ); + d->helpButton->setText( tr( "&Help" ) ); + + d->nextButton->setDefault( TRUE ); + + connect( d->backButton, SIGNAL(clicked()), + this, SLOT(back()) ); + connect( d->nextButton, SIGNAL(clicked()), + this, SLOT(next()) ); + connect( d->finishButton, SIGNAL(clicked()), + this, SLOT(accept()) ); + connect( d->cancelButton, SIGNAL(clicked()), + this, SLOT(reject()) ); + connect( d->helpButton, SIGNAL(clicked()), + this, SLOT(help()) ); + +#ifndef QT_NO_ACCEL + d->accel = new QAccel( this, "arrow-key accel" ); + d->backAccel = d->accel->insertItem( Qt::ALT + Qt::Key_Left ); + d->accel->connectItem( d->backAccel, this, SLOT(back()) ); + d->nextAccel = d->accel->insertItem( Qt::ALT + Qt::Key_Right ); + d->accel->connectItem( d->nextAccel, this, SLOT(next()) ); +#endif +} + + +/*! + Destroys the object and frees any allocated resources, including + all pages and controllers. +*/ + +QWizard::~QWizard() +{ + delete d; +} + + +/*! + \reimp +*/ + +void QWizard::show() +{ + if ( !d->current ) { + // No page yet + if ( pageCount() > 0 ) + showPage( d->pages.at( 0 )->w ); + else + showPage( 0 ); + } + + QDialog::show(); +} + + +/*! + \reimp +*/ + +void QWizard::setFont( const QFont & font ) +{ + QApplication::postEvent( this, new QEvent( QEvent::LayoutHint ) ); + QDialog::setFont( font ); +} + + +/*! + Adds \a page to the end of the page sequence, with the title, \a + title. +*/ + +void QWizard::addPage( QWidget * page, const QString & title ) +{ + if ( !page ) + return; + if ( d->page( page ) ) { +#if defined(QT_CHECK_STATE) + qWarning( "QWizard::addPage(): already added %s/%s to %s/%s", + page->className(), page->name(), + className(), name() ); +#endif + return; + } + int i = d->pages.count(); + + if( i > 0 ) + d->pages.at( i - 1 )->nextEnabled = TRUE; + + QWizardPrivate::Page * p = new QWizardPrivate::Page( page, title ); + p->backEnabled = ( i > 0 ); + d->ws->addWidget( page, i ); + d->pages.append( p ); +} + +/*! + Inserts \a page at position \a index into the page sequence, with + title \a title. If \a index is -1, the page will be appended to + the end of the wizard's page sequence. +*/ + +void QWizard::insertPage( QWidget * page, const QString & title, int index ) +{ + if ( !page ) + return; + if ( d->page( page ) ) { +#if defined(QT_CHECK_STATE) + qWarning( "QWizard::insertPage(): already added %s/%s to %s/%s", + page->className(), page->name(), + className(), name() ); +#endif + return; + } + + if ( index < 0 || index > (int)d->pages.count() ) + index = d->pages.count(); + + if( index > 0 && ( index == (int)d->pages.count() ) ) + d->pages.at( index - 1 )->nextEnabled = TRUE; + + QWizardPrivate::Page * p = new QWizardPrivate::Page( page, title ); + p->backEnabled = ( index > 0 ); + p->nextEnabled = ( index < (int)d->pages.count() ); + + d->ws->addWidget( page, index ); + d->pages.insert( index, p ); +} + +/*! + \fn void QWizard::selected(const QString&) + + This signal is emitted when the current page changes. The + parameter contains the title of the selected page. +*/ + + +/*! + Makes \a page the current page and emits the selected() signal. + + This virtual function is called whenever a different page is to + be shown, including the first time the QWizard is shown. + By reimplementing it (and calling QWizard::showPage()), + you can prepare each page prior to it being shown. +*/ + +void QWizard::showPage( QWidget * page ) +{ + QWizardPrivate::Page * p = d->page( page ); + if ( p ) { + int i; + for( i = 0; i < (int)d->pages.count() && d->pages.at( i ) != p; i++ ); + bool notFirst( FALSE ); + + if( i ) { + i--; + while( ( i >= 0 ) && !notFirst ) { + notFirst |= appropriate( d->pages.at( i )->w ); + i--; + } + } + setBackEnabled( notFirst ); + setNextEnabled( TRUE ); + d->ws->raiseWidget( page ); + d->current = p; + } + + layOut(); + updateButtons(); + emit selected( p ? p->t : QString::null ); +} + + +/*! + Returns the number of pages in the wizard. +*/ + +int QWizard::pageCount() const +{ + return d->pages.count(); +} + +/*! + Returns the position of page \a page. If the page is not part of + the wizard -1 is returned. +*/ + +int QWizard::indexOf( QWidget* page ) const +{ + QWizardPrivate::Page * p = d->page( page ); + if ( !p ) return -1; + + return d->pages.find( p ); +} + +/*! + Called when the user clicks the Back button; this function shows + the preceding relevant page in the sequence. + + \sa appropriate() +*/ +void QWizard::back() +{ + int i = 0; + + while( i < (int)d->pages.count() && d->pages.at( i ) && + d->current && d->pages.at( i )->w != d->current->w ) + i++; + + i--; + while( i >= 0 && ( !d->pages.at( i ) || !appropriate( d->pages.at( i )->w ) ) ) + i--; + + if( i >= 0 ) + if( d->pages.at( i ) ) + showPage( d->pages.at( i )->w ); +} + + +/*! + Called when the user clicks the Next button, this function shows + the next relevant page in the sequence. + + \sa appropriate() +*/ +void QWizard::next() +{ + int i = 0; + while( i < (int)d->pages.count() && d->pages.at( i ) && + d->current && d->pages.at( i )->w != d->current->w ) + i++; + i++; + while( i <= (int)d->pages.count()-1 && + ( !d->pages.at( i ) || !appropriate( d->pages.at( i )->w ) ) ) + i++; + // if we fell of the end of the world, step back + while ( i > 0 && (i >= (int)d->pages.count() || !d->pages.at( i ) ) ) + i--; + if ( d->pages.at( i ) ) + showPage( d->pages.at( i )->w ); +} + + +/*! + \fn void QWizard::helpClicked() + + This signal is emitted when the user clicks on the Help button. +*/ + +/*! + Called when the user clicks the Help button, this function emits + the helpClicked() signal. +*/ + +void QWizard::help() +{ + QWidget * page = d->ws->visibleWidget(); + if ( !page ) + return; + +#if 0 + QWizardPage *wpage = ::qt_cast<QWizardPage*>(page); + if ( wpage ) + emit wpage->helpClicked(); +#endif + emit helpClicked(); +} + + +void QWizard::setBackEnabled( bool enable ) +{ + d->backButton->setEnabled( enable ); +#ifndef QT_NO_ACCEL + d->accel->setItemEnabled( d->backAccel, enable ); +#endif +} + + +void QWizard::setNextEnabled( bool enable ) +{ + d->nextButton->setEnabled( enable ); +#ifndef QT_NO_ACCEL + d->accel->setItemEnabled( d->nextAccel, enable ); +#endif +} + + +void QWizard::setHelpEnabled( bool enable ) +{ + d->helpButton->setEnabled( enable ); +} + + +/*! + \fn void QWizard::setFinish( QWidget *, bool ) + \obsolete + + Use setFinishEnabled instead +*/ + +/*! + If \a enable is TRUE, page \a page has a Back button; otherwise \a + page has no Back button. By default all pages have this button. +*/ +void QWizard::setBackEnabled( QWidget * page, bool enable ) +{ + QWizardPrivate::Page * p = d->page( page ); + if ( !p ) + return; + + p->backEnabled = enable; + updateButtons(); +} + + +/*! + If \a enable is TRUE, page \a page has a Next button; otherwise + the Next button on \a page is disabled. By default all pages have + this button. +*/ + +void QWizard::setNextEnabled( QWidget * page, bool enable ) +{ + QWizardPrivate::Page * p = d->page( page ); + if ( !p ) + return; + + p->nextEnabled = enable; + updateButtons(); +} + + +/*! + If \a enable is TRUE, page \a page has a Finish button; otherwise + \a page has no Finish button. By default \e no page has this + button. +*/ +void QWizard::setFinishEnabled( QWidget * page, bool enable ) +{ + QWizardPrivate::Page * p = d->page( page ); + if ( !p ) + return; + + p->finishEnabled = enable; + updateButtons(); +} + + +/*! + If \a enable is TRUE, page \a page has a Help button; otherwise \a + page has no Help button. By default all pages have this button. +*/ +void QWizard::setHelpEnabled( QWidget * page, bool enable ) +{ + QWizardPrivate::Page * p = d->page( page ); + if ( !p ) + return; + + p->helpEnabled = enable; + updateButtons(); +} + + +/*! + Called when the Next button is clicked; this virtual function + returns TRUE if \a page is relevant for display in the current + context; otherwise it is ignored by QWizard and returns FALSE. The + default implementation returns the value set using + setAppropriate(). The ultimate default is TRUE. + + \warning The last page of the wizard will be displayed if no page + is relevant in the current context. +*/ + +bool QWizard::appropriate( QWidget * page ) const +{ + QWizardPrivate::Page * p = d->page( page ); + return p ? p->appropriate : TRUE; +} + + +/*! + If \a appropriate is TRUE then page \a page is considered relevant + in the current context and should be displayed in the page + sequence; otherwise \a page should not be displayed in the page + sequence. + + \sa appropriate() +*/ +void QWizard::setAppropriate( QWidget * page, bool appropriate ) +{ + QWizardPrivate::Page * p = d->page( page ); + if ( p ) + p->appropriate = appropriate; +} + + +void QWizard::updateButtons() +{ + if ( !d->current ) + return; + + int i; + for( i = 0; i < (int)d->pages.count() && d->pages.at( i ) != d->current; i++ ); + bool notFirst( FALSE ); + if( i ) { + i--; + while( ( i >= 0 ) && !notFirst ) { + notFirst |= appropriate( d->pages.at( i )->w ); + i--; + } + } + setBackEnabled( d->current->backEnabled && notFirst ); + setNextEnabled( d->current->nextEnabled ); + d->finishButton->setEnabled( d->current->finishEnabled ); + d->helpButton->setEnabled( d->current->helpEnabled ); + + if ( ( d->current->finishEnabled && !d->finishButton->isVisible() ) || + ( d->current->backEnabled && !d->backButton->isVisible() ) || + ( d->current->nextEnabled && !d->nextButton->isVisible() ) || + ( d->current->helpEnabled && !d->helpButton->isVisible() ) ) + layOut(); +} + + +/*! + Returns a pointer to the current page in the sequence. Although + the wizard does its best to make sure that this value is never 0, + it can be if you try hard enough. +*/ + +QWidget * QWizard::currentPage() const +{ + return d->ws->visibleWidget(); +} + + +/*! + Returns the title of page \a page. +*/ + +QString QWizard::title( QWidget * page ) const +{ + QWizardPrivate::Page * p = d->page( page ); + return p ? p->t : QString::null; +} + +/*! + Sets the title for page \a page to \a title. +*/ + +void QWizard::setTitle( QWidget *page, const QString &title ) +{ + QWizardPrivate::Page * p = d->page( page ); + if ( p ) + p->t = title; + if ( page == currentPage() ) + d->title->setText( title ); +} + +/*! + \property QWizard::titleFont + \brief the font used for page titles + + The default is QApplication::font(). +*/ +QFont QWizard::titleFont() const +{ + return d->title->font(); +} + +void QWizard::setTitleFont( const QFont & font ) +{ + d->title->setFont( font ); +} + + +/*! + Returns a pointer to the dialog's Back button + + By default, this button is connected to the back() slot, which is + virtual so you can reimplement it in a QWizard subclass. Use + setBackEnabled() to enable/disable this button. +*/ +QPushButton * QWizard::backButton() const +{ + return d->backButton; +} + + +/*! + Returns a pointer to the dialog's Next button + + By default, this button is connected to the next() slot, which is + virtual so you can reimplement it in a QWizard subclass. Use + setNextEnabled() to enable/disable this button. +*/ +QPushButton * QWizard::nextButton() const +{ + return d->nextButton; +} + + +/*! + Returns a pointer to the dialog's Finish button + + By default, this button is connected to the QDialog::accept() + slot, which is virtual so you can reimplement it in a QWizard + subclass. Use setFinishEnabled() to enable/disable this button. +*/ +QPushButton * QWizard::finishButton() const +{ + return d->finishButton; +} + + +/*! + Returns a pointer to the dialog's Cancel button + + By default, this button is connected to the QDialog::reject() + slot, which is virtual so you can reimplement it in a QWizard + subclass. +*/ +QPushButton * QWizard::cancelButton() const +{ + return d->cancelButton; +} + + +/*! + Returns a pointer to the dialog's Help button + + By default, this button is connected to the help() slot, which is + virtual so you can reimplement it in a QWizard subclass. Use + setHelpEnabled() to enable/disable this button. +*/ +QPushButton * QWizard::helpButton() const +{ + return d->helpButton; +} + + +/*! + This virtual function is responsible for adding the buttons below + the bottom divider. + + \a layout is the horizontal layout of the entire wizard. +*/ + +void QWizard::layOutButtonRow( QHBoxLayout * layout ) +{ + bool hasHelp = FALSE; + bool hasEarlyFinish = FALSE; + + int i = d->pages.count() - 2; + while ( !hasEarlyFinish && i >= 0 ) { + if ( d->pages.at( i ) && d->pages.at( i )->finishEnabled ) + hasEarlyFinish = TRUE; + i--; + } + i = 0; + while ( !hasHelp && i < (int)d->pages.count() ) { + if ( d->pages.at( i ) && d->pages.at( i )->helpEnabled ) + hasHelp = TRUE; + i++; + } + + QBoxLayout * h = new QBoxLayout( QBoxLayout::LeftToRight ); + layout->addLayout( h ); + + if ( hasHelp ) + h->addWidget( d->helpButton ); + else + d->helpButton->hide(); + + h->addStretch( 42 ); + + h->addWidget( d->backButton ); + + h->addSpacing( 6 ); + + if (d->current == d->pages.at( d->pages.count()-1 )) + hasEarlyFinish = FALSE; + + if ( hasEarlyFinish ) { + d->nextButton->show(); + d->finishButton->show(); + h->addWidget( d->nextButton ); + h->addSpacing( 12 ); + h->addWidget( d->finishButton ); + } else if ( d->pages.count() == 0 || + d->current->finishEnabled || + d->current == d->pages.at( d->pages.count()-1 ) ) { + d->nextButton->hide(); + d->finishButton->show(); + h->addWidget( d->finishButton ); + } else { + d->nextButton->show(); + d->finishButton->hide(); + h->addWidget( d->nextButton ); + } + + // if last page is disabled - show finished btn. at lastpage-1 + i = d->pages.count()-1; + if ( i >= 0 && !appropriate( d->pages.at( i )->w ) && + d->current == d->pages.at( d->pages.count()-2 ) ) { + d->nextButton->hide(); + d->finishButton->show(); + h->addWidget( d->finishButton ); + } + + h->addSpacing( 12 ); + h->addWidget( d->cancelButton ); +} + + +/*! + This virtual function is responsible for laying out the title row. + + \a layout is the horizontal layout for the wizard, and \a + title is the title for this page. This function is called every + time \a title changes. +*/ + +void QWizard::layOutTitleRow( QHBoxLayout * layout, const QString & title ) +{ + d->title->setText( title ); + layout->addWidget( d->title, 10 ); +} + + +/* + +*/ + +void QWizard::layOut() +{ + delete d->v; + d->v = new QVBoxLayout( this, 6, 0, "top-level layout" ); + + QHBoxLayout * l; + l = new QHBoxLayout( 6 ); + d->v->addLayout( l, 0 ); + layOutTitleRow( l, d->current ? d->current->t : QString::null ); + + if ( ! d->hbar1 ) { + d->hbar1 = new QFrame( this, "<hr>", 0 ); + d->hbar1->setFrameStyle( QFrame::Sunken + QFrame::HLine ); + d->hbar1->setFixedHeight( 12 ); + } + + d->v->addWidget( d->hbar1 ); + + d->v->addWidget( d->ws, 10 ); + + if ( ! d->hbar2 ) { + d->hbar2 = new QFrame( this, "<hr>", 0 ); + d->hbar2->setFrameStyle( QFrame::Sunken + QFrame::HLine ); + d->hbar2->setFixedHeight( 12 ); + } + d->v->addWidget( d->hbar2 ); + + l = new QHBoxLayout( 6 ); + d->v->addLayout( l ); + layOutButtonRow( l ); + d->v->activate(); +} + + +/*! + \reimp +*/ + +bool QWizard::eventFilter( QObject * o, QEvent * e ) +{ + if ( o == d->ws && e && e->type() == QEvent::ChildRemoved ) { + QChildEvent * c = (QChildEvent*)e; + if ( c->child() && c->child()->isWidgetType() ) + removePage( (QWidget *)c->child() ); + } + return QDialog::eventFilter( o, e ); +} + + +/*! + Removes \a page from the page sequence but does not delete the + page. If \a page is currently being displayed, QWizard will + display the page that precedes it, or the first page if this was + the first page. +*/ + +void QWizard::removePage( QWidget * page ) +{ + if ( !page ) + return; + + int i = d->pages.count(); + QWidget* cp = currentPage(); + while( --i >= 0 && d->pages.at( i ) && d->pages.at( i )->w != page ) { } + if ( i < 0 ) + return; + QWizardPrivate::Page * p = d->pages.at( i ); + d->pages.removeRef( p ); + d->ws->removeWidget( page ); + + if( cp == page ) { + i--; + if( i < 0 ) + i = 0; + if ( pageCount() > 0 ) + showPage( QWizard::page( i ) ); + } +} + + +/*! + Returns a pointer to the page at position \a index in the + sequence, or 0 if \a index is out of range. The first page has + index 0. +*/ + +QWidget* QWizard::page( int index ) const +{ + if ( index >= pageCount() || index < 0 ) + return 0; + + return d->pages.at( index )->w; +} + +#endif // QT_NO_WIZARD diff --git a/src/dialogs/qwizard.h b/src/dialogs/qwizard.h new file mode 100644 index 0000000..537b843 --- /dev/null +++ b/src/dialogs/qwizard.h @@ -0,0 +1,142 @@ +/**************************************************************************** +** +** Definition of the QWizard class. +** +** Created : 990101 +** +** Copyright (C) 1999-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the dialogs module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** Please review the following information to ensure GNU General +** Public Licensing requirements will be met: +** http://trolltech.com/products/qt/licenses/licensing/opensource/. +** If you are unsure which license is appropriate for your use, please +** review the following information: +** http://trolltech.com/products/qt/licenses/licensing/licensingoverview +** or contact the sales department at sales@trolltech.com. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QWIZARDDIALOG_H +#define QWIZARDDIALOG_H + + +#ifndef QT_H +#include "qdialog.h" +#endif // QT_H + +#ifndef QT_NO_WIZARD + +class QHBoxLayout; +class QWizardPrivate; + +class Q_EXPORT QWizard : public QDialog +{ + Q_OBJECT + Q_PROPERTY( QFont titleFont READ titleFont WRITE setTitleFont ) + +public: + QWizard( QWidget* parent=0, const char* name=0, bool modal=FALSE, + WFlags f=0 ); + ~QWizard(); + + void show(); + + void setFont( const QFont & font ); + + virtual void addPage( QWidget *, const QString & ); + virtual void insertPage( QWidget*, const QString&, int ); + virtual void removePage( QWidget * ); + + QString title( QWidget * ) const; + void setTitle( QWidget *, const QString & ); + QFont titleFont() const; + void setTitleFont( const QFont & ); + + virtual void showPage( QWidget * ); + + QWidget * currentPage() const; + + QWidget* page( int ) const; + int pageCount() const; + int indexOf( QWidget* ) const; + + virtual bool appropriate( QWidget * ) const; + virtual void setAppropriate( QWidget *, bool ); + + QPushButton * backButton() const; + QPushButton * nextButton() const; + QPushButton * finishButton() const; + QPushButton * cancelButton() const; + QPushButton * helpButton() const; + + bool eventFilter( QObject *, QEvent * ); + +public slots: + virtual void setBackEnabled( QWidget *, bool ); + virtual void setNextEnabled( QWidget *, bool ); + virtual void setFinishEnabled( QWidget *, bool ); + + virtual void setHelpEnabled( QWidget *, bool ); + + // obsolete + virtual void setFinish( QWidget *, bool ) {} + +protected slots: + virtual void back(); + virtual void next(); + virtual void help(); + +signals: + void helpClicked(); + void selected( const QString& ); + +protected: + virtual void layOutButtonRow( QHBoxLayout * ); + virtual void layOutTitleRow( QHBoxLayout *, const QString & ); + +private: + void setBackEnabled( bool ); + void setNextEnabled( bool ); + + void setHelpEnabled( bool ); + + void setNextPage( QWidget * ); + + void updateButtons(); + + void layOut(); + + QWizardPrivate *d; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QWizard( const QWizard & ); + QWizard& operator=( const QWizard & ); +#endif +}; + +#endif // QT_NO_WIZARD + +#endif // QWIZARD_H |