00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "Screen.h"
00025
00026
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <unistd.h>
00030 #include <assert.h>
00031 #include <string.h>
00032 #include <ctype.h>
00033
00034
00035 #include <QtCore/QTextStream>
00036 #include <QtCore/QDate>
00037
00038
00039 #include <kdebug.h>
00040
00041
00042 #include "konsole_wcwidth.h"
00043 #include "TerminalCharacterDecoder.h"
00044
00045 using namespace Konsole;
00046
00047
00048
00049 #define BS_CLEARS false
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060 #ifndef loc
00061 #define loc(X,Y) ((Y)*columns+(X))
00062 #endif
00063
00064
00065 Character Screen::defaultChar = Character(' ',
00066 CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR),
00067 CharacterColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR),
00068 DEFAULT_RENDITION);
00069
00070
00071
00072 Screen::Screen(int l, int c)
00073 : lines(l),
00074 columns(c),
00075 screenLines(new ImageLine[lines+1] ),
00076 _scrolledLines(0),
00077 _droppedLines(0),
00078 history(new HistoryScrollNone()),
00079 cuX(0), cuY(0),
00080 currentRendition(0),
00081 _topMargin(0), _bottomMargin(0),
00082 selBegin(0), selTopLeft(0), selBottomRight(0),
00083 blockSelectionMode(false),
00084 effectiveForeground(CharacterColor()), effectiveBackground(CharacterColor()), effectiveRendition(0),
00085 lastPos(-1)
00086 {
00087 lineProperties.resize(lines+1);
00088 for (int i=0;i<lines+1;i++)
00089 lineProperties[i]=LINE_DEFAULT;
00090
00091 initTabStops();
00092 clearSelection();
00093 reset();
00094 }
00095
00099 Screen::~Screen()
00100 {
00101 delete[] screenLines;
00102 delete history;
00103 }
00104
00105 void Screen::cursorUp(int n)
00106
00107 {
00108 if (n == 0) n = 1;
00109 int stop = cuY < _topMargin ? 0 : _topMargin;
00110 cuX = qMin(columns-1,cuX);
00111 cuY = qMax(stop,cuY-n);
00112 }
00113
00114 void Screen::cursorDown(int n)
00115
00116 {
00117 if (n == 0) n = 1;
00118 int stop = cuY > _bottomMargin ? lines-1 : _bottomMargin;
00119 cuX = qMin(columns-1,cuX);
00120 cuY = qMin(stop,cuY+n);
00121 }
00122
00123 void Screen::cursorLeft(int n)
00124
00125 {
00126 if (n == 0) n = 1;
00127 cuX = qMin(columns-1,cuX);
00128 cuX = qMax(0,cuX-n);
00129 }
00130
00131 void Screen::cursorRight(int n)
00132
00133 {
00134 if (n == 0) n = 1;
00135 cuX = qMin(columns-1,cuX+n);
00136 }
00137
00138 void Screen::setMargins(int top, int bot)
00139
00140 {
00141 if (top == 0) top = 1;
00142 if (bot == 0) bot = lines;
00143 top = top - 1;
00144 bot = bot - 1;
00145 if ( !( 0 <= top && top < bot && bot < lines ) )
00146 { kDebug()<<" setRegion("<<top<<","<<bot<<") : bad range.";
00147 return;
00148 }
00149 _topMargin = top;
00150 _bottomMargin = bot;
00151 cuX = 0;
00152 cuY = getMode(MODE_Origin) ? top : 0;
00153
00154 }
00155
00156 int Screen::topMargin() const
00157 {
00158 return _topMargin;
00159 }
00160 int Screen::bottomMargin() const
00161 {
00162 return _bottomMargin;
00163 }
00164
00165 void Screen::index()
00166
00167 {
00168 if (cuY == _bottomMargin)
00169 scrollUp(1);
00170 else if (cuY < lines-1)
00171 cuY += 1;
00172 }
00173
00174 void Screen::reverseIndex()
00175
00176 {
00177 if (cuY == _topMargin)
00178 scrollDown(_topMargin,1);
00179 else if (cuY > 0)
00180 cuY -= 1;
00181 }
00182
00183 void Screen::nextLine()
00184
00185 {
00186 toStartOfLine(); index();
00187 }
00188
00189 void Screen::eraseChars(int n)
00190 {
00191 if (n == 0) n = 1;
00192 int p = qMax(0,qMin(cuX+n-1,columns-1));
00193 clearImage(loc(cuX,cuY),loc(p,cuY),' ');
00194 }
00195
00196 void Screen::deleteChars(int n)
00197 {
00198 Q_ASSERT( n >= 0 );
00199
00200
00201 if (n == 0)
00202 n = 1;
00203
00204
00205 if ( cuX >= screenLines[cuY].count() )
00206 return;
00207
00208 if ( cuX+n >= screenLines[cuY].count() )
00209 n = screenLines[cuY].count() - 1 - cuX;
00210
00211 Q_ASSERT( n >= 0 );
00212 Q_ASSERT( cuX+n < screenLines[cuY].count() );
00213
00214 screenLines[cuY].remove(cuX,n);
00215 }
00216
00217 void Screen::insertChars(int n)
00218 {
00219 if (n == 0) n = 1;
00220
00221 if ( screenLines[cuY].size() < cuX )
00222 screenLines[cuY].resize(cuX);
00223
00224 screenLines[cuY].insert(cuX,n,' ');
00225
00226 if ( screenLines[cuY].count() > columns )
00227 screenLines[cuY].resize(columns);
00228 }
00229
00230 void Screen::deleteLines(int n)
00231 {
00232 if (n == 0) n = 1;
00233 scrollUp(cuY,n);
00234 }
00235
00236 void Screen::insertLines(int n)
00237 {
00238 if (n == 0) n = 1;
00239 scrollDown(cuY,n);
00240 }
00241
00242 void Screen::setMode(int m)
00243 {
00244 currentModes[m] = true;
00245 switch(m)
00246 {
00247 case MODE_Origin : cuX = 0; cuY = _topMargin; break;
00248 }
00249 }
00250
00251 void Screen::resetMode(int m)
00252 {
00253 currentModes[m] = false;
00254 switch(m)
00255 {
00256 case MODE_Origin : cuX = 0; cuY = 0; break;
00257 }
00258 }
00259
00260 void Screen::saveMode(int m)
00261 {
00262 savedModes[m] = currentModes[m];
00263 }
00264
00265 void Screen::restoreMode(int m)
00266 {
00267 currentModes[m] = savedModes[m];
00268 }
00269
00270 bool Screen::getMode(int m) const
00271 {
00272 return currentModes[m];
00273 }
00274
00275 void Screen::saveCursor()
00276 {
00277 savedState.cursorColumn = cuX;
00278 savedState.cursorLine = cuY;
00279 savedState.rendition = currentRendition;
00280 savedState.foreground = currentForeground;
00281 savedState.background = currentBackground;
00282 }
00283
00284 void Screen::restoreCursor()
00285 {
00286 cuX = qMin(savedState.cursorColumn,columns-1);
00287 cuY = qMin(savedState.cursorLine,lines-1);
00288 currentRendition = savedState.rendition;
00289 currentForeground = savedState.foreground;
00290 currentBackground = savedState.background;
00291 updateEffectiveRendition();
00292 }
00293
00294 void Screen::resizeImage(int new_lines, int new_columns)
00295 {
00296 if ((new_lines==lines) && (new_columns==columns)) return;
00297
00298 if (cuY > new_lines-1)
00299 {
00300 _bottomMargin = lines-1;
00301 for (int i = 0; i < cuY-(new_lines-1); i++)
00302 {
00303 addHistLine(); scrollUp(0,1);
00304 }
00305 }
00306
00307
00308
00309 ImageLine* newScreenLines = new ImageLine[new_lines+1];
00310 for (int i=0; i < qMin(lines-1,new_lines+1) ;i++)
00311 newScreenLines[i]=screenLines[i];
00312 for (int i=lines;(i > 0) && (i<new_lines+1);i++)
00313 newScreenLines[i].resize( new_columns );
00314
00315 lineProperties.resize(new_lines+1);
00316 for (int i=lines;(i > 0) && (i<new_lines+1);i++)
00317 lineProperties[i] = LINE_DEFAULT;
00318
00319 clearSelection();
00320
00321 delete[] screenLines;
00322 screenLines = newScreenLines;
00323
00324 lines = new_lines;
00325 columns = new_columns;
00326 cuX = qMin(cuX,columns-1);
00327 cuY = qMin(cuY,lines-1);
00328
00329
00330 _topMargin=0;
00331 _bottomMargin=lines-1;
00332 initTabStops();
00333 clearSelection();
00334 }
00335
00336 void Screen::setDefaultMargins()
00337 {
00338 _topMargin = 0;
00339 _bottomMargin = lines-1;
00340 }
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367
00368
00369
00370
00371
00372
00373
00374
00375
00376
00377 void Screen::reverseRendition(Character& p) const
00378 {
00379 CharacterColor f = p.foregroundColor;
00380 CharacterColor b = p.backgroundColor;
00381
00382 p.foregroundColor = b;
00383 p.backgroundColor = f;
00384 }
00385
00386 void Screen::updateEffectiveRendition()
00387 {
00388 effectiveRendition = currentRendition;
00389 if (currentRendition & RE_REVERSE)
00390 {
00391 effectiveForeground = currentBackground;
00392 effectiveBackground = currentForeground;
00393 }
00394 else
00395 {
00396 effectiveForeground = currentForeground;
00397 effectiveBackground = currentBackground;
00398 }
00399
00400 if (currentRendition & RE_BOLD)
00401 effectiveForeground.toggleIntensive();
00402 }
00403
00404 void Screen::copyFromHistory(Character* dest, int startLine, int count) const
00405 {
00406 Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= history->getLines() );
00407
00408 for (int line = startLine; line < startLine + count; line++)
00409 {
00410 const int length = qMin(columns,history->getLineLen(line));
00411 const int destLineOffset = (line-startLine)*columns;
00412
00413 history->getCells(line,0,length,dest + destLineOffset);
00414
00415 for (int column = length; column < columns; column++)
00416 dest[destLineOffset+column] = defaultChar;
00417
00418
00419 if (selBegin !=-1)
00420 {
00421 for (int column = 0; column < columns; column++)
00422 {
00423 if (isSelected(column,line))
00424 {
00425 reverseRendition(dest[destLineOffset + column]);
00426 }
00427 }
00428 }
00429 }
00430 }
00431
00432 void Screen::copyFromScreen(Character* dest , int startLine , int count) const
00433 {
00434 Q_ASSERT( startLine >= 0 && count > 0 && startLine + count <= lines );
00435
00436 for (int line = startLine; line < (startLine+count) ; line++)
00437 {
00438 int srcLineStartIndex = line*columns;
00439 int destLineStartIndex = (line-startLine)*columns;
00440
00441 for (int column = 0; column < columns; column++)
00442 {
00443 int srcIndex = srcLineStartIndex + column;
00444 int destIndex = destLineStartIndex + column;
00445
00446 dest[destIndex] = screenLines[srcIndex/columns].value(srcIndex%columns,defaultChar);
00447
00448
00449 if (selBegin != -1 && isSelected(column,line + history->getLines()))
00450 reverseRendition(dest[destIndex]);
00451 }
00452
00453 }
00454 }
00455
00456 void Screen::getImage( Character* dest, int size, int startLine, int endLine ) const
00457 {
00458 Q_ASSERT( startLine >= 0 );
00459 Q_ASSERT( endLine >= startLine && endLine < history->getLines() + lines );
00460
00461 const int mergedLines = endLine - startLine + 1;
00462
00463 Q_ASSERT( size >= mergedLines * columns );
00464
00465 const int linesInHistoryBuffer = qBound(0,history->getLines()-startLine,mergedLines);
00466 const int linesInScreenBuffer = mergedLines - linesInHistoryBuffer;
00467
00468
00469 if (linesInHistoryBuffer > 0)
00470 copyFromHistory(dest,startLine,linesInHistoryBuffer);
00471
00472
00473 if (linesInScreenBuffer > 0)
00474 copyFromScreen(dest + linesInHistoryBuffer*columns,
00475 startLine + linesInHistoryBuffer - history->getLines(),
00476 linesInScreenBuffer);
00477
00478
00479 if (getMode(MODE_Screen))
00480 {
00481 for (int i = 0; i < mergedLines*columns; i++)
00482 reverseRendition(dest[i]);
00483 }
00484
00485
00486 int cursorIndex = loc(cuX, cuY + linesInHistoryBuffer);
00487 if(getMode(MODE_Cursor) && cursorIndex < columns*mergedLines)
00488 dest[cursorIndex].rendition |= RE_CURSOR;
00489 }
00490
00491 QVector<LineProperty> Screen::getLineProperties( int startLine , int endLine ) const
00492 {
00493 Q_ASSERT( startLine >= 0 );
00494 Q_ASSERT( endLine >= startLine && endLine < history->getLines() + lines );
00495
00496 const int mergedLines = endLine-startLine+1;
00497 const int linesInHistory = qBound(0,history->getLines()-startLine,mergedLines);
00498 const int linesInScreen = mergedLines - linesInHistory;
00499
00500 QVector<LineProperty> result(mergedLines);
00501 int index = 0;
00502
00503
00504 for (int line = startLine; line < startLine + linesInHistory; line++)
00505 {
00506
00507 if (history->isWrappedLine(line))
00508 {
00509 result[index] = (LineProperty)(result[index] | LINE_WRAPPED);
00510 }
00511 index++;
00512 }
00513
00514
00515 const int firstScreenLine = startLine + linesInHistory - history->getLines();
00516 for (int line = firstScreenLine; line < firstScreenLine+linesInScreen; line++)
00517 {
00518 result[index]=lineProperties[line];
00519 index++;
00520 }
00521
00522 return result;
00523 }
00524
00525 void Screen::reset(bool clearScreen)
00526 {
00527 setMode(MODE_Wrap ); saveMode(MODE_Wrap );
00528 resetMode(MODE_Origin); saveMode(MODE_Origin);
00529 resetMode(MODE_Insert); saveMode(MODE_Insert);
00530 setMode(MODE_Cursor);
00531 resetMode(MODE_Screen);
00532 resetMode(MODE_NewLine);
00533
00534 _topMargin=0;
00535 _bottomMargin=lines-1;
00536
00537 setDefaultRendition();
00538 saveCursor();
00539
00540 if ( clearScreen )
00541 clear();
00542 }
00543
00544 void Screen::clear()
00545 {
00546 clearEntireScreen();
00547 home();
00548 }
00549
00550 void Screen::backspace()
00551 {
00552 cuX = qMin(columns-1,cuX);
00553 cuX = qMax(0,cuX-1);
00554
00555 if (screenLines[cuY].size() < cuX+1)
00556 screenLines[cuY].resize(cuX+1);
00557
00558 if (BS_CLEARS)
00559 screenLines[cuY][cuX].character = ' ';
00560 }
00561
00562 void Screen::tab(int n)
00563 {
00564
00565 if (n == 0) n = 1;
00566 while((n > 0) && (cuX < columns-1))
00567 {
00568 cursorRight(1);
00569 while((cuX < columns-1) && !tabStops[cuX])
00570 cursorRight(1);
00571 n--;
00572 }
00573 }
00574
00575 void Screen::backtab(int n)
00576 {
00577
00578 if (n == 0) n = 1;
00579 while((n > 0) && (cuX > 0))
00580 {
00581 cursorLeft(1); while((cuX > 0) && !tabStops[cuX]) cursorLeft(1);
00582 n--;
00583 }
00584 }
00585
00586 void Screen::clearTabStops()
00587 {
00588 for (int i = 0; i < columns; i++) tabStops[i] = false;
00589 }
00590
00591 void Screen::changeTabStop(bool set)
00592 {
00593 if (cuX >= columns) return;
00594 tabStops[cuX] = set;
00595 }
00596
00597 void Screen::initTabStops()
00598 {
00599 tabStops.resize(columns);
00600
00601
00602
00603
00604 for (int i = 0; i < columns; i++)
00605 tabStops[i] = (i%8 == 0 && i != 0);
00606 }
00607
00608 void Screen::newLine()
00609 {
00610 if (getMode(MODE_NewLine))
00611 toStartOfLine();
00612 index();
00613 }
00614
00615 void Screen::checkSelection(int from, int to)
00616 {
00617 if (selBegin == -1)
00618 return;
00619 int scr_TL = loc(0, history->getLines());
00620
00621 if ( (selBottomRight > (from+scr_TL)) && (selTopLeft < (to+scr_TL)) )
00622 clearSelection();
00623 }
00624
00625 void Screen::displayCharacter(unsigned short c)
00626 {
00627
00628
00629
00630
00631
00632 int w = konsole_wcwidth(c);
00633 if (w <= 0)
00634 return;
00635
00636 if (cuX+w > columns) {
00637 if (getMode(MODE_Wrap)) {
00638 lineProperties[cuY] = (LineProperty)(lineProperties[cuY] | LINE_WRAPPED);
00639 nextLine();
00640 }
00641 else
00642 cuX = columns-w;
00643 }
00644
00645
00646 int size = screenLines[cuY].size();
00647 if (size == 0 && cuY > 0)
00648 {
00649 screenLines[cuY].resize( qMax(screenLines[cuY-1].size() , cuX+w) );
00650 }
00651 else
00652 {
00653 if (size < cuX+w)
00654 {
00655 screenLines[cuY].resize(cuX+w);
00656 }
00657 }
00658
00659 if (getMode(MODE_Insert)) insertChars(w);
00660
00661 lastPos = loc(cuX,cuY);
00662
00663
00664 checkSelection(cuX,cuY);
00665
00666 Character& currentChar = screenLines[cuY][cuX];
00667
00668 currentChar.character = c;
00669 currentChar.foregroundColor = effectiveForeground;
00670 currentChar.backgroundColor = effectiveBackground;
00671 currentChar.rendition = effectiveRendition;
00672
00673 int i = 0;
00674 int newCursorX = cuX + w--;
00675 while(w)
00676 {
00677 i++;
00678
00679 if ( screenLines[cuY].size() < cuX + i + 1 )
00680 screenLines[cuY].resize(cuX+i+1);
00681
00682 Character& ch = screenLines[cuY][cuX + i];
00683 ch.character = 0;
00684 ch.foregroundColor = effectiveForeground;
00685 ch.backgroundColor = effectiveBackground;
00686 ch.rendition = effectiveRendition;
00687
00688 w--;
00689 }
00690 cuX = newCursorX;
00691 }
00692
00693 void Screen::compose(const QString& )
00694 {
00695 Q_ASSERT( 0 );
00696
00697
00698
00699
00700
00701
00702
00703
00704 }
00705
00706 int Screen::scrolledLines() const
00707 {
00708 return _scrolledLines;
00709 }
00710 int Screen::droppedLines() const
00711 {
00712 return _droppedLines;
00713 }
00714 void Screen::resetDroppedLines()
00715 {
00716 _droppedLines = 0;
00717 }
00718 void Screen::resetScrolledLines()
00719 {
00720 _scrolledLines = 0;
00721 }
00722
00723 void Screen::scrollUp(int n)
00724 {
00725 if (n == 0) n = 1;
00726 if (_topMargin == 0) addHistLine();
00727 scrollUp(_topMargin, n);
00728 }
00729
00730 QRect Screen::lastScrolledRegion() const
00731 {
00732 return _lastScrolledRegion;
00733 }
00734
00735 void Screen::scrollUp(int from, int n)
00736 {
00737 if (n <= 0 || from + n > _bottomMargin) return;
00738
00739 _scrolledLines -= n;
00740 _lastScrolledRegion = QRect(0,_topMargin,columns-1,(_bottomMargin-_topMargin));
00741
00742
00743 moveImage(loc(0,from),loc(0,from+n),loc(columns-1,_bottomMargin));
00744 clearImage(loc(0,_bottomMargin-n+1),loc(columns-1,_bottomMargin),' ');
00745 }
00746
00747 void Screen::scrollDown(int n)
00748 {
00749 if (n == 0) n = 1;
00750 scrollDown(_topMargin, n);
00751 }
00752
00753 void Screen::scrollDown(int from, int n)
00754 {
00755 _scrolledLines += n;
00756
00757
00758 if (n <= 0)
00759 return;
00760 if (from > _bottomMargin)
00761 return;
00762 if (from + n > _bottomMargin)
00763 n = _bottomMargin - from;
00764 moveImage(loc(0,from+n),loc(0,from),loc(columns-1,_bottomMargin-n));
00765 clearImage(loc(0,from),loc(columns-1,from+n-1),' ');
00766 }
00767
00768 void Screen::setCursorYX(int y, int x)
00769 {
00770 setCursorY(y); setCursorX(x);
00771 }
00772
00773 void Screen::setCursorX(int x)
00774 {
00775 if (x == 0) x = 1;
00776 x -= 1;
00777 cuX = qMax(0,qMin(columns-1, x));
00778 }
00779
00780 void Screen::setCursorY(int y)
00781 {
00782 if (y == 0) y = 1;
00783 y -= 1;
00784 cuY = qMax(0,qMin(lines -1, y + (getMode(MODE_Origin) ? _topMargin : 0) ));
00785 }
00786
00787 void Screen::home()
00788 {
00789 cuX = 0;
00790 cuY = 0;
00791 }
00792
00793 void Screen::toStartOfLine()
00794 {
00795 cuX = 0;
00796 }
00797
00798 int Screen::getCursorX() const
00799 {
00800 return cuX;
00801 }
00802
00803 int Screen::getCursorY() const
00804 {
00805 return cuY;
00806 }
00807
00808 void Screen::clearImage(int loca, int loce, char c)
00809 {
00810 int scr_TL=loc(0,history->getLines());
00811
00812
00813
00814 if ( (selBottomRight > (loca+scr_TL) )&&(selTopLeft < (loce+scr_TL)) )
00815 {
00816 clearSelection();
00817 }
00818
00819 int topLine = loca/columns;
00820 int bottomLine = loce/columns;
00821
00822 Character clearCh(c,currentForeground,currentBackground,DEFAULT_RENDITION);
00823
00824
00825
00826 bool isDefaultCh = (clearCh == Character());
00827
00828 for (int y=topLine;y<=bottomLine;y++)
00829 {
00830 lineProperties[y] = 0;
00831
00832 int endCol = ( y == bottomLine) ? loce%columns : columns-1;
00833 int startCol = ( y == topLine ) ? loca%columns : 0;
00834
00835 QVector<Character>& line = screenLines[y];
00836
00837 if ( isDefaultCh && endCol == columns-1 )
00838 {
00839 line.resize(startCol);
00840 }
00841 else
00842 {
00843 if (line.size() < endCol + 1)
00844 line.resize(endCol+1);
00845
00846 Character* data = line.data();
00847 for (int i=startCol;i<=endCol;i++)
00848 data[i]=clearCh;
00849 }
00850 }
00851 }
00852
00853 void Screen::moveImage(int dest, int sourceBegin, int sourceEnd)
00854 {
00855 Q_ASSERT( sourceBegin <= sourceEnd );
00856
00857 int lines=(sourceEnd-sourceBegin)/columns;
00858
00859
00860
00861
00862
00863
00864 if (dest < sourceBegin)
00865 {
00866 for (int i=0;i<=lines;i++)
00867 {
00868 screenLines[ (dest/columns)+i ] = screenLines[ (sourceBegin/columns)+i ];
00869 lineProperties[(dest/columns)+i]=lineProperties[(sourceBegin/columns)+i];
00870 }
00871 }
00872 else
00873 {
00874 for (int i=lines;i>=0;i--)
00875 {
00876 screenLines[ (dest/columns)+i ] = screenLines[ (sourceBegin/columns)+i ];
00877 lineProperties[(dest/columns)+i]=lineProperties[(sourceBegin/columns)+i];
00878 }
00879 }
00880
00881 if (lastPos != -1)
00882 {
00883 int diff = dest - sourceBegin;
00884 lastPos += diff;
00885 if ((lastPos < 0) || (lastPos >= (lines*columns)))
00886 lastPos = -1;
00887 }
00888
00889
00890 if (selBegin != -1)
00891 {
00892 bool beginIsTL = (selBegin == selTopLeft);
00893 int diff = dest - sourceBegin;
00894 int scr_TL=loc(0,history->getLines());
00895 int srca = sourceBegin+scr_TL;
00896 int srce = sourceEnd+scr_TL;
00897 int desta = srca+diff;
00898 int deste = srce+diff;
00899
00900 if ((selTopLeft >= srca) && (selTopLeft <= srce))
00901 selTopLeft += diff;
00902 else if ((selTopLeft >= desta) && (selTopLeft <= deste))
00903 selBottomRight = -1;
00904
00905 if ((selBottomRight >= srca) && (selBottomRight <= srce))
00906 selBottomRight += diff;
00907 else if ((selBottomRight >= desta) && (selBottomRight <= deste))
00908 selBottomRight = -1;
00909
00910 if (selBottomRight < 0)
00911 {
00912 clearSelection();
00913 }
00914 else
00915 {
00916 if (selTopLeft < 0)
00917 selTopLeft = 0;
00918 }
00919
00920 if (beginIsTL)
00921 selBegin = selTopLeft;
00922 else
00923 selBegin = selBottomRight;
00924 }
00925 }
00926
00927 void Screen::clearToEndOfScreen()
00928 {
00929 clearImage(loc(cuX,cuY),loc(columns-1,lines-1),' ');
00930 }
00931
00932 void Screen::clearToBeginOfScreen()
00933 {
00934 clearImage(loc(0,0),loc(cuX,cuY),' ');
00935 }
00936
00937 void Screen::clearEntireScreen()
00938 {
00939
00940 for (int i = 0; i < (lines-1); i++)
00941 {
00942 addHistLine(); scrollUp(0,1);
00943 }
00944
00945 clearImage(loc(0,0),loc(columns-1,lines-1),' ');
00946 }
00947
00952 void Screen::helpAlign()
00953 {
00954 clearImage(loc(0,0),loc(columns-1,lines-1),'E');
00955 }
00956
00957 void Screen::clearToEndOfLine()
00958 {
00959 clearImage(loc(cuX,cuY),loc(columns-1,cuY),' ');
00960 }
00961
00962 void Screen::clearToBeginOfLine()
00963 {
00964 clearImage(loc(0,cuY),loc(cuX,cuY),' ');
00965 }
00966
00967 void Screen::clearEntireLine()
00968 {
00969 clearImage(loc(0,cuY),loc(columns-1,cuY),' ');
00970 }
00971
00972 void Screen::setRendition(int re)
00973 {
00974 currentRendition |= re;
00975 updateEffectiveRendition();
00976 }
00977
00978 void Screen::resetRendition(int re)
00979 {
00980 currentRendition &= ~re;
00981 updateEffectiveRendition();
00982 }
00983
00984 void Screen::setDefaultRendition()
00985 {
00986 setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
00987 setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
00988 currentRendition = DEFAULT_RENDITION;
00989 updateEffectiveRendition();
00990 }
00991
00992 void Screen::setForeColor(int space, int color)
00993 {
00994 currentForeground = CharacterColor(space, color);
00995
00996 if ( currentForeground.isValid() )
00997 updateEffectiveRendition();
00998 else
00999 setForeColor(COLOR_SPACE_DEFAULT,DEFAULT_FORE_COLOR);
01000 }
01001
01002 void Screen::setBackColor(int space, int color)
01003 {
01004 currentBackground = CharacterColor(space, color);
01005
01006 if ( currentBackground.isValid() )
01007 updateEffectiveRendition();
01008 else
01009 setBackColor(COLOR_SPACE_DEFAULT,DEFAULT_BACK_COLOR);
01010 }
01011
01012 void Screen::clearSelection()
01013 {
01014 selBottomRight = -1;
01015 selTopLeft = -1;
01016 selBegin = -1;
01017 }
01018
01019 void Screen::getSelectionStart(int& column , int& line) const
01020 {
01021 if ( selTopLeft != -1 )
01022 {
01023 column = selTopLeft % columns;
01024 line = selTopLeft / columns;
01025 }
01026 else
01027 {
01028 column = cuX + getHistLines();
01029 line = cuY + getHistLines();
01030 }
01031 }
01032 void Screen::getSelectionEnd(int& column , int& line) const
01033 {
01034 if ( selBottomRight != -1 )
01035 {
01036 column = selBottomRight % columns;
01037 line = selBottomRight / columns;
01038 }
01039 else
01040 {
01041 column = cuX + getHistLines();
01042 line = cuY + getHistLines();
01043 }
01044 }
01045 void Screen::setSelectionStart(const int x, const int y, const bool mode)
01046 {
01047 selBegin = loc(x,y);
01048
01049 if (x == columns) selBegin--;
01050
01051 selBottomRight = selBegin;
01052 selTopLeft = selBegin;
01053 blockSelectionMode = mode;
01054 }
01055
01056 void Screen::setSelectionEnd( const int x, const int y)
01057 {
01058 if (selBegin == -1)
01059 return;
01060
01061 int endPos = loc(x,y);
01062
01063 if (endPos < selBegin)
01064 {
01065 selTopLeft = endPos;
01066 selBottomRight = selBegin;
01067 }
01068 else
01069 {
01070
01071 if (x == columns)
01072 endPos--;
01073
01074 selTopLeft = selBegin;
01075 selBottomRight = endPos;
01076 }
01077
01078
01079 if (blockSelectionMode)
01080 {
01081 int topRow = selTopLeft / columns;
01082 int topColumn = selTopLeft % columns;
01083 int bottomRow = selBottomRight / columns;
01084 int bottomColumn = selBottomRight % columns;
01085
01086 selTopLeft = loc(qMin(topColumn,bottomColumn),topRow);
01087 selBottomRight = loc(qMax(topColumn,bottomColumn),bottomRow);
01088 }
01089 }
01090
01091 bool Screen::isSelected( const int x,const int y) const
01092 {
01093 bool columnInSelection = true;
01094 if (blockSelectionMode)
01095 {
01096 columnInSelection = x >= (selTopLeft % columns) &&
01097 x <= (selBottomRight % columns);
01098 }
01099
01100 int pos = loc(x,y);
01101 return pos >= selTopLeft && pos <= selBottomRight && columnInSelection;
01102 }
01103
01104 QString Screen::selectedText(bool preserveLineBreaks) const
01105 {
01106 QString result;
01107 QTextStream stream(&result, QIODevice::ReadWrite);
01108
01109 PlainTextDecoder decoder;
01110 decoder.begin(&stream);
01111 writeSelectionToStream(&decoder , preserveLineBreaks);
01112 decoder.end();
01113
01114 return result;
01115 }
01116
01117 bool Screen::isSelectionValid() const
01118 {
01119 return selTopLeft >= 0 && selBottomRight >= 0;
01120 }
01121
01122 void Screen::writeSelectionToStream(TerminalCharacterDecoder* decoder ,
01123 bool preserveLineBreaks) const
01124 {
01125 if (!isSelectionValid())
01126 return;
01127 writeToStream(decoder,selTopLeft,selBottomRight,preserveLineBreaks);
01128 }
01129
01130 void Screen::writeToStream(TerminalCharacterDecoder* decoder,
01131 int startIndex, int endIndex,
01132 bool preserveLineBreaks) const
01133 {
01134 int top = startIndex / columns;
01135 int left = startIndex % columns;
01136
01137 int bottom = endIndex / columns;
01138 int right = endIndex % columns;
01139
01140 Q_ASSERT( top >= 0 && left >= 0 && bottom >= 0 && right >= 0 );
01141
01142 for (int y=top;y<=bottom;y++)
01143 {
01144 int start = 0;
01145 if ( y == top || blockSelectionMode ) start = left;
01146
01147 int count = -1;
01148 if ( y == bottom || blockSelectionMode ) count = right - start + 1;
01149
01150 const bool appendNewLine = ( y != bottom );
01151 int copied = copyLineToStream( y,
01152 start,
01153 count,
01154 decoder,
01155 appendNewLine,
01156 preserveLineBreaks );
01157
01158
01159
01160
01161
01162
01163 if ( y == bottom &&
01164 copied < count )
01165 {
01166 Character newLineChar('\n');
01167 decoder->decodeLine(&newLineChar,1,0);
01168 }
01169 }
01170 }
01171
01172 int Screen::copyLineToStream(int line ,
01173 int start,
01174 int count,
01175 TerminalCharacterDecoder* decoder,
01176 bool appendNewLine,
01177 bool preserveLineBreaks) const
01178 {
01179
01180
01181
01182
01183 static const int MAX_CHARS = 1024;
01184 static Character characterBuffer[MAX_CHARS];
01185
01186 assert( count < MAX_CHARS );
01187
01188 LineProperty currentLineProperties = 0;
01189
01190
01191 if (line < history->getLines())
01192 {
01193 const int lineLength = history->getLineLen(line);
01194
01195
01196 start = qMin(start,qMax(0,lineLength-1));
01197
01198
01199
01200
01201 if (count == -1)
01202 {
01203 count = lineLength-start;
01204 }
01205 else
01206 {
01207 count = qMin(start+count,lineLength)-start;
01208 }
01209
01210
01211 assert( start >= 0 );
01212 assert( count >= 0 );
01213 assert( (start+count) <= history->getLineLen(line) );
01214
01215 history->getCells(line,start,count,characterBuffer);
01216
01217 if ( history->isWrappedLine(line) )
01218 currentLineProperties |= LINE_WRAPPED;
01219 }
01220 else
01221 {
01222 if ( count == -1 )
01223 count = columns - start;
01224
01225 assert( count >= 0 );
01226
01227 const int screenLine = line-history->getLines();
01228
01229 Character* data = screenLines[screenLine].data();
01230 int length = screenLines[screenLine].count();
01231
01232
01233 for (int i = length-1; i >= 0; i--)
01234 {
01235 if (data[i].character == ' ')
01236 length--;
01237 else
01238 break;
01239 }
01240
01241 for (int i=start;i < qMin(start+count,length);i++)
01242 {
01243 characterBuffer[i-start] = data[i];
01244 }
01245
01246
01247 count = qBound(0,count,length-start);
01248
01249 Q_ASSERT( screenLine < lineProperties.count() );
01250 currentLineProperties |= lineProperties[screenLine];
01251 }
01252
01253
01254 const bool omitLineBreak = (currentLineProperties & LINE_WRAPPED) ||
01255 !preserveLineBreaks;
01256
01257 if ( !omitLineBreak && appendNewLine && (count+1 < MAX_CHARS) )
01258 {
01259 characterBuffer[count] = '\n';
01260 count++;
01261 }
01262
01263
01264 decoder->decodeLine( (Character*) characterBuffer ,
01265 count, currentLineProperties );
01266
01267 return count;
01268 }
01269
01270 void Screen::writeLinesToStream(TerminalCharacterDecoder* decoder, int fromLine, int toLine) const
01271 {
01272 writeToStream(decoder,loc(0,fromLine),loc(columns-1,toLine));
01273 }
01274
01275 void Screen::addHistLine()
01276 {
01277
01278
01279
01280 if (hasScroll())
01281 {
01282 int oldHistLines = history->getLines();
01283
01284 history->addCellsVector(screenLines[0]);
01285 history->addLine( lineProperties[0] & LINE_WRAPPED );
01286
01287 int newHistLines = history->getLines();
01288
01289 bool beginIsTL = (selBegin == selTopLeft);
01290
01291
01292
01293 if ( newHistLines == oldHistLines )
01294 _droppedLines++;
01295
01296
01297 if (newHistLines > oldHistLines)
01298 {
01299 if (selBegin != -1)
01300 {
01301 selTopLeft += columns;
01302 selBottomRight += columns;
01303 }
01304 }
01305
01306 if (selBegin != -1)
01307 {
01308
01309 int top_BR = loc(0, 1+newHistLines);
01310
01311 if (selTopLeft < top_BR)
01312 selTopLeft -= columns;
01313
01314 if (selBottomRight < top_BR)
01315 selBottomRight -= columns;
01316
01317 if (selBottomRight < 0)
01318 clearSelection();
01319 else
01320 {
01321 if (selTopLeft < 0)
01322 selTopLeft = 0;
01323 }
01324
01325 if (beginIsTL)
01326 selBegin = selTopLeft;
01327 else
01328 selBegin = selBottomRight;
01329 }
01330 }
01331
01332 }
01333
01334 int Screen::getHistLines() const
01335 {
01336 return history->getLines();
01337 }
01338
01339 void Screen::setScroll(const HistoryType& t , bool copyPreviousScroll)
01340 {
01341 clearSelection();
01342
01343 if ( copyPreviousScroll )
01344 history = t.scroll(history);
01345 else
01346 {
01347 HistoryScroll* oldScroll = history;
01348 history = t.scroll(0);
01349 delete oldScroll;
01350 }
01351 }
01352
01353 bool Screen::hasScroll() const
01354 {
01355 return history->hasScroll();
01356 }
01357
01358 const HistoryType& Screen::getScroll() const
01359 {
01360 return history->getType();
01361 }
01362
01363 void Screen::setLineProperty(LineProperty property , bool enable)
01364 {
01365 if ( enable )
01366 lineProperties[cuY] = (LineProperty)(lineProperties[cuY] | property);
01367 else
01368 lineProperties[cuY] = (LineProperty)(lineProperties[cuY] & ~property);
01369 }
01370 void Screen::fillWithDefaultChar(Character* dest, int count)
01371 {
01372 for (int i=0;i<count;i++)
01373 dest[i] = defaultChar;
01374 }