commands/fed/src/cmdwindow.cpp
changeset 0 7f656887cf89
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/commands/fed/src/cmdwindow.cpp	Wed Jun 23 15:52:26 2010 +0100
@@ -0,0 +1,432 @@
+// cmdwindow.cpp
+// 
+// Copyright (c) 2009 - 2010 Accenture. All rights reserved.
+// This component and the accompanying materials are made available
+// under the terms of the "Eclipse Public License v1.0"
+// which accompanies this distribution, and is available
+// at the URL "http://www.eclipse.org/legal/epl-v10.html".
+// 
+// Initial Contributors:
+// Accenture - Initial contribution
+//
+#include "cmdwindow.h"
+#include <e32cons.h>
+#include <BADESCA.H>
+
+const TInt KInfoPrintTime = 2500000; // 2.5 seconds
+
+CCommandWindow* CCommandWindow::NewL(RFs& aFs, CColorConsoleBase& aConsole)
+	{
+	CCommandWindow* self = new(ELeave) CCommandWindow(aFs, aConsole);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CCommandWindow* CCommandWindow::NewL(RFs& aFs, CConsoleBase& aConsole)
+	{
+	CCommandWindow* self = new(ELeave) CCommandWindow(aFs, aConsole);
+	CleanupStack::PushL(self);
+	self->ConstructL();
+	CleanupStack::Pop(self);
+	return self;
+	}
+
+CCommandWindow::CCommandWindow(RFs& aFs, CConsoleBase& aConsole)
+	: iFs(aFs), iConsole(aConsole), iColorConsole(NULL), iConsoleAdapter(aConsole)
+	{}
+
+CCommandWindow::CCommandWindow(RFs& aFs, CColorConsoleBase& aConsole)
+	: iFs(aFs), iConsole(aConsole), iColorConsole(&aConsole), iConsoleAdapter(aConsole)
+	{}
+
+void CCommandWindow::ConstructL()
+	{
+	iInfoPrintDismisser = CPeriodic::NewL(CActive::EPriorityStandard);
+	TBuf<64> buf;
+
+	User::LeaveIfError(iFs.PrivatePath(buf));
+	buf.Insert(0, _L("c:"));
+	buf.Append(_L("fed_filehistory"));
+	iFileNameLineEditor = CLineEditor::NewL(iFs, iConsoleAdapter, *this, *this, buf);
+
+	User::LeaveIfError(iFs.PrivatePath(buf));
+	buf.Insert(0, _L("c:"));
+	buf.Append(_L("fed_generalhistory"));
+	iGeneralLineEditor = CLineEditor::NewL(iFs, iConsoleAdapter, *this, *this, buf);
+	}
+
+CCommandWindow::~CCommandWindow()
+	{
+	if (iInfoPrintDismisser) iInfoPrintDismisser->Cancel();
+	delete iInfoPrintDismisser;
+	delete iGeneralLineEditor;
+	delete iFileNameLineEditor;
+	}
+
+CConsoleBase& CCommandWindow::Console()
+	{
+	return iConsole;
+	}
+
+CColorConsoleBase* CCommandWindow::ColorConsole()
+	{
+	return iColorConsole;
+	}
+
+class TOverflow16 : public TDes16Overflow
+	{
+public:
+	void Overflow(TDes16 &) {}
+	};
+
+void CCommandWindow::WriteStatus(const TDesC& aNameToTruncate, TRefByValue<const TDesC> aFmt, ...)
+	{
+	TDes& buf = iLastStatus;
+	buf.Zero();
+	VA_LIST args;
+	VA_START(args, aFmt);
+	TOverflow16 overflow;
+	buf.AppendFormatList(aFmt, args, &overflow);
+	VA_END(args);
+
+	const TInt availWidth = iWindow.iWidth - 1;
+	buf.SetLength(Min(buf.Length(), availWidth));
+	TInt widthForName = availWidth - buf.Length();
+	buf.Insert(0, aNameToTruncate.Right(widthForName));
+	if (buf.Length() < iWindow.iWidth) buf.Append(' ');
+	buf.AppendFill('-', iWindow.iWidth - buf.Length() - 1); // Don't fill to edge of screen, that causes a wrap
+
+	DoWriteLine(buf);
+	}
+
+void CCommandWindow::DoWriteLine(const TDesC& aLine, TInt aHighlightStart, TInt aHighlightLength)
+	{
+	TPoint cursor = iConsole.CursorPos();
+	iConsole.SetCursorHeight(0);
+	iConsole.SetPos(iWindow.iX, iWindow.iY);
+	if (aHighlightLength && ColorConsole())
+		{
+		TPtrC left = aLine.Left(aHighlightStart);
+		TPtrC mid = aLine.Mid(aHighlightStart, aHighlightLength);
+		TPtrC right = aLine.Mid(aHighlightStart + aHighlightLength);
+		ColorConsole()->Write(left);
+		ColorConsole()->SetTextAttribute(ETextAttributeInverse);
+		ColorConsole()->Write(mid);
+		ColorConsole()->SetTextAttribute(ETextAttributeNormal);
+		ColorConsole()->Write(right);
+		}
+	else
+		{
+		iConsole.Write(aLine);
+		}
+	iConsole.SetCursorPosAbs(cursor);
+	iConsole.SetCursorHeight(20);
+	}
+
+void CCommandWindow::InfoPrint(TRefByValue<const TDesC> aFmt, ...)
+	{
+	iInfoPrintDismisser->Cancel(); // If there's already a print onscreen, we bin it straight away (same as how User::InfoPrint works)
+	TBuf<256> buf;
+	VA_LIST args;
+	VA_START(args, aFmt);
+	TOverflow16 overflow;
+	buf.AppendFormatList(aFmt, args, &overflow);
+	VA_END(args);
+
+	buf.SetLength(Min(buf.Length(), iWindow.iWidth-5)); // 4 for -[ and ]-, and one more to avoid hitting the final column
+	TInt highlightLen = buf.Length() + 2; // Highlight the [] as well
+	buf.Insert(0, _L("-["));
+	buf.Append(_L("]-"));
+	TInt fillWidth = iWindow.iWidth - buf.Length() - 1;
+	TInt left = fillWidth / 2;
+	TInt highlightStart = left+1;
+	TInt right = fillWidth - left;
+	while(left--)
+		{
+		buf.Insert(0, _L("-"));
+		}
+	buf.AppendFill('-', right);
+	DoWriteLine(buf, highlightStart, highlightLen);
+	iInfoPrintDismisser->Start(KInfoPrintTime, KInfoPrintTime, TCallBack(&DismissInfoPrint, this));
+	}
+
+TInt CCommandWindow::DismissInfoPrint(TAny* aSelf)
+	{
+	CCommandWindow* self = static_cast<CCommandWindow*>(aSelf);
+	// Restore previous status
+	self->DoWriteLine(self->iLastStatus);
+	self->iInfoPrintDismisser->Cancel();
+	return 0;
+	}
+
+TKeyCode CCommandWindow::Query(const TDesC& aPrompt, const TDesC& aValidKeys)
+	{
+	TPoint cursor = iConsole.CursorPos();
+	iQuery = aPrompt;
+	iQuery.Append(_L("[ ]"));
+	iQuery.AppendFill('-', iQuery.MaxLength() - iQuery.Length());
+	iQuery.SetLength(iWindow.iWidth - 1);
+	DoWriteLine(iQuery);
+	iConsole.SetPos(iWindow.iX + aPrompt.Length()+1, iWindow.iY);
+	iConsole.SetCursorHeight(20);
+	TKeyCode res = EKeyNull;
+	while (aValidKeys.Locate(res) == KErrNotFound)
+		{
+		res = iConsole.Getch();
+		}
+	// Print the key that the user entered, between the square brackets
+	if (TChar(res).IsPrint())
+		{
+		TBuf<1> chbuf;
+		chbuf.Append(res);
+		iConsole.Write(chbuf);
+		}
+	iConsole.SetCursorPosAbs(cursor);
+	// Async clear the query (in case we are called repeatedly)
+	iInfoPrintDismisser->Cancel();
+	iInfoPrintDismisser->Start(0, KInfoPrintTime, TCallBack(&DismissInfoPrint, this));
+	return res;
+	}
+
+TBool CCommandWindow::QueryText(const TDesC& aPrompt, TDes& aText)
+	{
+	iLineEditor = iGeneralLineEditor;
+	return DoQueryText(aPrompt, aText);
+	}
+
+TBool CCommandWindow::QueryFilename(const TDesC& aPrompt, TFileName& aFileName)
+	{
+	iLineEditor = iFileNameLineEditor;
+	TBool res = DoQueryText(aPrompt, aFileName);
+	if (res)
+		{
+		IoUtils::TFileName2 fn2(aFileName);
+		TRAPD(err, fn2.MakeAbsoluteL(iFs));
+		if (err) res = EFalse;
+		aFileName.Copy(fn2);
+		}
+	return res;
+	}
+
+TBool CCommandWindow::DoQueryText(const TDesC& aPrompt, TDes& aText)
+	{
+	// Get cursor in right position
+	TPoint cursor = iConsole.CursorPos();
+	// Clear the way
+	iConsole.SetPos(iWindow.iX, iWindow.iY);
+	iQuery.Fill(' ', iWindow.iWidth-1);
+	iConsole.Write(iQuery);
+	iConsole.SetPos(iWindow.iX, iWindow.iY);
+	// Start the line editor going
+	iLineEditor->Start(aPrompt, aText);
+	iLineEditor->ReinstatePromptAndUserInput();
+	iFinished = EFalse;
+	TBool result = ETrue;
+	iResultForQuery = &aText;
+	while (!iFinished)
+		{
+		TKeyCode ch = iConsole.Getch();
+		if (ch == EKeyEscape) 
+			{
+			result = EFalse;
+			break;
+			}
+		if (ch == EKeyEnter)
+			{
+			// Fool line editor by moving cursor up a line, so when it does its newline it doesn't screw us up
+			iConsole.SetCursorPosRel(TPoint(0, -1));
+			}
+		iLineEditor->HandleKey(ch, iConsole.KeyModifiers());
+		}
+	iConsole.SetCursorPosAbs(cursor);
+	// Async clear the query (in case of... something. Velociraptors maybe?)
+	iInfoPrintDismisser->Cancel();
+	iInfoPrintDismisser->Start(0, KInfoPrintTime, TCallBack(&DismissInfoPrint, this));
+	return result;
+	}
+
+RFs& CCommandWindow::Fs()
+	{
+	return iFs;
+	}
+
+void CCommandWindow::LeoHandleLine(const TDesC& aLine)
+	{
+	iFinished = ETrue;
+	*iResultForQuery = aLine.Left(iResultForQuery->MaxLength());
+	}
+
+_LIT(KFileNameSlash, "\\");
+_LIT(KDriveColonSlash, ":\\");
+_LIT(KTab, "\t");
+_LIT(KSpace, " ");
+
+// This code ripped from ptf
+void CCommandWindow::LcCompleteLineL(TConsoleLine& aLine, const TChar& /*aEscapeChar*/)
+	{
+	if (iLineEditor != iFileNameLineEditor) return; // Don't autocomplete for anything that isn't a filename
+
+	IoUtils::TFileName2 fileNameMatch;
+	fileNameMatch.Copy(aLine.ContentsToCursor());
+	
+	CDesCArray* suggestions = new(ELeave) CDesC16ArrayFlat(16);
+	CleanupStack::PushL(suggestions);
+
+	if (fileNameMatch.Length()==0)
+		{
+		SuggestDrivesL(suggestions);
+		}
+	else if (fileNameMatch.Length() == 2 && TChar(fileNameMatch[0]).IsAlpha() && fileNameMatch[1] == ':')
+		{
+		fileNameMatch.Append(KFileNameSlash);
+		}
+
+	if (!fileNameMatch.IsAbsolute())
+		{
+		fileNameMatch.MakeAbsoluteL(iFs);
+		}
+	
+	TPtrC relativeDir = aLine.ContentsToCursor();
+	relativeDir.Set(relativeDir.Left(relativeDir.LocateReverse('\\')+1)); // Remove any name to the right of the last backslash
+		
+	fileNameMatch.Append('*');
+	
+	CDir* files = NULL;
+	User::LeaveIfError(iFs.GetDir(fileNameMatch, KEntryAttNormal | KEntryAttDir, ESortByName, files));
+	CleanupStack::PushL(files);
+		
+	TInt numFiles = files->Count();
+	if (numFiles == 1)
+		{
+		fileNameMatch.SetLength(fileNameMatch.DriveAndPath().Length());
+		fileNameMatch.AppendComponentL((*files)[0].iName);
+		TEntry entry;
+		User::LeaveIfError(iFs.Entry(fileNameMatch, entry));
+		suggestions->AppendL(fileNameMatch.NameAndExt());
+		CompleteL(aLine, *suggestions, &relativeDir, entry.IsDir() ? &KFileNameSlash : NULL);
+		}
+	else if (numFiles > 0)
+		{
+		for (TInt i=0; i<numFiles; ++i)
+			{
+			suggestions->AppendL((*files)[i].iName);
+			}
+		CompleteL(aLine, *suggestions, &relativeDir, NULL);
+		}
+	
+	CleanupStack::PopAndDestroy(2, suggestions); // files, suggestions
+	}
+
+void CCommandWindow::SuggestDrivesL(CDesCArray* aSuggestions)
+	{
+	TDriveList drives;
+	User::LeaveIfError(iFs.DriveList(drives));
+	
+	for (TInt i=0; i<drives.Length(); ++i)
+		{
+		if (drives[i])
+			{
+			TBuf<3> buf;
+			
+			TChar driveChar;
+			User::LeaveIfError(iFs.DriveToChar(i, driveChar));
+			
+			buf.Append(driveChar);
+			buf.Append(KDriveColonSlash);
+			aSuggestions->AppendL(buf);						
+			}
+		}
+	}
+	
+void CCommandWindow::CompleteL(TConsoleLine& aLine, const CDesCArray& aPossibilities, const TDesC* aPrefix, const TDesC* aSuffix)
+	{
+	const TInt numPossibilities = aPossibilities.Count();
+
+	if (numPossibilities > 1)
+		{
+		// Fill out possibilities buffer.
+		IoUtils::CTextBuffer* possibilities = IoUtils::CTextBuffer::NewLC(0x100);
+		for (TInt i = 0; i < numPossibilities; ++i)
+			{
+			possibilities->AppendL(aPossibilities[i]);
+			if (i != (numPossibilities - 1))
+				{
+				possibilities->AppendL(KTab);
+				}
+			}
+
+		aLine.PrintCompletionPossibilitiesL(possibilities->Descriptor());
+		CleanupStack::PopAndDestroy(possibilities);
+		}
+
+	if (numPossibilities > 0)
+		{
+		IoUtils::CTextBuffer* completion = IoUtils::CTextBuffer::NewLC(0x100);
+		TPtrC commonChars(NULL, 0);
+		if (numPossibilities > 1)
+			{
+			// Find common leading characters of the possibilities.
+			TInt commonCharPos = -1;
+			TBool finished(EFalse);
+			do
+				{
+				++commonCharPos;
+				TChar character(0);
+				for (TInt i = 0; i < numPossibilities; ++i)
+					{
+					if (commonCharPos >= aPossibilities[i].Length())
+						{
+						finished = ETrue;
+						break;
+						}
+					else if (i == 0)
+						{
+						character = aPossibilities[0][commonCharPos];
+						character.Fold();
+						}
+					else
+						{
+						TChar c(aPossibilities[i][commonCharPos]);
+						c.Fold();
+						if (c != character)
+							{
+							finished = ETrue;
+							break;
+							}
+						}
+					}
+				}
+				while (!finished);
+
+			commonChars.Set(aPossibilities[0].Mid(0, commonCharPos));
+			}
+		else
+			{
+			commonChars.Set(aPossibilities[0]);
+			}
+
+		if (aPrefix)
+			{
+			completion->AppendL(*aPrefix);
+			}
+		completion->AppendL(commonChars);
+
+		if ((numPossibilities == 1) && (aSuffix))
+			{
+			completion->AppendL(*aSuffix);
+			}
+			
+		if ((numPossibilities == 1) && (!aSuffix))
+			{
+			completion->AppendL(KSpace);
+			}
+			
+		if (completion->Descriptor().Length() > 0)
+			{
+			aLine.Replace(0, completion->Descriptor());
+			}
+		CleanupStack::PopAndDestroy(completion);
+		}
+	}