commands/fed/src/lrtextview.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // lrtextview.cpp
       
     2 // 
       
     3 // Copyright (c) 2009 - 2010 Accenture. All rights reserved.
       
     4 // This component and the accompanying materials are made available
       
     5 // under the terms of the "Eclipse Public License v1.0"
       
     6 // which accompanies this distribution, and is available
       
     7 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 // 
       
     9 // Initial Contributors:
       
    10 // Accenture - Initial contribution
       
    11 //
       
    12 
       
    13 #include "lrtextview.h"
       
    14 #include <e32cons.h>
       
    15 #include "filebuffer.h"
       
    16 #include <fshell/common.mmh>
       
    17 #include <fshell/ltkutils.h>
       
    18 
       
    19 const TInt KLastCtrlChar = 0x1f;	//Last control char in ASCII
       
    20 const TInt KCtrlHTab = 0x09;		//Horizontal Tab
       
    21 
       
    22 CLRTextView* CLRTextView::NewL(MConsoleProvider& aConsoleProvider, CFedBufferBase& aBuffer)
       
    23 	{
       
    24 	CLRTextView* self = new (ELeave) CLRTextView(aConsoleProvider, aBuffer);
       
    25 	CleanupStack::PushL(self);
       
    26 	self->ConstructL();
       
    27 	CleanupStack::Pop(self);
       
    28 	return self;
       
    29 	}
       
    30 
       
    31 CLRTextView::~CLRTextView()
       
    32 	{
       
    33 	delete iLineData;
       
    34 	delete iMarkFlasher;
       
    35 	}
       
    36 
       
    37 CLRTextView::CLRTextView(MConsoleProvider& aConsoleProvider, CFedBufferBase& aBuffer)
       
    38 	: CTextView(aConsoleProvider, aBuffer), iMarkDocPos(-1), iOldNextLine(-1)
       
    39 	{
       
    40 	}
       
    41 
       
    42 void CLRTextView::ConstructL()
       
    43 	{
       
    44 	iLineData = new(ELeave) CLineData;
       
    45 	CTextView::ConstructL();
       
    46 	iMarkFlasher = CPeriodic::NewL(CActive::EPriorityStandard);
       
    47 	}
       
    48 
       
    49 //MDeferredClose
       
    50 TBool CLRTextView::TryCloseL()
       
    51 	{
       
    52 	if (!iBuffer.Modified())
       
    53 		{
       
    54 		return ETrue; // Ok to close now
       
    55 		}
       
    56 	else
       
    57 		{
       
    58 		TKeyCode ch = iConsoleProvider.Query(_L("Save changes to file? (yes/no/cancel) "), _L("ync\x1B"));
       
    59 		if (ch == 'c' || ch == EKeyEscape) return EFalse;
       
    60 		if (ch == 'y')
       
    61 			{
       
    62 			TInt err = Save();
       
    63 			if (err) return EFalse; // Don't allow exit if the save failed
       
    64 			}
       
    65 		return ETrue;
       
    66 		}
       
    67 	}
       
    68 
       
    69 TInt CLRTextView::Save()
       
    70 	{
       
    71 	if (!iBuffer.Editable() || iLineIsErrorMessage) return KErrNotSupported;
       
    72 	
       
    73 	CancelMark();
       
    74 	TBool wasOpen = iBuffer.IsOpen();
       
    75 	TInt err = KErrNone;
       
    76 	const TDesC& name = iBuffer.Title();
       
    77 	if (name.Length())
       
    78 		{
       
    79 		iConsoleProvider.InfoPrint(_L("Saving"));
       
    80 		TRAP(err, iBuffer.SaveL(name, ETrue));
       
    81 		HandleSaveResult(err, wasOpen, iBuffer.Title());
       
    82 		return err;
       
    83 		}
       
    84 	else
       
    85 		{
       
    86 		return SaveAs();
       
    87 		}
       
    88 	}
       
    89 
       
    90 TInt CLRTextView::SaveAs()
       
    91 	{
       
    92 	if (!iBuffer.Editable() || iLineIsErrorMessage) return KErrNotSupported;
       
    93 	
       
    94 	CancelMark();
       
    95 	TBool wasOpen = iBuffer.IsOpen();
       
    96 	TFileName name = iBuffer.Title();
       
    97 	TInt err = KErrCancel;
       
    98 	TBool go = iConsoleProvider.QueryFilename(_L("Save as: "), name);
       
    99 	if (go)
       
   100 		{
       
   101 		iConsoleProvider.InfoPrint(_L("Saving"));
       
   102 		TRAP(err, iBuffer.SaveL(name, EFalse));
       
   103 		if (err == KErrAlreadyExists)
       
   104 			{
       
   105 			if (iConsoleProvider.Query(_L("File already exists. Replace? (yes/no) "), _L("yn")) == 'y')
       
   106 				{
       
   107 				iConsoleProvider.InfoPrint(_L("Saving"));
       
   108 				TRAP(err, iBuffer.SaveL(name, ETrue));
       
   109 				}
       
   110 			}
       
   111 		HandleSaveResult(err, wasOpen, iBuffer.Title());
       
   112 		}
       
   113 	return err;
       
   114 	}
       
   115 
       
   116 void CLRTextView::HandleSaveResult(TInt aError, TBool aWasOpen, const TDesC& aName)
       
   117 	{
       
   118 	if (aError == KErrNone)
       
   119 		{
       
   120 		TRAP_IGNORE(DoRedrawL()); // Not only can QueryFilename mess up the screen, saving the file could change the line endings and thus change the character counts, meaning we need to recalculate & redraw
       
   121 		iConsoleProvider.InfoPrint(_L("Save succeeded"));
       
   122 		}
       
   123 	else if (aWasOpen && !iBuffer.IsOpen())
       
   124 		{
       
   125 		// An error occurred after the original file was closed. This is fatal so we need to put up a dialog to that effect
       
   126 		iLine.Format(_L("Temp file @ %S"), &aName);
       
   127 		iLineIsErrorMessage = ETrue;
       
   128 		UpdateStatus();
       
   129 		iConsoleProvider.InfoPrint(_L("Failed to rename temp file (%d)"), aError);
       
   130 		}
       
   131 	else
       
   132 		{
       
   133 		// Failed to save, but we didn't mess with the original so we can carry on using it
       
   134 		TRAP_IGNORE(DoRedrawL()); // Not only can QueryFilename mess up the screen, saving the file could change the line endings and thus change the character counts, meaning we need to recalculate & redraw
       
   135 		switch (aError)
       
   136 			{
       
   137 			case KErrDiskFull:
       
   138 				iConsoleProvider.InfoPrint(_L("Disk full, couldn't save file"));
       
   139 				break;
       
   140 			case KErrNoMemory:
       
   141 				iConsoleProvider.InfoPrint(_L("Out of memory!"));
       
   142 				break;
       
   143 			case KErrPathNotFound:
       
   144 				iConsoleProvider.InfoPrint(_L("KErrPathNotFound. Directory doesn't exist?"));
       
   145 				break;
       
   146 			case KErrGeneral:
       
   147 				iConsoleProvider.InfoPrint(_L("Couldn't save file. No idea why"));
       
   148 				break;
       
   149 			case KErrBadName:
       
   150 				iConsoleProvider.InfoPrint(_L("Bad file name"));
       
   151 				break;
       
   152 			case KErrAccessDenied:
       
   153 				iConsoleProvider.InfoPrint(_L("Access denied. Read-only file or disk?"));
       
   154 				break;
       
   155 			default:
       
   156 				iConsoleProvider.InfoPrint(_L("Unable to save file: %d"), aError);
       
   157 				break;
       
   158 			}
       
   159 		}
       
   160 	}
       
   161 
       
   162 //MKeyConsumer
       
   163 TBool CLRTextView::ConsumeKeyL(const TKeyCode& aCode)
       
   164 	{
       
   165 	TBool handled = ETrue;
       
   166 	switch(aCode)
       
   167 		{
       
   168 		case EKeyUpArrow:
       
   169 			MoveCursor(0, -1); break;
       
   170 		case EKeyDownArrow:
       
   171 			MoveCursor(0, 1); break;
       
   172 		case EKeyLeftArrow:
       
   173 			MoveCursor(-1, 0); break;
       
   174 		case EKeyRightArrow:
       
   175 			MoveCursor(1, 0); break;
       
   176 		case EKeyPageUp:
       
   177 		case CTRL('u'):
       
   178 			MoveCursor(0, -iWindow.iHeight); break;
       
   179 		case EKeyPageDown:
       
   180 		case CTRL('d'):
       
   181 			MoveCursor(0, iWindow.iHeight); break;
       
   182 		case EKeyHome:
       
   183 			UpdateCursor(TPoint(0, iCursor.iY));
       
   184 			break;
       
   185 		case CTRL('t'):
       
   186 			iCursor.SetXY(0, 0);
       
   187 			RequestData(ETrue, 0); break;
       
   188 		case CTRL('b'):
       
   189 			GoToLine(KMaxTInt); break;
       
   190 		case EKeyEnd:
       
   191 			{
       
   192 			TInt pos = iLineData->LastValidPosition(iCursor.iY);
       
   193 			UpdateCursor(TPoint(pos, iCursor.iY));
       
   194 			break;
       
   195 			}
       
   196 		case EKeyBackspace:
       
   197 			DeleteTextL(-1);
       
   198 			break;
       
   199 		case EKeyDelete:
       
   200 			DeleteTextL(1);
       
   201 			break;
       
   202 		case CTRL('s'):
       
   203 			Save();
       
   204 			break;
       
   205 		case CTRL('a'):
       
   206 			SaveAs();
       
   207 			break;
       
   208 		case CTRL('k'):
       
   209 			DeleteCurrentLineL();
       
   210 			break;
       
   211 		case CTRL('g'):
       
   212 			GoToLine();
       
   213 			break;
       
   214 		case CTRL('f'):
       
   215 			Find();
       
   216 			break;
       
   217 		case CTRL('v'):
       
   218 			PasteL();
       
   219 			break;
       
   220 		case CTRL('c'):
       
   221 			if (MarkActive()) CopyOrCutL(EFalse);
       
   222 			else SetMark();
       
   223 			break;
       
   224 		case CTRL('x'):
       
   225 			if (MarkActive()) CopyOrCutL(ETrue);
       
   226 			else SetMark();
       
   227 			break;
       
   228 		default:
       
   229 			handled = EFalse;
       
   230 			break;
       
   231 		}
       
   232 
       
   233 	if (!handled && (aCode == EKeyEnter || aCode == EKeyTab || TChar(aCode).IsPrint()))
       
   234 		{
       
   235 		TBuf<1> buf;
       
   236 		buf.Append(aCode);
       
   237 		InsertTextL(buf);
       
   238 		handled = ETrue;
       
   239 		}
       
   240 	return handled;
       
   241 }
       
   242 
       
   243 void CLRTextView::MoveCursor(TInt aX, TInt aY)
       
   244 	{
       
   245 	if (aX) ASSERT(aY == 0);
       
   246 	if (aY) ASSERT(aX == 0); // Can't handle moving in both axes at once
       
   247 
       
   248 	TInt line = iCursor.iY;
       
   249 	TInt dir = (aX > 0) ? 1 : -1;
       
   250 	TInt newX = iCursor.iX;
       
   251 	while (aX)
       
   252 		{
       
   253 		newX += dir;
       
   254 		if (newX < 0)
       
   255 			{
       
   256 			// Move to end of previous line
       
   257 			newX = iWindow.iWidth; // Validate cursor will fix this, in the case where this causes us to scroll up a line
       
   258 			aY--;
       
   259 			break; // We don't really support seeking further than one line either way
       
   260 			}
       
   261 		else if (newX >= iWindow.iWidth-1)
       
   262 			{
       
   263 			// Move to start of next line
       
   264 			newX = 0;
       
   265 			aY++;
       
   266 			break; // We don't really support seeking further than one line either way
       
   267 			}
       
   268 
       
   269 		if (iLineData->IsScreenPositionValid(line, newX))
       
   270 			{
       
   271 			aX -= dir;
       
   272 			}
       
   273 		}
       
   274 
       
   275 	if (line + aY < 0)
       
   276 		{
       
   277 		// Scroll up
       
   278 		SeekData(iLineData->DocumentPosition(0), aY);
       
   279 		}
       
   280 	else if (line + aY >= iWindow.iHeight)
       
   281 		{
       
   282 		// Scroll down
       
   283 		SeekData(iLineData->DocumentPosition(0), aY);
       
   284 		}
       
   285 	else
       
   286 		{
       
   287 		// Just update cursor
       
   288 		if (iLineData->IsScreenPositionValid(line + aY, 0))
       
   289 			{
       
   290 			// If the line len is -1 it means the doc doesn't extend as far as this line, therefore we shouldn't allow the cursor to be moved to it
       
   291 			UpdateCursor(TPoint(newX, iCursor.iY + aY));
       
   292 			}
       
   293 		}
       
   294 	}
       
   295 
       
   296 void CLRTextView::DoResizeL(const TWindow& /*aOldWindow*/)
       
   297 	{
       
   298 	DoRedrawL();
       
   299 	}
       
   300 
       
   301 void CLRTextView::DoRedrawL()
       
   302 	{
       
   303 	iLineData->EnsureCapacityL(iWindow.iWidth, iWindow.iHeight);
       
   304 	ValidateCursor();
       
   305 	RequestData(ETrue, iLineData->DocumentPosition(0));
       
   306 	}
       
   307 
       
   308 void CLRTextView::DoDrawL()
       
   309 	{
       
   310 	DoDrawL(iRecursiveUpdateFlag ? *iRecursiveUpdateFlag : ETrue);
       
   311 	}
       
   312 
       
   313 void CLRTextView::DoDrawL(TBool aUpdateCursorAndStatus)
       
   314 	{
       
   315 	if (iDrawPoint == TPoint(iWindow.iX, iWindow.iY))
       
   316 		{
       
   317 		iLineData->SetDocumentPositionForLine(0, iRange.iLocation);
       
   318 		iLineData->SetFileLineNumberForLine(0, iRangeStartLineNumber);
       
   319 		}
       
   320 
       
   321 	ASSERT(iRange.iLength == iDes.Length());
       
   322 	HideCursor(); // Don't show the cursor while we're moving it around drawing - will be shown again by UpdateCursor
       
   323 	for (iCurrentDrawDocIndex = 0; iCurrentDrawDocIndex < iDes.Length(); iCurrentDrawDocIndex++)
       
   324 		{
       
   325 		TUint16 c = iDes[iCurrentDrawDocIndex];
       
   326 		if(iDrawPoint.iY >= iWindow.NextY())
       
   327 			{
       
   328 			break;
       
   329 			}
       
   330 		if(c <= KLastCtrlChar)
       
   331 			HandleControlChar();
       
   332 		else
       
   333 			AppendChar(c);
       
   334 		}
       
   335 
       
   336 	TBool moreData = !iBuffer.DocumentPositionIsEof(iRange.Max());
       
   337 	TBool filledScreen = iDrawPoint.iY >= iWindow.NextY();
       
   338 	if (!filledScreen)
       
   339 		{
       
   340 		WriteChars();
       
   341 		LineFinished();
       
   342 		}
       
   343 	if (!moreData)
       
   344 		{
       
   345 		iDrawPoint.iY++; // Start from the line *after* the line we were on
       
   346 		// In the case where we've finished writing but haven't filled the screen, we need to blank the rest of it (because to avoid flicker we don't do ClearScreens)
       
   347 		while (iDrawPoint.iY < iWindow.NextY())
       
   348 			{
       
   349 			iDrawPoint.iX = iWindow.iX;
       
   350 			iLine.Copy(_L("^"));
       
   351 			WriteChars();
       
   352 			TInt lineNum = iDrawPoint.iY - iWindow.iY;
       
   353 			iLineData->SetDocumentPositionForLine(lineNum+1, iLineData->DocumentPosition(lineNum));
       
   354 			iLineData->SetFileLineNumberForLine(lineNum, -1);
       
   355 			iLineData->LineFinishedAt(lineNum, -1);
       
   356 			iDrawPoint.iY++;
       
   357 			}
       
   358 		}
       
   359 
       
   360 	if (filledScreen || !moreData)
       
   361 		{
       
   362 		// Finished - null iDes and restore cursor
       
   363 		iDes.Set(NULL, 0);
       
   364 		if (aUpdateCursorAndStatus)
       
   365 			{
       
   366 			UpdateCursor(iCursor);
       
   367 			}
       
   368 		}
       
   369 	else
       
   370 		{
       
   371 		TBool flagSet = EFalse;
       
   372 		if (!iRecursiveUpdateFlag)
       
   373 			{
       
   374 			iRecursiveUpdateFlag = &aUpdateCursorAndStatus;
       
   375 			flagSet = ETrue;
       
   376 			}
       
   377 		// More data needed to fill the screen
       
   378 		RequestData(EFalse, iRange.Max());
       
   379 		if (flagSet) iRecursiveUpdateFlag = NULL;
       
   380 		}
       
   381 }
       
   382 
       
   383 void CLRTextView::ValidateCursor()
       
   384 	{	
       
   385 	CTextView::ValidateCursor();
       
   386 	TInt maxX = iWindow.iWidth - 1;
       
   387 	TInt line = iCursor.iY;
       
   388 	while (iCursor.iX > 0 && !iLineData->IsScreenPositionValid(line, iCursor.iX))
       
   389 		{
       
   390 		// In case the cursor ended up in the dead space in the middle of a tab character
       
   391 		iCursor.iX--;
       
   392 		}
       
   393 	while (line > 0 && !iLineData->IsScreenPositionValid(line, 0))
       
   394 		{
       
   395 		// In case the cursor has ended up in dead space
       
   396 		iCursor.iY--;
       
   397 		line--;
       
   398 		}
       
   399 	maxX = iLineData->LastValidPosition(line);
       
   400 	if(iCursor.iX > maxX)
       
   401 		iCursor.iX = maxX;
       
   402 	}
       
   403 
       
   404 void CLRTextView::HandleControlChar()
       
   405 	{
       
   406 	TUint8 c = iDes[iCurrentDrawDocIndex];
       
   407 	if (c == KCtrlHTab)
       
   408 		{
       
   409 		TInt pos = iDrawPoint.iX - iWindow.iX + iLine.Length();
       
   410 		TInt numToWrite = TabWidth() - (pos % TabWidth()); // Tabs align to 4-column boundaries rather than just outputting 4 spaces
       
   411 		numToWrite = Min(numToWrite, iWindow.iWidth-1-pos); // In case the tab causes a line continuation, we want to make sure the tab ends at the end of the line so the following character will start at column zero
       
   412 		for(TInt i=0; i<numToWrite; i++)
       
   413 			{
       
   414 			TInt line = iDrawPoint.iY - iWindow.iY;
       
   415 			TInt col = iDrawPoint.iX - iWindow.iX + iLine.Length();
       
   416 			AppendChar(' ');
       
   417 			if (i > 0) iLineData->SetPositionIsValid(line, col, EFalse); // i==0 (ie the first screen position of the tab) is a valid place to move the cursor to
       
   418 			}
       
   419 		}
       
   420 	else if (c == '\r')
       
   421 		{
       
   422 		if (iCurrentDrawDocIndex+1 < iDes.Length() && iDes[iCurrentDrawDocIndex+1] == '\n') iCurrentDrawDocIndex++; // Skip over the CR to the LF
       
   423 		WriteLine();
       
   424 		}
       
   425 	else if (c == '\n')
       
   426 		{
       
   427 		WriteLine();
       
   428 		}
       
   429 	else
       
   430 		{
       
   431 		// unknown control char - so escape it
       
   432 		AppendChar('.');
       
   433 		}
       
   434 	}
       
   435 
       
   436 void CLRTextView::AppendChar(TUint16 aChar)
       
   437 	{
       
   438 	iLine.Append(TChar(aChar));
       
   439 	iLineData->SetPositionIsValid(iDrawPoint.iY - iWindow.iY, iDrawPoint.iX - iWindow.iX + iLine.Length(), ETrue);
       
   440 	if(iDrawPoint.iX + iLine.Length() == iWindow.NextX()-1)
       
   441 		{
       
   442 		WriteChars();
       
   443 		WriteLineContinue();
       
   444 		GoToNextLine();
       
   445 		}
       
   446 	}
       
   447 
       
   448 //Writes the current line on the screen and moves to the next verse and line
       
   449 void CLRTextView::WriteLine()
       
   450 	{
       
   451 	TInt thisLine = iDrawPoint.iY-iWindow.iY;
       
   452 	WriteChars();
       
   453 	GoToNextLine();
       
   454 	iLineData->SetFileLineNumberForLine(thisLine+1, iLineData->FileLineNumber(thisLine) + 1);
       
   455 	if (iOldNextLine != -1 && thisLine+1 == iOldNextLine && iLineData->DocumentPosition(iOldNextLine) == iOldNextLineDocPos + iPredictedOldNextLineDocPosDelta)
       
   456 		{
       
   457 		// We have drawn everything we need to, and the drawing didn't cause the former next line to move
       
   458 		iDrawPoint.iY = iWindow.NextY();
       
   459 		UpdateDocumentPositionsStartingAtLine(iOldNextLine+1, iPredictedOldNextLineDocPosDelta);
       
   460 		}
       
   461 	iOldNextLine = -1;
       
   462 	}
       
   463 
       
   464 //Writes the current line on the screen
       
   465 void CLRTextView::WriteChars()
       
   466 	{
       
   467 	/* As an performance optimisation, we avoid calling ClearScreen when redrawing. Therefore we must ensure we 
       
   468 	 * write to the entire line to prevent artifacts. 
       
   469 	 *
       
   470 	 * There are 2 approaches to this - either using CConsoleBase::ClearToEndOfLine or padding the line with 
       
   471 	 * spaces up to the window width. ClearToEndOfLine is really slow in WINSCW tshell which is why it's not
       
   472 	 * used by default. On target it's probably more efficient to use it.
       
   473 	 */
       
   474 	TPoint drawPoint(iDrawPoint);
       
   475 	TPoint endPoint(drawPoint.iX + iLine.Length(), drawPoint.iY);
       
   476 	iConsole.SetCursorPosAbs(drawPoint);
       
   477 #ifdef FSHELL_WSERV_SUPPORT
       
   478 // text windowserver is really slow at ClearToEndOfLine
       
   479 #define USE_CLEARTOENDOFLINE
       
   480 #endif
       
   481 #ifdef USE_CLEARTOENDOFLINE
       
   482 	iConsole.Write(iLine);
       
   483 	iConsole.ClearToEndOfLine();
       
   484 #else
       
   485 	iLine.AppendFill(' ', iWindow.iWidth - (iDrawPoint.iX-iWindow.iX) - iLine.Length());
       
   486 	iConsole.Write(iLine);
       
   487 #endif
       
   488 	iLine.Zero();
       
   489 	// Remember to reset the console pos and the drawpoint to the end of the line proper in case the WriteChars 
       
   490 	// was to half a line and the rest of the line is in another block.
       
   491 	iDrawPoint = endPoint;
       
   492 	iConsole.SetCursorPosAbs(iDrawPoint);
       
   493 	}
       
   494 
       
   495 // Moves to the next screen line but doesn't move to the next file line (used when a line is longer than the width of the window)
       
   496 void CLRTextView::GoToNextLine()
       
   497 	{
       
   498 	LineFinished();
       
   499 	iDrawPoint.iX = iWindow.iX;
       
   500 	iDrawPoint.iY++;
       
   501 	iLineData->SetPositionIsValid(iDrawPoint.iY-iWindow.iY, 0, ETrue);
       
   502 	}
       
   503 
       
   504 void CLRTextView::LineFinished()
       
   505 	{
       
   506 	TInt currentLine = iDrawPoint.iY - iWindow.iY;
       
   507 	if (currentLine == iWindow.iHeight) return; // This can happen (and is ok) when drawing the last line of the screen
       
   508 	iLineData->LineFinishedAt(currentLine, iDrawPoint.iX - iWindow.iX);
       
   509 	iLineData->SetDocumentPositionForLine(currentLine+1, iRange.iLocation+iCurrentDrawDocIndex+1); // Plus one cos we haven't drawn the first character of the next line yet
       
   510 	}
       
   511 
       
   512 void CLRTextView::WriteLineContinue()
       
   513 	{
       
   514 	CColorConsoleBase* cons = iConsoleProvider.ColorConsole();
       
   515 	if (cons) cons->SetTextAttribute(ETextAttributeHighlight);
       
   516 	_LIT(KContinuation, "\\");
       
   517 	iConsole.Write(KContinuation);
       
   518 	if (cons) cons->SetTextAttribute(ETextAttributeNormal);
       
   519 
       
   520 	TInt thisLine = iDrawPoint.iY-iWindow.iY;
       
   521 	iLineData->SetFileLineNumberForLine(thisLine+1, iLineData->FileLineNumber(thisLine)); // The new line has the same file number as the current line, because it's a continuation line
       
   522 	}
       
   523 
       
   524 TInt CLRTextView::DocumentPosition() const
       
   525 	{
       
   526 	TInt line = iCursor.iY;
       
   527 	TInt pos = iLineData->DocumentPosition(line);
       
   528 	for (TInt i = 0; i < iCursor.iX; i++)
       
   529 		{
       
   530 		if (iLineData->IsScreenPositionValid(line, i)) pos++;
       
   531 		}
       
   532 	return pos;
       
   533 	}
       
   534 
       
   535 void CLRTextView::InsertTextL(const TDesC& aText)
       
   536 	{
       
   537 	if (!iBuffer.Editable() || iLineIsErrorMessage) return;
       
   538 	
       
   539 	CancelMark();
       
   540 	TInt pos = DocumentPosition();
       
   541 	iBuffer.InsertTextL(pos, aText);
       
   542 	if (iCursor.iX == iWindow.iWidth-1)
       
   543 		{
       
   544 		// If the cursor is over a line continuation character (which it will be if it gets to this value) move cursor to the real insertion point at the start of the next line before doing anything - makes the logic much easier!
       
   545 		MoveCursor(1, 0);
       
   546 		}
       
   547 
       
   548 	// If we can be sure it won't cause a reflow, shortcut the requesting and redrawing mechanism, for performance reasons
       
   549 	TPoint cursorPos = WindowLocationForDocumentPosition(pos);
       
   550 	TInt lineNum = cursorPos.iY;
       
   551 	TBool posWasAtEndOfLine = cursorPos.iX == iLineData->LastValidPosition(lineNum) && cursorPos.iX + aText.Length() < iWindow.iWidth-1;
       
   552 	if (posWasAtEndOfLine && aText.Locate('\t') == KErrNotFound && aText.Locate('\r') == KErrNotFound)
       
   553 		{
       
   554 		// Can't optimise if the text contains tabs or newlines, we need to do the full algorithm in that case
       
   555 		iConsole.Write(aText);
       
   556 		for (TInt i = 0; i < aText.Length(); i++)
       
   557 			{
       
   558 			iLineData->SetPositionIsValid(lineNum, cursorPos.iX + 1 + i, ETrue); // Each added char makes the character position one after that character valid
       
   559 			}
       
   560 		for (TInt l = lineNum+1; l <= iWindow.iHeight; l++)
       
   561 			{
       
   562 			iLineData->SetDocumentPositionForLine(l, iLineData->DocumentPosition(l) + aText.Length());
       
   563 			}
       
   564 		MoveCursor(aText.Length(),0);
       
   565 		}
       
   566 	else
       
   567 		{
       
   568 		RedrawFromPositionToEndOfLine(pos, aText.Length());
       
   569 		CenterDocPosOnScreen(pos + aText.Length());
       
   570 		}
       
   571 	}
       
   572 
       
   573 void CLRTextView::RedrawFromPositionToEndOfLine(TInt aDocumentPosition, TInt aNumCharsInserted)
       
   574 	{
       
   575 	TPoint point = WindowLocationForDocumentPosition(aDocumentPosition);
       
   576 	ASSERT(point.iY >= 0);
       
   577 	iDrawPoint = point + iWindow.Origin();
       
   578 	// Try and avoid redrawing the whole screen if the RequestData doesn't make the line longer (in terms of screen lines)
       
   579 	TInt lastScreenLineForCurrentLine = point.iY;
       
   580 	while (iLineData->FileLineNumber(lastScreenLineForCurrentLine+1) == iLineData->FileLineNumber(lastScreenLineForCurrentLine))
       
   581 		{
       
   582 		// We have to allow for the current line wrapping onto additional screen lines
       
   583 		lastScreenLineForCurrentLine++;
       
   584 		}
       
   585 	iOldNextLine = lastScreenLineForCurrentLine + 1;
       
   586 	iOldNextLineDocPos = iLineData->DocumentPosition(iOldNextLine);
       
   587 	iPredictedOldNextLineDocPosDelta = aNumCharsInserted;
       
   588 	RequestData(EFalse, aDocumentPosition);
       
   589 	}
       
   590 
       
   591 void CLRTextView::DeleteTextL(TInt aNumChars)
       
   592 	{
       
   593 	if (!iBuffer.Editable() || iLineIsErrorMessage) return;
       
   594 
       
   595 	CancelMark();
       
   596 	ASSERT(aNumChars >= -1); // Can't backspace more than one character
       
   597 	TInt pos = DocumentPosition();
       
   598 	TRange range;
       
   599 	if (aNumChars < 0)
       
   600 		range = TRange(pos + aNumChars, -aNumChars);
       
   601 	else
       
   602 		range = TRange(pos, aNumChars);
       
   603 	range.Intersect(TRange(0, KMaxTInt)); // Clamp the range to zero
       
   604 
       
   605 	if (range.iLength)
       
   606 		{
       
   607 		iBuffer.DeleteTextL(range);
       
   608 		TInt line = iCursor.iY;
       
   609 		if (aNumChars == -1) MoveCursor(-1, 0);
       
   610 		// Seems to be an issue using RedrawFromPositionToEndOfLine when deleting from the start of a line - since we know it wouldn't be worth using it in that case, don't do it.
       
   611 		if (iCursor.iY == line && aNumChars == -1)
       
   612 			{
       
   613 			RedrawFromPositionToEndOfLine(range.iLocation, -range.iLength);
       
   614 			}
       
   615 		else
       
   616 			{
       
   617 			iDrawPoint = iCursor + iWindow.Origin();
       
   618 			RequestData(EFalse, DocumentPosition());
       
   619 			}
       
   620 		}
       
   621 	}
       
   622 
       
   623 void CLRTextView::DeleteCurrentLineL()
       
   624 	{
       
   625 	if (!iBuffer.Editable() || iLineIsErrorMessage) return;
       
   626 
       
   627 	CancelMark();
       
   628 	TInt currentLine = iCursor.iY;
       
   629 	TInt lineStart = iLineData->DocumentPosition(currentLine);
       
   630 	TInt lineLen = iLineData->DocumentPosition(currentLine+1) - lineStart;
       
   631 	if (lineLen > 0)
       
   632 		{
       
   633 		TRange range(lineStart, lineLen);
       
   634 		iBuffer.DeleteTextL(range);
       
   635 		iDrawPoint = TPoint(iWindow.iX, iWindow.iY + iCursor.iY);
       
   636 		RequestData(EFalse, lineStart);
       
   637 		}
       
   638 	}
       
   639 
       
   640 void CLRTextView::UpdateCursor(const TPoint& aNewPos)
       
   641 	{
       
   642 	CTextView::UpdateCursor(aNewPos);
       
   643 	UpdateStatus();
       
   644 	}
       
   645 
       
   646 void CLRTextView::UpdateStatus()
       
   647 	{
       
   648 	if (iLineIsErrorMessage)
       
   649 		{
       
   650 		iConsoleProvider.WriteStatus(iLine, KNullDesC);
       
   651 		return;
       
   652 		}
       
   653 
       
   654 	_LIT(KUnknownDelim, "CRLF"); // Since that's what it will get output as
       
   655 	_LIT(KUnknownEnc, "UTF-8"); // ditto
       
   656 	const TDesC* lineEnding = &KUnknownDelim;
       
   657 #define CASE_LIT(res, x, y) case x: { _LIT(KName, y); res = &KName; break; }
       
   658 	switch(iBuffer.DelimiterType())
       
   659 		{
       
   660 		CASE_LIT(lineEnding, EDelimLF, "LF")
       
   661 		CASE_LIT(lineEnding, EDelimCR, "CR")
       
   662 		CASE_LIT(lineEnding, EDelimCRLF, "CRLF")
       
   663 		CASE_LIT(lineEnding, EDelimUnicode, "UniLF")
       
   664 		default:
       
   665 			break;
       
   666 		}
       
   667 	const TDesC* encoding = &KUnknownEnc;
       
   668 	switch (iBuffer.Encoding())
       
   669 		{
       
   670 		CASE_LIT(encoding, EEncodingNarrow, "8-bit")
       
   671 		CASE_LIT(encoding, EEncodingUtf8, "UTF-8")
       
   672 		CASE_LIT(encoding, EEncodingUtf16LE, "UTF-16LE")
       
   673 		CASE_LIT(encoding, EEncodingUtf16BE, "UTF-16BE")
       
   674 		default:
       
   675 			break;
       
   676 		}
       
   677 
       
   678 	const TDesC* modified = &KNullDesC;
       
   679 	if (iBuffer.Modified())
       
   680 		{
       
   681 		_LIT(KMod, "(*)");
       
   682 		modified = &KMod;
       
   683 		}
       
   684 
       
   685 	TInt currentLine = iLineData->FileLineNumber(iCursor.iY) + 1; // Human-readable line numbers are always shown as 1-based
       
   686 	TInt currentCol = iCursor.iX + 1; // Human-readable col numbers are always shown as 1-based, annoying as it is we will do the same
       
   687 	TInt docPos = DocumentPosition();
       
   688 	_LIT(KStatus, "%S %S %S Ln:%d Col:%d Char:%d");
       
   689 	_LIT(KShortStatus, "%S %S %S Ln:%d");
       
   690 	_LIT(KMarkStatus, "Mark@%d. ^X/^C to complete. Ln:%d Ch:%d");
       
   691 	const TDesC* title = &iBuffer.Title();
       
   692 	_LIT(KUntitled, "untitled");
       
   693 	if (title->Length() == 0) title = &KUntitled;
       
   694 	if (MarkActive())
       
   695 		{
       
   696 		iConsoleProvider.WriteStatus(KNullDesC, KMarkStatus, iMarkDocPos, currentLine, docPos);
       
   697 		}
       
   698 	else if (iConsole.ScreenSize().iWidth < 50)
       
   699 		{
       
   700 		iConsoleProvider.WriteStatus(*title, KShortStatus, modified, lineEnding, encoding, currentLine);
       
   701 		}
       
   702 	else
       
   703 		{
       
   704 		iConsoleProvider.WriteStatus(*title, KStatus, modified, lineEnding, encoding, currentLine, currentCol, docPos);
       
   705 		}
       
   706 	}
       
   707 
       
   708 void CLRTextView::GoToLine()
       
   709 	{
       
   710 	TBuf<32> lineText;
       
   711 	TBool go = iConsoleProvider.QueryText(_L("Go to line: "), lineText);
       
   712 	if (go == EFalse) return;
       
   713 
       
   714 	TLex lex(lineText);
       
   715 	TBool gotoLine = ETrue;
       
   716 	if (lex.Peek() == 'c')
       
   717 		{
       
   718 		// Go to character pos
       
   719 		lex.Inc();
       
   720 		gotoLine = EFalse;
       
   721 		}
       
   722 
       
   723 	TInt pos;
       
   724 	TInt err = lex.Val(pos);
       
   725 	if (err || pos <= 0)
       
   726 		{
       
   727 		iConsoleProvider.InfoPrint(_L("Couldn't parse line number '%S'"), &lineText);
       
   728 		return;
       
   729 		}
       
   730 
       
   731 	if (gotoLine && pos > 1)
       
   732 		{
       
   733 		GoToLine(pos-1); // -1 to change 1-based display number to internal 0-based.
       
   734 		}
       
   735 	else
       
   736 		{
       
   737 		CenterDocPosOnScreen(pos-1);
       
   738 		}
       
   739 	}
       
   740 
       
   741 void CLRTextView::GoToLine(TInt aLine)
       
   742 	{
       
   743 	TInt err = iBuffer.SeekFromOffset(*this, 0, aLine, KMaxTInt); 
       
   744 	if (err)
       
   745 		{
       
   746 		HandleDataLoadError(err);
       
   747 		}
       
   748 	else
       
   749 		{
       
   750 		CenterDocPosOnScreen(iRange.iLocation);
       
   751 		}
       
   752 	}
       
   753 
       
   754 void CLRTextView::Find()
       
   755 	{
       
   756 	TBool searchBackwards = EFalse;
       
   757 	TBool proceed = iConsoleProvider.QueryText(_L("Find text: "), iFindText);
       
   758 	while (proceed)
       
   759 		{
       
   760 		TInt nextLineStart = iLineData->DocumentPosition(iCursor.iY + 1);
       
   761 		iConsoleProvider.InfoPrint(_L("Searching..."));
       
   762 		TInt found = iBuffer.Find(nextLineStart, iFindText, searchBackwards);
       
   763 		if (found == KErrNotFound)
       
   764 			{
       
   765 			iConsoleProvider.InfoPrint(_L("Cannot find '%S'"), &iFindText);
       
   766 			proceed = EFalse;
       
   767 			}
       
   768 		else if (found < 0)
       
   769 			{
       
   770 			iConsoleProvider.InfoPrint(_L("Error during searching: %d"), found);
       
   771 			proceed = EFalse;
       
   772 			}
       
   773 		else
       
   774 			{
       
   775 			CenterDocPosOnScreen(found);
       
   776 			/*TKeyCode ch = iConsoleProvider.Query(_L("Search again? (next/previous/cancel) "));
       
   777 			if (ch == 'n')
       
   778 				{
       
   779 				searchBackwards = EFalse;
       
   780 				continue;
       
   781 				}
       
   782 			else if (ch == 'p')
       
   783 				{
       
   784 				searchBackwards = ETrue;
       
   785 				continue;
       
   786 				}
       
   787 			else*/
       
   788 				{
       
   789 				proceed = EFalse;
       
   790 				}
       
   791 			}
       
   792 		}
       
   793 	}
       
   794 
       
   795 void CLRTextView::CenterDocPosOnScreen(TInt aDocumentPosition)
       
   796 	{
       
   797 	const TInt numScreenLines = iWindow.iHeight;
       
   798 	TPoint point = WindowLocationForDocumentPosition(aDocumentPosition);
       
   799 	if (point.iY != -1)
       
   800 		{
       
   801 		// pos is on screen already - just move the cursor
       
   802 		UpdateCursor(point);
       
   803 		return;
       
   804 		}
       
   805 
       
   806 	TInt err = iBuffer.SeekFromOffset(*this, aDocumentPosition, -(numScreenLines/2), iWindow.iWidth-1);
       
   807 	if (err)
       
   808 		{
       
   809 		HandleDataLoadError(err);
       
   810 		}
       
   811 	else
       
   812 		{
       
   813 		iDrawPoint.SetXY(iWindow.iX, iWindow.iY);
       
   814 		DoDrawL(EFalse); // EFalse to say we will update the cursor and status ourselves
       
   815 		UpdateCursor(WindowLocationForDocumentPosition(aDocumentPosition));
       
   816 		}
       
   817 	}
       
   818 
       
   819 void CLineData::EnsureCapacityL(TInt aWidth, TInt aHeight)
       
   820 	{
       
   821 	if (!iDocPosAndLine || (TUint)User::AllocLen(iDocPosAndLine) < sizeof(TInt)*2 * (aHeight+1))
       
   822 		{
       
   823 		User::Free(iDocPosAndLine);
       
   824 		iDocPosAndLine = NULL;
       
   825 		iDocPosAndLine = (TInt*)User::AllocZL(sizeof(TInt)*2*(aHeight+1));
       
   826 		}
       
   827 	iLineLen = aWidth-1;
       
   828 	TInt lineWidthBytes = ((iLineLen+7)&~7)/8;
       
   829 	TInt screenBytes = lineWidthBytes * (aHeight+1);
       
   830 	if (!iScreenIndexes || User::AllocLen(iScreenIndexes) < screenBytes)
       
   831 		{
       
   832 		User::Free(iScreenIndexes);
       
   833 		iScreenIndexes = NULL;
       
   834 		iScreenIndexes = (TUint8*)User::AllocZL(screenBytes);
       
   835 		}
       
   836 	SetPositionIsValid(0, 0, ETrue); // This position is always valid even if the document is empty
       
   837 	}
       
   838 
       
   839 TInt CLineData::DocumentPosition(TInt aLine) const
       
   840 	{
       
   841 	return iDocPosAndLine[aLine*2];
       
   842 	}
       
   843 
       
   844 TInt CLineData::FileLineNumber(TInt aLine) const
       
   845 	{
       
   846 	return iDocPosAndLine[aLine*2 + 1];
       
   847 	}
       
   848 
       
   849 const TUint8& CLineData::ByteForPos(TInt aLine, TInt aCol, TInt& aOffset) const
       
   850 	{
       
   851 	return const_cast<CLineData*>(this)->ByteForPos(aLine, aCol, aOffset);
       
   852 	}
       
   853 
       
   854 TUint8& CLineData::ByteForPos(TInt aLine, TInt aCol, TInt& aOffset)
       
   855 	{
       
   856 	TInt lineWidthBytes = ((iLineLen+7)&~7)/8;
       
   857 	TInt byteIndex = aLine*lineWidthBytes + aCol/8;
       
   858 	aOffset = aCol%8;
       
   859 	TUint8& b = iScreenIndexes[byteIndex];
       
   860 	return b;
       
   861 	}
       
   862 
       
   863 TBool CLineData::IsScreenPositionValid(TInt aLine, TInt aCol) const
       
   864 	{
       
   865 	TInt offset;
       
   866 	TUint8 b = ByteForPos(aLine, aCol, offset);
       
   867 	return b & (1 << offset);
       
   868 	}
       
   869 
       
   870 void CLineData::SetDocumentPositionForLine(TInt aLine, TInt aDocumentPosition)
       
   871 	{
       
   872 	ASSERT(iDocPosAndLine && aLine*2*sizeof(TInt) < (TUint)User::AllocLen(iDocPosAndLine));
       
   873 	iDocPosAndLine[aLine*2] = aDocumentPosition;
       
   874 	}
       
   875 
       
   876 void CLineData::SetFileLineNumberForLine(TInt aLine, TInt aFileLineNumber)
       
   877 	{
       
   878 	ASSERT(iDocPosAndLine && (aLine*2+1)*sizeof(TInt) < (TUint)User::AllocLen(iDocPosAndLine));
       
   879 	iDocPosAndLine[aLine*2 + 1] = aFileLineNumber;
       
   880 	}
       
   881 
       
   882 void CLineData::SetPositionIsValid(TInt aLine, TInt aCol, TBool aValid)
       
   883 	{
       
   884 	TInt offset;
       
   885 	TUint8& b = ByteForPos(aLine, aCol, offset);
       
   886 	if (aValid)
       
   887 		{
       
   888 		b |= (1<<offset);
       
   889 		}
       
   890 	else
       
   891 		{
       
   892 		b &= ~(1<<offset);
       
   893 		}
       
   894 	}
       
   895 
       
   896 void CLineData::LineFinishedAt(TInt aLine, TInt aCol)
       
   897 	{
       
   898 	if (aCol >=0 && aCol < iLineLen) SetPositionIsValid(aLine, aCol, ETrue); //  The last position on the line is valid even though nothing is drawn there
       
   899 	TInt offset;
       
   900 	TUint8& b = ByteForPos(aLine, aCol+1, offset); // Plus one as we want to clear everything beyond the aCol position
       
   901 	// Clear everything above the offset'th bit
       
   902 	b &= (1 << offset) - 1;
       
   903 	// And clear all bytes from b to the end of the line
       
   904 	TUint8* endb = &ByteForPos(aLine, iLineLen-1, offset);
       
   905 	// Armv5 doesn't like passing in a length of zero to memset, not sure why. Anyway, check there are actually some other bytes that need clearing
       
   906 	if (endb > &b)
       
   907 		{
       
   908 		Mem::FillZ((&b)+1, endb - &b);
       
   909 		}
       
   910 	}
       
   911 
       
   912 CLineData::~CLineData()
       
   913 	{
       
   914 	User::Free(iDocPosAndLine);
       
   915 	User::Free(iScreenIndexes);
       
   916 	}
       
   917 
       
   918 TInt CLineData::LastValidPosition(TInt aLine) const
       
   919 	{
       
   920 	TInt offset;
       
   921 	TInt pos = iLineLen-1; // Start comparing from the last possible valid position
       
   922 	const TUint8* b = &ByteForPos(aLine, pos, offset);
       
   923 	while(*b == 0)
       
   924 		{
       
   925 		b--; // Optimisation to skip over blanks
       
   926 		pos -= offset+1;
       
   927 		offset = 7;
       
   928 		}
       
   929 
       
   930 	while (offset >= 0 && ((*b) & (1<<offset)) == 0)
       
   931 		{
       
   932 		pos--;
       
   933 		offset--;
       
   934 		}
       
   935 	ASSERT(IsScreenPositionValid(aLine, pos)); // Something's gone very wrong in the logic of this function if this assert is not true!
       
   936 	return pos;
       
   937 	}
       
   938 
       
   939 void CLRTextView::CopyToClipboardL(const TDesC& aBuf)
       
   940 	{
       
   941 	LtkUtils::CopyToClipboardL(aBuf, &iConsoleProvider.Fs());
       
   942 	}
       
   943 
       
   944 HBufC* CLRTextView::GetFromClipboardL()
       
   945 	{
       
   946 	return LtkUtils::GetFromClipboardL(&iConsoleProvider.Fs());
       
   947 	}
       
   948 
       
   949 void CLRTextView::PasteL()
       
   950 	{
       
   951 	HBufC* text = GetFromClipboardL();
       
   952 	CleanupStack::PushL(text);
       
   953 	if (text->Length() == 0)
       
   954 		{
       
   955 		iConsoleProvider.InfoPrint(_L("Nothing to paste"));
       
   956 		}
       
   957 	else
       
   958 		{
       
   959 		InsertTextL(*text);
       
   960 		}
       
   961 	CleanupStack::PopAndDestroy(text);
       
   962 	}
       
   963 
       
   964 TPoint CLRTextView::WindowLocationForDocumentPosition(TInt aDocumentPosition) const
       
   965 	{
       
   966 	TPoint result(-1,-1); // We return this if doc pos is not on screen
       
   967 	const TInt numScreenLines = iWindow.iHeight;
       
   968 	if (aDocumentPosition >= iLineData->DocumentPosition(0) && aDocumentPosition < iLineData->DocumentPosition(numScreenLines))
       
   969 		{
       
   970 		// pos is on screen
       
   971 		for (TInt line = 0; line < numScreenLines; line++)
       
   972 			{
       
   973 			if (aDocumentPosition < iLineData->DocumentPosition(line+1))
       
   974 				{
       
   975 				result.iY = line;
       
   976 				TInt docPos = iLineData->DocumentPosition(line);
       
   977 				TInt column = 0;
       
   978 				// Find the column screen position whose document position is what we want
       
   979 				for (; docPos <= aDocumentPosition; column++)
       
   980 					{
       
   981 					if (iLineData->IsScreenPositionValid(line, column))
       
   982 						{
       
   983 						docPos++;
       
   984 						}
       
   985 					}
       
   986 				result.iX = column-1;
       
   987 				break;
       
   988 				}
       
   989 			}
       
   990 		}
       
   991 	return result;
       
   992 	}
       
   993 
       
   994 void CLRTextView::SetMark()
       
   995 	{
       
   996 	iMarkFlasher->Cancel();
       
   997 	iMarkDocPos = DocumentPosition();
       
   998 	iMarkShown = EFalse;
       
   999 	const TInt KFlashInterval = 500000;
       
  1000 	iMarkFlasher->Start(0, KFlashInterval, TCallBack(&FlashMark, this));
       
  1001 	UpdateStatus();
       
  1002 	iConsoleProvider.InfoPrint(_L("Mark set. Move cursor then press ^X/^C to cut/copy"));
       
  1003 	}
       
  1004 
       
  1005 void CLRTextView::CancelMark()
       
  1006 	{
       
  1007 	if (MarkActive())
       
  1008 		{
       
  1009 		iMarkFlasher->Cancel();
       
  1010 		if (WindowLocationForDocumentPosition(iMarkDocPos).iY != -1)
       
  1011 			{
       
  1012 			// If the mark pos is on screen, redraw it to get rid of the '*'
       
  1013 			RedrawFromPositionToEndOfLine(iMarkDocPos, 0);
       
  1014 			}
       
  1015 		}
       
  1016 	}
       
  1017 
       
  1018 TInt CLRTextView::FlashMark(TAny* aSelf)
       
  1019 	{
       
  1020 	static_cast<CLRTextView*>(aSelf)->DoFlashMark();
       
  1021 	return 1;
       
  1022 	}
       
  1023 
       
  1024 void CLRTextView::DoFlashMark()
       
  1025 	{
       
  1026 	TPoint markPos = WindowLocationForDocumentPosition(iMarkDocPos);
       
  1027 	if (markPos.iY != -1)
       
  1028 		{
       
  1029 		TPoint cursor = iConsole.CursorPos();
       
  1030 		iConsole.SetCursorPosAbs(markPos);
       
  1031 		if (iMarkShown)
       
  1032 			iConsole.Write(_L(" "));
       
  1033 		else
       
  1034 			iConsole.Write(_L("*"));
       
  1035 		iMarkShown = !iMarkShown;
       
  1036 		iConsole.SetCursorPosAbs(cursor);
       
  1037 		}
       
  1038 	}
       
  1039 
       
  1040 TBool CLRTextView::MarkActive() const
       
  1041 	{
       
  1042 	return iMarkFlasher->IsActive();
       
  1043 	}
       
  1044 
       
  1045 void CLRTextView::CopyOrCutL(TBool aCut)
       
  1046 	{
       
  1047 	TInt docPos = DocumentPosition();
       
  1048 	const TInt start = Min(docPos, iMarkDocPos);
       
  1049 	const TInt len = Abs(docPos - iMarkDocPos);
       
  1050 	CancelMark();
       
  1051 	RBuf textCopy;
       
  1052 	CleanupClosePushL(textCopy);
       
  1053 	TInt dataPos = start;
       
  1054 	while(ETrue)
       
  1055 		{
       
  1056 		TInt err = iBuffer.GetData(*this, dataPos);
       
  1057 		if (err)
       
  1058 			{
       
  1059 			HandleDataLoadError(err);
       
  1060 			CleanupStack::PopAndDestroy(&textCopy);
       
  1061 			return;
       
  1062 			}
       
  1063 		else
       
  1064 			{
       
  1065 			TPtrC text = iDes.Left(len - textCopy.Length());
       
  1066 			if (textCopy.MaxLength() == 0 && len <= iRange.iLength)
       
  1067 				{
       
  1068 				// All fits in one buffer, no need to copy anything!
       
  1069 				CopyToClipboardL(text);
       
  1070 				break;
       
  1071 				}
       
  1072 			else
       
  1073 				{
       
  1074 				// Need to do some copying
       
  1075 				if (textCopy.MaxLength() == 0) textCopy.CreateL(len);
       
  1076 				textCopy.Append(text);
       
  1077 				dataPos += text.Length();
       
  1078 				if (textCopy.Length() == len)
       
  1079 					{
       
  1080 					// Done
       
  1081 					CopyToClipboardL(textCopy);
       
  1082 					break;
       
  1083 					}
       
  1084 				}
       
  1085 			}
       
  1086 		}
       
  1087 	CleanupStack::PopAndDestroy(&textCopy);
       
  1088 	if (aCut)
       
  1089 		{
       
  1090 		TRange range(start, len);
       
  1091 		iBuffer.DeleteTextL(range);
       
  1092 		iCursor = WindowLocationForDocumentPosition(start);
       
  1093 		if (iCursor.iY == -1)
       
  1094 			{
       
  1095 			// Start of the selection is offscreen - force a scroll
       
  1096 			CenterDocPosOnScreen(start);
       
  1097 			}
       
  1098 		else
       
  1099 			{
       
  1100 			iDrawPoint = iCursor + iWindow.Origin();
       
  1101 			RequestData(EFalse, start);
       
  1102 			}
       
  1103 		iConsoleProvider.InfoPrint(_L("Text cut to clipboard"));
       
  1104 		}
       
  1105 	else
       
  1106 		{
       
  1107 		iConsoleProvider.InfoPrint(_L("Text copied to clipboard"));
       
  1108 		}
       
  1109 	}
       
  1110 
       
  1111 void CLRTextView::UpdateDocumentPositionsStartingAtLine(TInt aLine, TInt aDelta)
       
  1112 	{
       
  1113 	// This is important because even though we can optimise away the drawing, when a line has changed
       
  1114 	// length but not caused wrapping, we still need to make sure the document positions of all the
       
  1115 	// lines we didn't draw are correct to reflect the extra characters.
       
  1116 	for (TInt i = aLine; i < iWindow.iHeight+1; i++)
       
  1117 		{
       
  1118 		iLineData->SetDocumentPositionForLine(i, iLineData->DocumentPosition(i) + aDelta);
       
  1119 		}
       
  1120 	}