/************************** * * * * * * * * * * * * *************************** Copyright (c) 1999-2005 Ryan Bobko ryan@ostrich-emulators.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. ************************** * * * * * * * * * * * * ***************************/ #include "qhacclineedits.h" #include "qhaccutils.h" #include "qhacclineedits.moc" #include #include #include #include #include using namespace std; /* * * * * * * * * * * * * */ /* * * * LINEEDIT * * * * */ /* * * * * * * * * * * * * */ //needed to make this because I need a focusout event QHaccLineEdit::QHaccLineEdit( QWidget * p, const char * n ) : QLineEdit( p, n ){ dosel=true; } QHaccLineEdit::QHaccLineEdit( const QString& c, QWidget * p, const char * n ) : QLineEdit( c, p, n ){ dosel=true; } QHaccLineEdit::~QHaccLineEdit(){} void QHaccLineEdit::focusInEvent( QFocusEvent * e ){ if( QLineEdit::text()==empty || dosel ) selectAll(); QLineEdit::focusInEvent( e ); emit gainedFocus(); } void QHaccLineEdit::focusOutEvent( QFocusEvent * e ){ deselect(); QLineEdit::focusOutEvent( e ); } void QHaccLineEdit::setText( const QString& s ){ QLineEdit::setText( ( s.isEmpty() ? empty : s ) ); } void QHaccLineEdit::setEmptyText( const QString& s ){ empty=s; if( QLineEdit::text().isEmpty() ) QLineEdit::setText( s ); } QString QHaccLineEdit::text() const { QString ret=QLineEdit::text(); if( ret==empty ) return QString(); else return ret; } void QHaccLineEdit::selectAllOnFocus( bool b ){ dosel=b; } /* * * * * * * * * * * * * */ /* * * * CHOICEEDIT * * * */ /* * * * * * * * * * * * * */ //similar to a dropbox, but without the drop part QHaccChoiceEdit::QHaccChoiceEdit( bool allow, QWidget * w, const char * n ) : QHaccLineEdit( w, n ){ allowInserts=allow; index=0; nocase=false; listBox=0; if( !allow ) setValidator( new QHaccChoiceValidator( &strings, this ) ); } QHaccChoiceEdit::~QHaccChoiceEdit(){} void QHaccChoiceEdit::ignoreCase( bool b ){ nocase=b; } void QHaccChoiceEdit::insertItem( const QString& newOne ){ if ( !strings.contains( newOne ) ){ strings+=newOne; strings.sort(); } } void QHaccChoiceEdit::insertStringList( QStringList newOnes ){ for( QStringList::iterator it=newOnes.begin(); it!=newOnes.end(); ++it ){ if( !strings.contains( *it ) ) strings+=( *it ); } strings.sort(); } void QHaccChoiceEdit::remove( QString s ){ strings.remove( s ); } void QHaccChoiceEdit::clear(){ strings.clear(); } void QHaccChoiceEdit::complete(){ //cout<<"into complete "<"<"< mymap; QStringList::Iterator it=strings.begin(); while( it!=strings.end() ){ if( nocase ){ QString str=( *it ).lower(); prefixer=prefixer.lower(); if( ( str ).startsWith( prefixer ) && ( str ).length()>=prefixer.length() ){ mymap[str]=*it; } } else{ if( ( *it ).startsWith( prefixer ) && ( *it ).length()>=prefixer.length() ){ mymap[( *it )]=*it; } } ++it; } if( mymap.empty() ) { if( listBox ) listBox->close(); if( !allowInserts ){ setText( "" ); setCursorPosition( 0 ); selectAll(); } } /* else if( mymap.size()==1 ){ QHaccLineEdit::setText( ( *mymap.begin() ).second ); setSelection( sstart, text().length()-sstart ); if( listBox ) listBox->close(); } */ else{ if( !listBox ) createListBox(); listBox->clear(); map::iterator it=mymap.begin(); QStringList strs; for( ; it!=mymap.end(); ++it ) strs<<( *it ).second; if( isempty ) listBox->insertItem( empty, 0 ); listBox->insertStringList( strs ); QPoint point=mapToGlobal( rect().bottomLeft() ); point.setY( point.y()+1 ); // move one pixel down listBox->move( point ); // resize the completion box based on items inside int tH=0; if ( listBox->variableHeight() ){ for( int i=0; i<( int )listBox->count(); ++i ){ tH+=listBox->itemHeight( i ); } } else tH=listBox->itemHeight( 0 )*listBox->count(); listBox->setSelected( listBox->item( 0 ), true ); if( !allowInserts ) itemHighlighted( listBox->item( 0 ) ); // don't put the listbox off the screen listBox->setFixedHeight( QMIN( tH+5, qApp->desktop()->height()-point.y() ) ); listBox->setFixedWidth( width() ); listBox->show(); } } void QHaccChoiceEdit::createListBox(){ if( !listBox ){ listBox=new QListBox( this, "listBox", WType_Popup ); connect( listBox, SIGNAL( clicked( QListBoxItem *) ), this, SLOT( itemChosen(QListBoxItem * ) ) ); connect( listBox, SIGNAL( returnPressed( QListBoxItem * ) ), this, SLOT( itemChosen( QListBoxItem * ) ) ); if( !allowInserts ){ connect( listBox, SIGNAL( highlighted( QListBoxItem * ) ), this, SLOT( itemHighlighted( QListBoxItem * ) ) ); } listBox->setFocusProxy( this ); } } void QHaccChoiceEdit::itemHighlighted( QListBoxItem * item ){ if( item ){ QString first=item->text(); int cpos=cursorPosition(); QHaccLineEdit::setText( first ); setCursorPosition( cpos ); } } void QHaccChoiceEdit::itemChosen( QListBoxItem * item ){ if( item ) QHaccLineEdit::setText( item->text() ); listBox->close(); } void QHaccChoiceEdit::keyPressEvent( QKeyEvent * qke ){ int key=qke->key(); if( key==Key_Up || key==Key_Down || key==Key_PageDown || key==Key_PageUp ){ qke->accept(); if( listBox ){ if( listBox->isVisible() ){ int nitems=( int )listBox->count(); int newitem=listBox->currentItem(); if( key==Key_Up ) newitem--; else if( key==Key_Down ) newitem++; else{ // the -2/+2 stuff is so that we leave a little buffer when cycling int nvis=listBox->numItemsVisible(); if( key==Key_PageDown ) newitem+=nvis-2; else newitem-=nvis+2; } // provide a cycling mechanism if( newitem<0 ) newitem=nitems+newitem; else if( newitem>( nitems-1 ) ) newitem=newitem%nitems; listBox->setSelected( newitem, true ); listBox->ensureCurrentVisible(); } else listBox->show(); } else complete(); } // up, down, pageup, pagedown else{ if( key==Key_Escape ){ // if we hit escape, close the listbox before moving on if( listBox && listBox->isVisible() ) listBox->close(); else qke->ignore(); // allow to propagate up the widget stack return; } // remember: the "empty" string isn't necessarily no text if( text().isEmpty() ) selectAll(); QHaccLineEdit::keyPressEvent( qke ); int key=qke->key(); if( !allowInserts && ( key==Key_Backspace || key==Key_Delete ) ) setText( "" ); complete(); if( !allowInserts ){ if( text().isEmpty() ) selectAll(); else{ int cp=cursorPosition(); setSelection( cp, text().length()-cp ); } } } } bool QHaccChoiceEdit::event( QEvent * qe ){ if ( qe->type()==QEvent::KeyPress ){ const int key=( ( QKeyEvent * )qe )->key(); if ( key==Key_Tab || key==Key_BackTab ) removeListBox(); // and propagate else if( key==Key_Enter || key==Key_Return ){ // if we're showing a list box, move the text // to the line edit and close the listbox if( listBox && listBox->isVisible() ){ #if QT_VERSION<320 itemChosen( listBox->item( listBox->currentItem() ) ); #else itemChosen( listBox->selectedItem() ); #endif return true; } // else we'll propagate the keypress } } else if( qe->type()==QEvent::Hide ) ignorecomplete=true; else if( qe->type()==QEvent::Show ) ignorecomplete=false; return QHaccLineEdit::event( qe ); } void QHaccChoiceEdit::removeListBox(){ if( listBox ){ delete listBox; listBox=0; } } /* * * * * * * * * * * * * */ /* * * * MONEY EDIT * * * */ /* * * * * * * * * * * * * */ QHaccMoneyEdit::QHaccMoneyEdit( const MonCon& c, QWidget * p, const char * n ) : QHaccChoiceEdit( true, p, n ){ focusoutterm=total=0; add=sub=false; conv=&c; } QHaccMoneyEdit::~QHaccMoneyEdit(){} /* void QHaccMoneyEdit::keyPressEvent( QKeyEvent * qke ){ int key=qke->key(); QString txt=qke->text(); if( Key_Plus==key || Key_Minus==key || Key_Equal==key ){ // we've hit the + or - key, so total up if we // were previously calculating something //if( add ){ if( Key_Plus==key ){ cout<<"into add, term is "<convert( total ) ); } //else if( sub ){ else if( Key_Minus==key ){ cout<<"into sub, term is "<convert( total ) ); } if( Key_Equal==key ){ cout<<"into equal, term is "<converti( text() ); } cout<key(); QString txt=qke->text(); if( blanktext && Key_Backspace!=key ){ blanktext=false; setText( "" ); } QHaccChoiceEdit::keyPressEvent( qke ); QString ftext=text(); focusoutterm=conv->converti( ftext ); if( Key_Plus==key || Key_Minus==key || Key_Equal==key ){ // we've hit the + or - key, so total up if we // were previously calculating something // get rid of the +, -, or = signs ftext=ftext.left( ftext.length()-1 ); int term=conv->converti( ftext ); if( add ) total+=term; else if( sub ) total-=term; if( Key_Plus==key ){ add=true; sub=false; if( 0==total ) total=term; // this is for the first run through setText( conv->convert( total )+txt ); blanktext=true; } else if( Key_Minus==key ){ sub=true; add=false; if( 0==total ) total=term; // this is for the first run through setText( conv->convert( total )+txt ); blanktext=true; } if( Key_Equal==key ){ setText( conv->convert( total ) ); add=sub=false; } } else if( Key_Backspace==key ){ if( ftext.isEmpty() ){ total=0; add=sub=false; } } } void QHaccMoneyEdit::focusOutEvent( QFocusEvent * e ){ // figure out our total before losing focus if( add ) total+=focusoutterm; else if( sub ) total-=focusoutterm; if( 0!=total ) setText( conv->convert( total ) ); QHaccChoiceEdit::focusOutEvent( e ); } /* * * * * * * * * * * * * */ /* * * * * DATEEDIT * * * */ /* * * * * * * * * * * * * */ QHaccDateEdit::DateFormat QHaccDateEdit::form=QHaccDateEdit::AMERICAN; QString QHaccDateEdit::sep="/"; QString QHaccDateEdit::AmForm="MM/dd/yyyy"; QString QHaccDateEdit::EuForm="dd/MM/yyyy"; QString QHaccDateEdit::YfForm="yyyy/MM/dd"; // a text box that is specially designed to store dates QHaccDateEdit::QHaccDateEdit( QWidget * p, const char * n ) : QHaccLineEdit( p, n ){ setDate( QDate::currentDate() ); setValidator( new QHaccDateValidator( this ) ); } QHaccDateEdit::QHaccDateEdit( const QDate& d, QWidget * p, const char * n ) : QHaccLineEdit( p, n ){ setDate( d ); setValidator( new QHaccDateValidator( this ) ); } QHaccDateEdit::~QHaccDateEdit(){} void QHaccDateEdit::refresh(){ setText( getDateString( day ) ); } QString QHaccDateEdit::getDateString( const QDate& d ){ return Utils::stringFromDate( d, sep, ( int )form ); } QDate QHaccDateEdit::getValidDateFromString( const QString& dstring ){ QDate d=getDateFromString( dstring ); return ( d.isValid() ? d : QDate::currentDate() ); } QDate QHaccDateEdit::getDateFromString( const QString& dstring ){ return Utils::dateFromString( dstring, sep, ( int )form ); } void QHaccDateEdit::setDateFormat( DateFormat d ){ form=d; } void QHaccDateEdit::setDateSeparator( const QString& s ){ sep=s; AmForm="MM"+s+"dd"+s+"yyyy"; EuForm="dd"+s+"MM"+s+"yyyy"; YfForm="yyyy"+s+"MM"+s+"dd"; } void QHaccDateEdit::setDate( const QDate& d ){ QDate before( day ); if( d.isValid() ) day=d; else day=QDate::currentDate(); setText( getDateString( day ) ); if ( before!=day ) emit dateChanged( day ); } void QHaccDateEdit::focusOutEvent( QFocusEvent * ){ deselect(); setDate( getValidDateFromString( text() ) ); } void QHaccDateEdit::focusInEvent( QFocusEvent * ){ setSelection( 0, text().find( sep ) ); } bool QHaccDateEdit::event( QEvent * qe ){ if ( qe->type()==QEvent::KeyPress ){ int sep1=text().find( sep ); int sep2=text().find( sep, sep1+1 )-1; int pos=cursorPosition(); int elempos=0; if( pos>sep2+1 ) elempos=2; else if ( pos>sep1 ) elempos=1; QKeyEvent * k=( QKeyEvent * )qe; int key=k->key(); if ( key==Key_Tab ){ if( elempos==0 ){ // we're on the first date element setCursorPosition( sep1+1 ); setSelection( sep1+1, sep2-sep1 ); // highlight the next element } else if( elempos==1 ){ // we're on element #2 setCursorPosition( sep2+1 ); setSelection( sep2+2, text().length()-( sep2+2 ) ); // last element } else if( elempos==2 ) return QWidget::event( qe ); return true; } else if( key==Key_BackTab ){ if( elempos==0 ) return QWidget::event( qe ); else if( elempos==1 ){ setCursorPosition( 0 ); setSelection( 0, sep1 ); // highlight the first element } else if( elempos==2 ){ // we're on element #2 setCursorPosition( sep1+1 ); setSelection( sep1+1, sep2-sep1 ); // 2nd element } return true; } else if( key==Key_Up || key==Key_Down ){ QDate me=getValidDateFromString( text() ); QDate month, date, year; // figure out what might get changed int change=-1; if ( k->key()==Key_Up ) change=1; year=me.addYears( change ); month=me.addMonths( change ); date=me.addDays( change ); // apply the correct change to the date if ( elempos==0 ){ if( form==AMERICAN ) setDate( month ); else if ( form==EUROPEAN ) setDate( date ); else setDate( year ); } else if ( elempos==1 ){ if( form==AMERICAN ) setDate( date ); else setDate( month ); } else if ( elempos==2 ){ if( form==YEARFIRST ) setDate( date ); else setDate( year ); } // calling setDate will position the cursor at the end of the // lineedit. we want the cursor right where the user left it setCursorPosition( pos ); return true; } else return QWidget::event( qe ); } else return QWidget::event( qe ); } QDate QHaccDateEdit::getDate() const { return day; } QHaccDateEdit::DateFormat QHaccDateEdit::getDateFormat() { return form; } QString QHaccDateEdit::getDateSeparator() { return sep; } /* * * * * * * * * * * * */ /* * * * ACCELEDIT * * * */ /* * * * * * * * * * * * */ QHaccAccelEdit::QHaccAccelEdit( QWidget * p, const char * n ) : QHaccLineEdit( p, n ){ } QHaccAccelEdit::QHaccAccelEdit( const QString& c, QWidget * p, const char * n ) : QHaccLineEdit( c, p, n ){ } QHaccAccelEdit::~QHaccAccelEdit(){} void QHaccAccelEdit::keyPressEvent( QKeyEvent * e ){ QString txt=e->text(); if( txt.isNull() ) e->ignore(); else{ int key=e->key(); if( key==Key_Backspace || key==Key_Delete ){ setText( "" ); e->accept(); } ButtonState keystate=e->state(); if( keystate ){ if( keystate & ControlButton ) key+=CTRL; if( keystate & ShiftButton ) key+=SHIFT; if( keystate & AltButton ) key+=ALT; #if QT_VERSION>=320 if( keystate & MetaButton ) key+=META; #endif setText( QKeySequence( key ) ); e->accept(); } else e->ignore(); } } /* * * * * * * * * * * * * */ /* * * * DATEVALIDATOR * * */ /* * * * * * * * * * * * * */ QHaccDateValidator::QHaccDateValidator( QWidget * p, const char * n ) : QValidator( p, n ) {} QHaccDateValidator::~QHaccDateValidator(){} QValidator::State QHaccDateValidator::validate( QString& text, int& ) const { // only accept numbers, or date separators in the correct form // don't worry about valid dates, just the right form QString sep="\\"+QHaccDateEdit::getDateSeparator(); QString year="[12][09]\\d\\d"; QString mon="[01]?\\d"; QString day="[0123]?\\d"; QString pattern="^"; QHaccDateEdit::DateFormat form=QHaccDateEdit::getDateFormat(); if( form==QHaccDateEdit::AMERICAN ) pattern+=mon+sep+day+sep+year; else if ( form==QHaccDateEdit::EUROPEAN ) pattern+=day+sep+mon+sep+year; else pattern+=year+sep+mon+sep+day; pattern+="$"; QRegExp exp( pattern ); if( exp.search( text, 0 )>-1 ) return Acceptable; exp.setPattern( "^\\d*"+sep+"\\d*"+sep+"\\d*$" ); if( exp.search( text, 0 )>-1 ) return Intermediate; return Invalid; } /* * * * * * * * * * * * * * * */ /* * * * CHOICEVALIDATOR * * * */ /* * * * * * * * * * * * * * * */ QHaccChoiceValidator::QHaccChoiceValidator( QStringList * l, QHaccChoiceEdit * p, const char * n ) : QValidator( p, n ) { list=l; } QHaccChoiceValidator::~QHaccChoiceValidator(){} QValidator::State QHaccChoiceValidator::validate( QString& text, int& ) const { // only accept strings that are contained in the list // anything else might be valid, but we can't tell if( list->contains( text ) || ( ( QHaccChoiceEdit * )parent() )->text().isEmpty() ) return Acceptable; return Intermediate; }