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