kdeui Library API Documentation

keditcl1.cpp

00001 /* This file is part of the KDE libraries
00002 
00003    Copyright (C) 1997 Bernd Johannes Wuebben <wuebben@math.cornell.edu>
00004    Copyright (C) 2000 Waldo Bastian <bastian@kde.org>
00005 
00006    This library is free software; you can redistribute it and/or
00007    modify it under the terms of the GNU Library General Public
00008    License as published by the Free Software Foundation; either
00009    version 2 of the License, or (at your option) any later version.
00010 
00011    This library is distributed in the hope that it will be useful,
00012    but WITHOUT ANY WARRANTY; without even the implied warranty of
00013    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014    Library General Public License for more details.
00015 
00016    You should have received a copy of the GNU Library General Public License
00017    along with this library; see the file COPYING.LIB.  If not, write to
00018    the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00019    Boston, MA 02111-1307, USA.
00020 */
00021 
00022 #include <qdragobject.h>
00023 #include <qpopupmenu.h>
00024 #include <qtextstream.h>
00025 #include <qtimer.h>
00026 
00027 #include <kapplication.h>
00028 #include <kcursor.h>
00029 #include <kdebug.h>
00030 #include <kcmenumngr.h>
00031 #include <kfontdialog.h>
00032 #include <klocale.h>
00033 #include <kmessagebox.h>
00034 #include <kstdaccel.h>
00035 #include <kurldrag.h>
00036 
00037 #include "keditcl.h"
00038 #include "keditcl.moc"
00039 
00040 class KEdit::KEditPrivate
00041 {
00042 public:
00043     bool overwriteEnabled:1;
00044     bool posDirty:1;
00045     bool autoUpdate:1;
00046 };
00047 
00048 
00049 KEdit::KEdit(QWidget *_parent, const char *name)
00050    : QMultiLineEdit(_parent, name)
00051 {
00052     d = new KEditPrivate;
00053     d->overwriteEnabled = false;
00054     d->posDirty = true;
00055     d->autoUpdate = true;
00056 
00057     parent = _parent;
00058 
00059     // set some defaults
00060 
00061     line_pos = col_pos = 0;
00062 
00063     srchdialog = NULL;
00064     replace_dialog= NULL;
00065     gotodialog = NULL;
00066 
00067     setAcceptDrops(true);
00068     KCursor::setAutoHideCursor( this, true );
00069 
00070     connect(this, SIGNAL(cursorPositionChanged(int,int)),
00071             this, SLOT(slotCursorPositionChanged()));
00072 }
00073 
00074 
00075 KEdit::~KEdit()
00076 {
00077   delete d;
00078 }
00079 
00080 void
00081 KEdit::setAutoUpdate(bool b)
00082 {
00083   d->autoUpdate = b;
00084 }
00085 
00086 void
00087 KEdit::insertText(QTextStream *stream)
00088 {
00089 //   setAutoUpdate(false);
00090    int line, col;
00091    getCursorPosition(&line, &col);
00092    int saveline = line;
00093    int savecol = col;
00094    QString textLine;
00095 
00096    // MS: Patch by Martin Schenk <martin@schenk.com>
00097    // MS: disable UNDO, or QMultiLineEdit remembers every textLine !!!
00098    // memory usage is:
00099    //   textLine: 2*size rounded up to nearest power of 2 (520Kb -> 1024Kb)
00100    //   widget:   about (2*size + 60bytes*lines)
00101    // -> without disabling undo, it often needs almost 8*size
00102    int oldUndoDepth = undoDepth();
00103    setUndoDepth( 0 ); // ### -1?
00104 
00105    // MS: read everything at once if file <= 1MB,
00106    // else read in 5000-line chunks to keep memory usage acceptable.
00107    QIODevice *dev=stream->device();
00108    if (dev && dev->size()>(1024*1024)) {
00109       while(1) {
00110         int i;
00111         textLine="";
00112         for (i=0; i<5000; i++) {
00113                 QString line=stream->readLine();
00114                 if (line.isNull()) break;  // EOF
00115                 textLine+=line+'\n';
00116         }
00117         insertAt(textLine, line, col);
00118         line+=i; col=0;
00119         if (i!=5000) break;
00120       }
00121    }
00122    else {
00123         textLine = stream->read(); // Read all !
00124         insertAt( textLine, line, col);
00125    }
00126    setUndoDepth( oldUndoDepth );
00127 
00128    setCursorPosition(saveline, savecol);
00129 //   setAutoUpdate(true);
00130 
00131 //   repaint();
00132 
00133    setModified(true);
00134    setFocus();
00135 
00136    // Bernd: Please don't leave debug message like that lying around
00137    // they cause ENORMOUSE performance hits. Once upon a day
00138    // kedit used to be really really fast using memmap etc .....
00139    // oh well ....
00140 
00141    //   QString str = text();
00142    //   for (int i = 0; i < (int) str.length(); i++)
00143    //     printf("KEdit: U+%04X\n", str[i].unicode());
00144 
00145 }
00146 
00147 void
00148 KEdit::cleanWhiteSpace()
00149 {
00150    d->autoUpdate = false;
00151    if (!hasMarkedText())
00152       selectAll();
00153    QString oldText = markedText();
00154    QString newText;
00155    QStringList lines = QStringList::split('\n', oldText, true);
00156    bool addSpace = false;
00157    bool firstLine = true;
00158    QChar lastChar = oldText[oldText.length()-1];
00159    QChar firstChar = oldText[0];
00160    for(QStringList::Iterator it = lines.begin();
00161        it != lines.end();)
00162    {
00163       QString line = (*it).simplifyWhiteSpace();
00164       if (line.isEmpty())
00165       {
00166          if (addSpace)
00167             newText += QString::fromLatin1("\n\n");
00168          if (firstLine)
00169          {
00170             if (firstChar.isSpace())
00171                newText += '\n';
00172             firstLine = false;
00173          }
00174          addSpace = false;
00175       }
00176       else
00177       {
00178          if (addSpace)
00179             newText += ' ';
00180          if (firstLine)
00181          {
00182             if (firstChar.isSpace())
00183                newText += ' ';
00184             firstLine = false;
00185          }
00186          newText += line;
00187          addSpace = true;
00188       }
00189       it = lines.remove(it);
00190    }
00191    if (addSpace)
00192    {
00193       if (lastChar == '\n')
00194          newText += '\n';
00195       else if (lastChar.isSpace())
00196          newText += ' ';
00197    }
00198 
00199    if (oldText == newText)
00200    {
00201       deselect();
00202       d->autoUpdate = true;
00203       repaint();
00204       return;
00205    }
00206    if (wordWrap() == NoWrap)
00207    {
00208       // If wordwrap is off, we have to do some line-wrapping ourselves now
00209       // We use another QMultiLineEdit for this, so that we get nice undo
00210       // behavior.
00211       QMultiLineEdit *we = new QMultiLineEdit();
00212       we->setWordWrap(FixedColumnWidth);
00213       we->setWrapColumnOrWidth(78);
00214       we->setText(newText);
00215       newText = QString::null;
00216       for(int i = 0; i < we->numLines(); i++)
00217       {
00218         QString line = we->textLine(i);
00219         if (line.right(1) != "\n")
00220            line += '\n';
00221         newText += line;
00222       }
00223       delete we;
00224    }
00225 
00226    insert(newText);
00227    d->autoUpdate = true;
00228    repaint();
00229 
00230    setModified(true);
00231    setFocus();
00232 }
00233 
00234 
00235 void
00236 KEdit::saveText(QTextStream *stream)
00237 {
00238    saveText(stream, false);
00239 }
00240 
00241 void
00242 KEdit::saveText(QTextStream *stream, bool softWrap)
00243 {
00244    int line_count = numLines()-1;
00245    if (line_count < 0)
00246       return;
00247 
00248    if (softWrap || (wordWrap() == NoWrap))
00249    {
00250       for(int i = 0; i < line_count; i++)
00251       {
00252          (*stream) << textLine(i) << '\n';
00253       }
00254       (*stream) << textLine(line_count);
00255    }
00256    else
00257    {
00258       for(int i = 0; i <= line_count; i++)
00259       {
00260          int lines_in_parag = linesOfParagraph(i);
00261          if (lines_in_parag == 1)
00262          {
00263             (*stream) << textLine(i);
00264          }
00265          else
00266          {
00267             QString parag_text = textLine(i);
00268             int pos = 0;
00269             int first_pos = 0;
00270             int current_line = 0;
00271             while(true) {
00272                while(lineOfChar(i, pos) == current_line) pos++;
00273                (*stream) << parag_text.mid(first_pos, pos - first_pos - 1) << '\n';
00274                current_line++;
00275                first_pos = pos;
00276                if (current_line+1 == lines_in_parag)
00277                {
00278                   // Last line
00279                   (*stream) << parag_text.mid(pos);
00280                   break;
00281                }
00282             }
00283          }
00284          if (i < line_count)
00285             (*stream) << '\n';
00286       }
00287    }
00288 }
00289 
00290 int KEdit::currentLine(){
00291 
00292   computePosition();
00293   return line_pos;
00294 
00295 }
00296 
00297 int KEdit::currentColumn(){
00298 
00299   computePosition();
00300   return col_pos;
00301 }
00302 
00303 void KEdit::slotCursorPositionChanged()
00304 {
00305   d->posDirty = true;
00306   emit CursorPositionChanged();
00307 }
00308 
00309 void KEdit::computePosition()
00310 {
00311   if (!d->posDirty) return;
00312   d->posDirty = false;
00313 
00314   int line, col;
00315 
00316   getCursorPosition(&line,&col);
00317 
00318   // line is expressed in paragraphs, we now need to convert to lines
00319   line_pos = 0;
00320   if (wordWrap() == NoWrap)
00321   {
00322      line_pos = line;
00323   }
00324   else
00325   {
00326      for(int i = 0; i < line; i++)
00327         line_pos += linesOfParagraph(i);
00328   }
00329 
00330   int line_offset = lineOfChar(line, col);
00331   line_pos += line_offset;
00332 
00333   // We now calculate where the current line starts in the paragraph.
00334   QString linetext = textLine(line);
00335   int start_of_line = 0;
00336   if (line_offset > 0)
00337   {
00338      start_of_line = col;
00339      while(lineOfChar(line, --start_of_line) == line_offset);
00340      start_of_line++;
00341   }
00342 
00343 
00344   // O.K here is the deal: The function getCursorPositoin returns the character
00345   // position of the cursor, not the screenposition. I.e,. assume the line
00346   // consists of ab\tc then the character c will be on the screen on position 8
00347   // whereas getCursorPosition will return 3 if the cursors is on the character c.
00348   // Therefore we need to compute the screen position from the character position.
00349   // That's what all the following trouble is all about:
00350 
00351   int coltemp = col-start_of_line;
00352   int pos  =    0;
00353   int find =    0;
00354   int mem  =    0;
00355   bool found_one = false;
00356 
00357   // if you understand the following algorithm you are worthy to look at the
00358   // kedit+ sources -- if not, go away ;-)
00359 
00360 
00361   while(find >=0 && find <= coltemp- 1 ){
00362     find = linetext.find('\t', find+start_of_line, true )-start_of_line;
00363     if( find >=0 && find <= coltemp - 1 ){
00364       found_one = true;
00365       pos = pos + find - mem;
00366       pos = pos + 8  - pos % 8;
00367       mem = find;
00368       find ++;
00369     }
00370   }
00371 
00372   pos = pos + coltemp - mem;  // add the number of characters behind the
00373                               // last tab on the line.
00374 
00375   if (found_one){
00376     pos = pos - 1;
00377   }
00378 
00379   col_pos = pos;
00380 }
00381 
00382 
00383 void KEdit::keyPressEvent ( QKeyEvent *e)
00384 {
00385   // ignore Ctrl-Return so that KDialogBase can catch them
00386   if ( e->key() == Key_Return && e->state() == ControlButton ) {
00387       e->ignore();
00388       return;
00389   }
00390 
00391   KKey key(e);
00392   int keyQt = key.keyCodeQt();
00393 
00394   if ( keyQt == CTRL+Key_K ){
00395 
00396     int line = 0;
00397     int col  = 0;
00398     QString killstring;
00399 
00400     if(!killing){
00401       killbufferstring = "";
00402       killtrue = false;
00403       lastwasanewline = false;
00404     }
00405 
00406     if(!atEnd()){
00407 
00408       getCursorPosition(&line,&col);
00409       killstring = textLine(line);
00410       killstring = killstring.mid(col,killstring.length());
00411 
00412 
00413       if(!killbufferstring.isEmpty() && !killtrue && !lastwasanewline){
00414         killbufferstring += '\n';
00415       }
00416 
00417       if( (killstring.length() == 0) && !killtrue){
00418         killbufferstring += '\n';
00419         lastwasanewline = true;
00420       }
00421 
00422       if(killstring.length() > 0){
00423 
00424         killbufferstring += killstring;
00425         lastwasanewline = false;
00426         killtrue = true;
00427 
00428       }else{
00429 
00430         lastwasanewline = false;
00431         killtrue = !killtrue;
00432 
00433       }
00434 
00435     }else{
00436 
00437     if(killbufferstring.isEmpty() && !killtrue && !lastwasanewline){
00438       killtrue = true;
00439     }
00440 
00441     }
00442 
00443     killing = true;
00444 
00445     QMultiLineEdit::keyPressEvent(e);
00446     setModified(true);
00447     return;
00448   }
00449   else if ( keyQt == CTRL+Key_Y ){
00450 
00451     int line = 0;
00452     int col  = 0;
00453 
00454     getCursorPosition(&line,&col);
00455 
00456     QString tmpstring = killbufferstring;
00457     if(!killtrue)
00458       tmpstring += '\n';
00459 
00460     insertAt(tmpstring,line,col);
00461 
00462     killing = false;
00463     setModified(true);
00464     return;
00465   }
00466 
00467   killing = false;
00468 
00469   if ( KStdAccel::copy().contains( key ) )
00470     copy();
00471   else if ( isReadOnly() )
00472     QMultiLineEdit::keyPressEvent( e );
00473   // If this is an unmodified printable key, send it directly to QMultiLineEdit.
00474   else if ( !(key.keyCodeQt() & (CTRL | ALT)) && !e->text().isEmpty() && e->text().unicode()->isPrint() )
00475     QMultiLineEdit::keyPressEvent( e );
00476   else if ( KStdAccel::paste().contains( key ) ) {
00477     paste();
00478     setModified(true);
00479     slotCursorPositionChanged();
00480   }
00481   else if ( KStdAccel::cut().contains( key ) ) {
00482     cut();
00483     setModified(true);
00484     slotCursorPositionChanged();
00485   }
00486   else if ( KStdAccel::undo().contains( key ) ) {
00487     undo();
00488     setModified(true);
00489     slotCursorPositionChanged();
00490   }
00491   else if ( KStdAccel::redo().contains( key ) ) {
00492     redo();
00493     setModified(true);
00494     slotCursorPositionChanged();
00495   }
00496   else if ( KStdAccel::deleteWordBack().contains( key ) ) {
00497     moveCursor(MoveWordBackward, true);
00498     if (hasSelectedText())
00499       del();
00500     setModified(true);
00501     slotCursorPositionChanged();
00502   }
00503   else if ( KStdAccel::deleteWordForward().contains( key ) ) {
00504     moveCursor(MoveWordForward, true);
00505     if (hasSelectedText())
00506       del();
00507     setModified(true);
00508     slotCursorPositionChanged();
00509   }
00510   else if ( KStdAccel::backwardWord().contains( key ) ) {
00511     moveCursor(MoveWordBackward, false );
00512     slotCursorPositionChanged();
00513   }
00514   else if ( KStdAccel::forwardWord().contains( key ) ) {
00515     moveCursor( MoveWordForward, false );
00516     slotCursorPositionChanged();
00517   }
00518   else if ( KStdAccel::next().contains( key ) ) {
00519     moveCursor( MovePgDown, false );
00520     slotCursorPositionChanged();
00521   }
00522   else if ( KStdAccel::prior().contains( key ) ) {
00523     moveCursor( MovePgUp, false );
00524     slotCursorPositionChanged();
00525   }
00526   else if ( KStdAccel::home().contains( key ) ) {
00527     moveCursor( MoveHome, false );
00528     slotCursorPositionChanged();
00529   }
00530   else if ( KStdAccel::end().contains( key ) ) {
00531     moveCursor( MoveEnd, false );
00532     slotCursorPositionChanged();
00533   }
00534   else if ( KStdAccel::beginningOfLine().contains( key ) ) {
00535     moveCursor( MoveLineStart, false);
00536     slotCursorPositionChanged();
00537   }
00538   else if ( KStdAccel::endOfLine().contains( key ) ) {
00539     moveCursor( MoveLineEnd, false);
00540     slotCursorPositionChanged();
00541   }
00542   else if ( key == Key_Insert ) {
00543     if (d->overwriteEnabled)
00544     {
00545       this->setOverwriteMode(!this->isOverwriteMode());
00546       emit toggle_overwrite_signal();
00547     }
00548   }
00549   else
00550     QMultiLineEdit::keyPressEvent(e);
00551 }
00552 
00553 void KEdit::installRBPopup(QPopupMenu *p) {
00554   KContextMenuManager::insert( this, p );
00555 }
00556 
00557 void KEdit::selectFont(){
00558 
00559   QFont font = this->font();
00560   KFontDialog::getFont(font);
00561   this->setFont(font);
00562 
00563 }
00564 
00565 void KEdit::doGotoLine() {
00566 
00567    if( !gotodialog )
00568       gotodialog = new KEdGotoLine( parent, "gotodialog" );
00569 
00570    this->clearFocus();
00571 
00572    gotodialog->exec();
00573    // this seems to be not necessary
00574    // gotodialog->setFocus();
00575    if( gotodialog->result() != KEdGotoLine::Accepted)
00576       return;
00577    int target_line = gotodialog->getLineNumber()-1;
00578    if (wordWrap() == NoWrap)
00579    {
00580       setCursorPosition( target_line, 0 );
00581       setFocus();
00582       return;
00583    }
00584 
00585    int max_parag = paragraphs();
00586 
00587    int line = 0;
00588    int parag = -1;
00589    int lines_in_parag = 0;
00590    while ((++parag < max_parag) && (line + lines_in_parag < target_line))
00591    {
00592       line += lines_in_parag;
00593       lines_in_parag = linesOfParagraph(parag);
00594    }
00595 
00596    int col = 0;
00597    if (parag >= max_parag)
00598    {
00599       target_line = line + lines_in_parag - 1;
00600       parag = max_parag-1;
00601    }
00602 
00603    while(1+line+lineOfChar(parag,col) < target_line) col++;
00604    setCursorPosition( parag, col );
00605    setFocus();
00606 }
00607 
00608 
00609 void  KEdit::dragMoveEvent(QDragMoveEvent* e) {
00610 
00611   if(KURLDrag::canDecode(e))
00612     e->accept();
00613   else if(QTextDrag::canDecode(e))
00614     QMultiLineEdit::dragMoveEvent(e);
00615 }
00616 
00617 void  KEdit::contentsDragMoveEvent(QDragMoveEvent* e) {
00618 
00619   if(KURLDrag::canDecode(e))
00620     e->accept();
00621   else if(QTextDrag::canDecode(e))
00622     QMultiLineEdit::contentsDragMoveEvent(e);
00623 }
00624 
00625 void  KEdit::dragEnterEvent(QDragEnterEvent* e) {
00626 
00627   kdDebug() << "KEdit::dragEnterEvent()" << endl;
00628   e->accept(KURLDrag::canDecode(e) || QTextDrag::canDecode(e));
00629 }
00630 
00631 void  KEdit::contentsDragEnterEvent(QDragEnterEvent* e) {
00632 
00633   kdDebug() << "KEdit::contentsDragEnterEvent()" << endl;
00634   e->accept(KURLDrag::canDecode(e) || QTextDrag::canDecode(e));
00635 }
00636 
00637 
00638 void  KEdit::dropEvent(QDropEvent* e) {
00639 
00640   kdDebug() << "KEdit::dropEvent()" << endl;
00641 
00642   if(KURLDrag::canDecode(e)) {
00643    emit gotUrlDrop(e);
00644   }
00645   else if(QTextDrag::canDecode(e))
00646     QMultiLineEdit::dropEvent(e);
00647 }
00648 
00649 void  KEdit::contentsDropEvent(QDropEvent* e) {
00650 
00651   kdDebug() << "KEdit::contentsDropEvent()" << endl;
00652 
00653   if(KURLDrag::canDecode(e)) {
00654    emit gotUrlDrop(e);
00655   }
00656   else if(QTextDrag::canDecode(e))
00657     QMultiLineEdit::contentsDropEvent(e);
00658 }
00659 
00660 void KEdit::setOverwriteEnabled(bool b)
00661 {
00662   d->overwriteEnabled = b;
00663 }
00664 
00665 // QWidget::create() turns off mouse-Tracking which would break auto-hiding
00666 void KEdit::create( WId id, bool initializeWindow, bool destroyOldWindow )
00667 {
00668   QMultiLineEdit::create( id, initializeWindow, destroyOldWindow );
00669   KCursor::setAutoHideCursor( this, true );
00670 }
00671 
00672 void KEdit::ensureCursorVisible()
00673 {
00674   if (!d->autoUpdate)
00675     return;
00676 
00677   QMultiLineEdit::ensureCursorVisible();
00678 }
00679 
00680 void KEdit::setCursor( const QCursor &c )
00681 {
00682   if (!d->autoUpdate)
00683     return;
00684 
00685   QMultiLineEdit::setCursor(c);
00686 }
00687 
00688 void KEdit::viewportPaintEvent( QPaintEvent*pe )
00689 {
00690   if (!d->autoUpdate)
00691     return;
00692 
00693   QMultiLineEdit::viewportPaintEvent(pe);
00694 }
00695 
00696 
00697 void KEdGotoLine::virtual_hook( int id, void* data )
00698 { KDialogBase::virtual_hook( id, data ); }
00699 
00700 void KEdFind::virtual_hook( int id, void* data )
00701 { KDialogBase::virtual_hook( id, data ); }
00702 
00703 void KEdReplace::virtual_hook( int id, void* data )
00704 { KDialogBase::virtual_hook( id, data ); }
00705 
00706 void KEdit::virtual_hook( int, void* )
00707 { /*BASE::virtual_hook( id, data );*/ }
00708 
KDE Logo
This file is part of the documentation for kdeui Library Version 3.4.2.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Tue Aug 2 12:23:17 2005 by doxygen 1.3.9.1 written by Dimitri van Heesch, © 1997-2003