diff -r 000000000000 -r 7f656887cf89 commands/fed/src/cmdwindow.cpp --- /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 +#include + +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 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 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(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; iAppendL((*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 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); + } + }