commands/fed/src/cmdwindow.cpp
changeset 0 7f656887cf89
equal deleted inserted replaced
-1:000000000000 0:7f656887cf89
       
     1 // cmdwindow.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 #include "cmdwindow.h"
       
    13 #include <e32cons.h>
       
    14 #include <BADESCA.H>
       
    15 
       
    16 const TInt KInfoPrintTime = 2500000; // 2.5 seconds
       
    17 
       
    18 CCommandWindow* CCommandWindow::NewL(RFs& aFs, CColorConsoleBase& aConsole)
       
    19 	{
       
    20 	CCommandWindow* self = new(ELeave) CCommandWindow(aFs, aConsole);
       
    21 	CleanupStack::PushL(self);
       
    22 	self->ConstructL();
       
    23 	CleanupStack::Pop(self);
       
    24 	return self;
       
    25 	}
       
    26 
       
    27 CCommandWindow* CCommandWindow::NewL(RFs& aFs, CConsoleBase& aConsole)
       
    28 	{
       
    29 	CCommandWindow* self = new(ELeave) CCommandWindow(aFs, aConsole);
       
    30 	CleanupStack::PushL(self);
       
    31 	self->ConstructL();
       
    32 	CleanupStack::Pop(self);
       
    33 	return self;
       
    34 	}
       
    35 
       
    36 CCommandWindow::CCommandWindow(RFs& aFs, CConsoleBase& aConsole)
       
    37 	: iFs(aFs), iConsole(aConsole), iColorConsole(NULL), iConsoleAdapter(aConsole)
       
    38 	{}
       
    39 
       
    40 CCommandWindow::CCommandWindow(RFs& aFs, CColorConsoleBase& aConsole)
       
    41 	: iFs(aFs), iConsole(aConsole), iColorConsole(&aConsole), iConsoleAdapter(aConsole)
       
    42 	{}
       
    43 
       
    44 void CCommandWindow::ConstructL()
       
    45 	{
       
    46 	iInfoPrintDismisser = CPeriodic::NewL(CActive::EPriorityStandard);
       
    47 	TBuf<64> buf;
       
    48 
       
    49 	User::LeaveIfError(iFs.PrivatePath(buf));
       
    50 	buf.Insert(0, _L("c:"));
       
    51 	buf.Append(_L("fed_filehistory"));
       
    52 	iFileNameLineEditor = CLineEditor::NewL(iFs, iConsoleAdapter, *this, *this, buf);
       
    53 
       
    54 	User::LeaveIfError(iFs.PrivatePath(buf));
       
    55 	buf.Insert(0, _L("c:"));
       
    56 	buf.Append(_L("fed_generalhistory"));
       
    57 	iGeneralLineEditor = CLineEditor::NewL(iFs, iConsoleAdapter, *this, *this, buf);
       
    58 	}
       
    59 
       
    60 CCommandWindow::~CCommandWindow()
       
    61 	{
       
    62 	if (iInfoPrintDismisser) iInfoPrintDismisser->Cancel();
       
    63 	delete iInfoPrintDismisser;
       
    64 	delete iGeneralLineEditor;
       
    65 	delete iFileNameLineEditor;
       
    66 	}
       
    67 
       
    68 CConsoleBase& CCommandWindow::Console()
       
    69 	{
       
    70 	return iConsole;
       
    71 	}
       
    72 
       
    73 CColorConsoleBase* CCommandWindow::ColorConsole()
       
    74 	{
       
    75 	return iColorConsole;
       
    76 	}
       
    77 
       
    78 class TOverflow16 : public TDes16Overflow
       
    79 	{
       
    80 public:
       
    81 	void Overflow(TDes16 &) {}
       
    82 	};
       
    83 
       
    84 void CCommandWindow::WriteStatus(const TDesC& aNameToTruncate, TRefByValue<const TDesC> aFmt, ...)
       
    85 	{
       
    86 	TDes& buf = iLastStatus;
       
    87 	buf.Zero();
       
    88 	VA_LIST args;
       
    89 	VA_START(args, aFmt);
       
    90 	TOverflow16 overflow;
       
    91 	buf.AppendFormatList(aFmt, args, &overflow);
       
    92 	VA_END(args);
       
    93 
       
    94 	const TInt availWidth = iWindow.iWidth - 1;
       
    95 	buf.SetLength(Min(buf.Length(), availWidth));
       
    96 	TInt widthForName = availWidth - buf.Length();
       
    97 	buf.Insert(0, aNameToTruncate.Right(widthForName));
       
    98 	if (buf.Length() < iWindow.iWidth) buf.Append(' ');
       
    99 	buf.AppendFill('-', iWindow.iWidth - buf.Length() - 1); // Don't fill to edge of screen, that causes a wrap
       
   100 
       
   101 	DoWriteLine(buf);
       
   102 	}
       
   103 
       
   104 void CCommandWindow::DoWriteLine(const TDesC& aLine, TInt aHighlightStart, TInt aHighlightLength)
       
   105 	{
       
   106 	TPoint cursor = iConsole.CursorPos();
       
   107 	iConsole.SetCursorHeight(0);
       
   108 	iConsole.SetPos(iWindow.iX, iWindow.iY);
       
   109 	if (aHighlightLength && ColorConsole())
       
   110 		{
       
   111 		TPtrC left = aLine.Left(aHighlightStart);
       
   112 		TPtrC mid = aLine.Mid(aHighlightStart, aHighlightLength);
       
   113 		TPtrC right = aLine.Mid(aHighlightStart + aHighlightLength);
       
   114 		ColorConsole()->Write(left);
       
   115 		ColorConsole()->SetTextAttribute(ETextAttributeInverse);
       
   116 		ColorConsole()->Write(mid);
       
   117 		ColorConsole()->SetTextAttribute(ETextAttributeNormal);
       
   118 		ColorConsole()->Write(right);
       
   119 		}
       
   120 	else
       
   121 		{
       
   122 		iConsole.Write(aLine);
       
   123 		}
       
   124 	iConsole.SetCursorPosAbs(cursor);
       
   125 	iConsole.SetCursorHeight(20);
       
   126 	}
       
   127 
       
   128 void CCommandWindow::InfoPrint(TRefByValue<const TDesC> aFmt, ...)
       
   129 	{
       
   130 	iInfoPrintDismisser->Cancel(); // If there's already a print onscreen, we bin it straight away (same as how User::InfoPrint works)
       
   131 	TBuf<256> buf;
       
   132 	VA_LIST args;
       
   133 	VA_START(args, aFmt);
       
   134 	TOverflow16 overflow;
       
   135 	buf.AppendFormatList(aFmt, args, &overflow);
       
   136 	VA_END(args);
       
   137 
       
   138 	buf.SetLength(Min(buf.Length(), iWindow.iWidth-5)); // 4 for -[ and ]-, and one more to avoid hitting the final column
       
   139 	TInt highlightLen = buf.Length() + 2; // Highlight the [] as well
       
   140 	buf.Insert(0, _L("-["));
       
   141 	buf.Append(_L("]-"));
       
   142 	TInt fillWidth = iWindow.iWidth - buf.Length() - 1;
       
   143 	TInt left = fillWidth / 2;
       
   144 	TInt highlightStart = left+1;
       
   145 	TInt right = fillWidth - left;
       
   146 	while(left--)
       
   147 		{
       
   148 		buf.Insert(0, _L("-"));
       
   149 		}
       
   150 	buf.AppendFill('-', right);
       
   151 	DoWriteLine(buf, highlightStart, highlightLen);
       
   152 	iInfoPrintDismisser->Start(KInfoPrintTime, KInfoPrintTime, TCallBack(&DismissInfoPrint, this));
       
   153 	}
       
   154 
       
   155 TInt CCommandWindow::DismissInfoPrint(TAny* aSelf)
       
   156 	{
       
   157 	CCommandWindow* self = static_cast<CCommandWindow*>(aSelf);
       
   158 	// Restore previous status
       
   159 	self->DoWriteLine(self->iLastStatus);
       
   160 	self->iInfoPrintDismisser->Cancel();
       
   161 	return 0;
       
   162 	}
       
   163 
       
   164 TKeyCode CCommandWindow::Query(const TDesC& aPrompt, const TDesC& aValidKeys)
       
   165 	{
       
   166 	TPoint cursor = iConsole.CursorPos();
       
   167 	iQuery = aPrompt;
       
   168 	iQuery.Append(_L("[ ]"));
       
   169 	iQuery.AppendFill('-', iQuery.MaxLength() - iQuery.Length());
       
   170 	iQuery.SetLength(iWindow.iWidth - 1);
       
   171 	DoWriteLine(iQuery);
       
   172 	iConsole.SetPos(iWindow.iX + aPrompt.Length()+1, iWindow.iY);
       
   173 	iConsole.SetCursorHeight(20);
       
   174 	TKeyCode res = EKeyNull;
       
   175 	while (aValidKeys.Locate(res) == KErrNotFound)
       
   176 		{
       
   177 		res = iConsole.Getch();
       
   178 		}
       
   179 	// Print the key that the user entered, between the square brackets
       
   180 	if (TChar(res).IsPrint())
       
   181 		{
       
   182 		TBuf<1> chbuf;
       
   183 		chbuf.Append(res);
       
   184 		iConsole.Write(chbuf);
       
   185 		}
       
   186 	iConsole.SetCursorPosAbs(cursor);
       
   187 	// Async clear the query (in case we are called repeatedly)
       
   188 	iInfoPrintDismisser->Cancel();
       
   189 	iInfoPrintDismisser->Start(0, KInfoPrintTime, TCallBack(&DismissInfoPrint, this));
       
   190 	return res;
       
   191 	}
       
   192 
       
   193 TBool CCommandWindow::QueryText(const TDesC& aPrompt, TDes& aText)
       
   194 	{
       
   195 	iLineEditor = iGeneralLineEditor;
       
   196 	return DoQueryText(aPrompt, aText);
       
   197 	}
       
   198 
       
   199 TBool CCommandWindow::QueryFilename(const TDesC& aPrompt, TFileName& aFileName)
       
   200 	{
       
   201 	iLineEditor = iFileNameLineEditor;
       
   202 	TBool res = DoQueryText(aPrompt, aFileName);
       
   203 	if (res)
       
   204 		{
       
   205 		IoUtils::TFileName2 fn2(aFileName);
       
   206 		TRAPD(err, fn2.MakeAbsoluteL(iFs));
       
   207 		if (err) res = EFalse;
       
   208 		aFileName.Copy(fn2);
       
   209 		}
       
   210 	return res;
       
   211 	}
       
   212 
       
   213 TBool CCommandWindow::DoQueryText(const TDesC& aPrompt, TDes& aText)
       
   214 	{
       
   215 	// Get cursor in right position
       
   216 	TPoint cursor = iConsole.CursorPos();
       
   217 	// Clear the way
       
   218 	iConsole.SetPos(iWindow.iX, iWindow.iY);
       
   219 	iQuery.Fill(' ', iWindow.iWidth-1);
       
   220 	iConsole.Write(iQuery);
       
   221 	iConsole.SetPos(iWindow.iX, iWindow.iY);
       
   222 	// Start the line editor going
       
   223 	iLineEditor->Start(aPrompt, aText);
       
   224 	iLineEditor->ReinstatePromptAndUserInput();
       
   225 	iFinished = EFalse;
       
   226 	TBool result = ETrue;
       
   227 	iResultForQuery = &aText;
       
   228 	while (!iFinished)
       
   229 		{
       
   230 		TKeyCode ch = iConsole.Getch();
       
   231 		if (ch == EKeyEscape) 
       
   232 			{
       
   233 			result = EFalse;
       
   234 			break;
       
   235 			}
       
   236 		if (ch == EKeyEnter)
       
   237 			{
       
   238 			// Fool line editor by moving cursor up a line, so when it does its newline it doesn't screw us up
       
   239 			iConsole.SetCursorPosRel(TPoint(0, -1));
       
   240 			}
       
   241 		iLineEditor->HandleKey(ch, iConsole.KeyModifiers());
       
   242 		}
       
   243 	iConsole.SetCursorPosAbs(cursor);
       
   244 	// Async clear the query (in case of... something. Velociraptors maybe?)
       
   245 	iInfoPrintDismisser->Cancel();
       
   246 	iInfoPrintDismisser->Start(0, KInfoPrintTime, TCallBack(&DismissInfoPrint, this));
       
   247 	return result;
       
   248 	}
       
   249 
       
   250 RFs& CCommandWindow::Fs()
       
   251 	{
       
   252 	return iFs;
       
   253 	}
       
   254 
       
   255 void CCommandWindow::LeoHandleLine(const TDesC& aLine)
       
   256 	{
       
   257 	iFinished = ETrue;
       
   258 	*iResultForQuery = aLine.Left(iResultForQuery->MaxLength());
       
   259 	}
       
   260 
       
   261 _LIT(KFileNameSlash, "\\");
       
   262 _LIT(KDriveColonSlash, ":\\");
       
   263 _LIT(KTab, "\t");
       
   264 _LIT(KSpace, " ");
       
   265 
       
   266 // This code ripped from ptf
       
   267 void CCommandWindow::LcCompleteLineL(TConsoleLine& aLine, const TChar& /*aEscapeChar*/)
       
   268 	{
       
   269 	if (iLineEditor != iFileNameLineEditor) return; // Don't autocomplete for anything that isn't a filename
       
   270 
       
   271 	IoUtils::TFileName2 fileNameMatch;
       
   272 	fileNameMatch.Copy(aLine.ContentsToCursor());
       
   273 	
       
   274 	CDesCArray* suggestions = new(ELeave) CDesC16ArrayFlat(16);
       
   275 	CleanupStack::PushL(suggestions);
       
   276 
       
   277 	if (fileNameMatch.Length()==0)
       
   278 		{
       
   279 		SuggestDrivesL(suggestions);
       
   280 		}
       
   281 	else if (fileNameMatch.Length() == 2 && TChar(fileNameMatch[0]).IsAlpha() && fileNameMatch[1] == ':')
       
   282 		{
       
   283 		fileNameMatch.Append(KFileNameSlash);
       
   284 		}
       
   285 
       
   286 	if (!fileNameMatch.IsAbsolute())
       
   287 		{
       
   288 		fileNameMatch.MakeAbsoluteL(iFs);
       
   289 		}
       
   290 	
       
   291 	TPtrC relativeDir = aLine.ContentsToCursor();
       
   292 	relativeDir.Set(relativeDir.Left(relativeDir.LocateReverse('\\')+1)); // Remove any name to the right of the last backslash
       
   293 		
       
   294 	fileNameMatch.Append('*');
       
   295 	
       
   296 	CDir* files = NULL;
       
   297 	User::LeaveIfError(iFs.GetDir(fileNameMatch, KEntryAttNormal | KEntryAttDir, ESortByName, files));
       
   298 	CleanupStack::PushL(files);
       
   299 		
       
   300 	TInt numFiles = files->Count();
       
   301 	if (numFiles == 1)
       
   302 		{
       
   303 		fileNameMatch.SetLength(fileNameMatch.DriveAndPath().Length());
       
   304 		fileNameMatch.AppendComponentL((*files)[0].iName);
       
   305 		TEntry entry;
       
   306 		User::LeaveIfError(iFs.Entry(fileNameMatch, entry));
       
   307 		suggestions->AppendL(fileNameMatch.NameAndExt());
       
   308 		CompleteL(aLine, *suggestions, &relativeDir, entry.IsDir() ? &KFileNameSlash : NULL);
       
   309 		}
       
   310 	else if (numFiles > 0)
       
   311 		{
       
   312 		for (TInt i=0; i<numFiles; ++i)
       
   313 			{
       
   314 			suggestions->AppendL((*files)[i].iName);
       
   315 			}
       
   316 		CompleteL(aLine, *suggestions, &relativeDir, NULL);
       
   317 		}
       
   318 	
       
   319 	CleanupStack::PopAndDestroy(2, suggestions); // files, suggestions
       
   320 	}
       
   321 
       
   322 void CCommandWindow::SuggestDrivesL(CDesCArray* aSuggestions)
       
   323 	{
       
   324 	TDriveList drives;
       
   325 	User::LeaveIfError(iFs.DriveList(drives));
       
   326 	
       
   327 	for (TInt i=0; i<drives.Length(); ++i)
       
   328 		{
       
   329 		if (drives[i])
       
   330 			{
       
   331 			TBuf<3> buf;
       
   332 			
       
   333 			TChar driveChar;
       
   334 			User::LeaveIfError(iFs.DriveToChar(i, driveChar));
       
   335 			
       
   336 			buf.Append(driveChar);
       
   337 			buf.Append(KDriveColonSlash);
       
   338 			aSuggestions->AppendL(buf);						
       
   339 			}
       
   340 		}
       
   341 	}
       
   342 	
       
   343 void CCommandWindow::CompleteL(TConsoleLine& aLine, const CDesCArray& aPossibilities, const TDesC* aPrefix, const TDesC* aSuffix)
       
   344 	{
       
   345 	const TInt numPossibilities = aPossibilities.Count();
       
   346 
       
   347 	if (numPossibilities > 1)
       
   348 		{
       
   349 		// Fill out possibilities buffer.
       
   350 		IoUtils::CTextBuffer* possibilities = IoUtils::CTextBuffer::NewLC(0x100);
       
   351 		for (TInt i = 0; i < numPossibilities; ++i)
       
   352 			{
       
   353 			possibilities->AppendL(aPossibilities[i]);
       
   354 			if (i != (numPossibilities - 1))
       
   355 				{
       
   356 				possibilities->AppendL(KTab);
       
   357 				}
       
   358 			}
       
   359 
       
   360 		aLine.PrintCompletionPossibilitiesL(possibilities->Descriptor());
       
   361 		CleanupStack::PopAndDestroy(possibilities);
       
   362 		}
       
   363 
       
   364 	if (numPossibilities > 0)
       
   365 		{
       
   366 		IoUtils::CTextBuffer* completion = IoUtils::CTextBuffer::NewLC(0x100);
       
   367 		TPtrC commonChars(NULL, 0);
       
   368 		if (numPossibilities > 1)
       
   369 			{
       
   370 			// Find common leading characters of the possibilities.
       
   371 			TInt commonCharPos = -1;
       
   372 			TBool finished(EFalse);
       
   373 			do
       
   374 				{
       
   375 				++commonCharPos;
       
   376 				TChar character(0);
       
   377 				for (TInt i = 0; i < numPossibilities; ++i)
       
   378 					{
       
   379 					if (commonCharPos >= aPossibilities[i].Length())
       
   380 						{
       
   381 						finished = ETrue;
       
   382 						break;
       
   383 						}
       
   384 					else if (i == 0)
       
   385 						{
       
   386 						character = aPossibilities[0][commonCharPos];
       
   387 						character.Fold();
       
   388 						}
       
   389 					else
       
   390 						{
       
   391 						TChar c(aPossibilities[i][commonCharPos]);
       
   392 						c.Fold();
       
   393 						if (c != character)
       
   394 							{
       
   395 							finished = ETrue;
       
   396 							break;
       
   397 							}
       
   398 						}
       
   399 					}
       
   400 				}
       
   401 				while (!finished);
       
   402 
       
   403 			commonChars.Set(aPossibilities[0].Mid(0, commonCharPos));
       
   404 			}
       
   405 		else
       
   406 			{
       
   407 			commonChars.Set(aPossibilities[0]);
       
   408 			}
       
   409 
       
   410 		if (aPrefix)
       
   411 			{
       
   412 			completion->AppendL(*aPrefix);
       
   413 			}
       
   414 		completion->AppendL(commonChars);
       
   415 
       
   416 		if ((numPossibilities == 1) && (aSuffix))
       
   417 			{
       
   418 			completion->AppendL(*aSuffix);
       
   419 			}
       
   420 			
       
   421 		if ((numPossibilities == 1) && (!aSuffix))
       
   422 			{
       
   423 			completion->AppendL(KSpace);
       
   424 			}
       
   425 			
       
   426 		if (completion->Descriptor().Length() > 0)
       
   427 			{
       
   428 			aLine.Replace(0, completion->Descriptor());
       
   429 			}
       
   430 		CleanupStack::PopAndDestroy(completion);
       
   431 		}
       
   432 	}