os/kernelhwsrv/userlibandfileserver/fileserver/etshell/ts_clicomp.cpp
author sl@SLION-WIN7.fritz.box
Fri, 15 Jun 2012 03:10:57 +0200
changeset 0 bde4ae8d615e
permissions -rw-r--r--
First public contribution.
sl@0
     1
// Copyright (c) 1996-2009 Nokia Corporation and/or its subsidiary(-ies).
sl@0
     2
// All rights reserved.
sl@0
     3
// This component and the accompanying materials are made available
sl@0
     4
// under the terms of the License "Eclipse Public License v1.0"
sl@0
     5
// which accompanies this distribution, and is available
sl@0
     6
// at the URL "http://www.eclipse.org/legal/epl-v10.html".
sl@0
     7
//
sl@0
     8
// Initial Contributors:
sl@0
     9
// Nokia Corporation - initial contribution.
sl@0
    10
//
sl@0
    11
// Contributors:
sl@0
    12
//
sl@0
    13
// Description:
sl@0
    14
// f32\etshell\ts_clicomp.cpp
sl@0
    15
// 
sl@0
    16
//
sl@0
    17
sl@0
    18
#include "ts_clicomp.h"
sl@0
    19
#include "ts_std.h"
sl@0
    20
sl@0
    21
CCliCompleter::CCliCompleter()
sl@0
    22
	{	
sl@0
    23
	}
sl@0
    24
	
sl@0
    25
CCliCompleter* CCliCompleter::NewL()
sl@0
    26
	{
sl@0
    27
	CCliCompleter* self = new(ELeave) CCliCompleter();
sl@0
    28
	CleanupStack::PushL(self);
sl@0
    29
	self->ConstructL();
sl@0
    30
	CleanupStack::Pop();
sl@0
    31
	
sl@0
    32
	return self;
sl@0
    33
	}
sl@0
    34
	
sl@0
    35
void CCliCompleter::ConstructL()
sl@0
    36
	{
sl@0
    37
	User::LeaveIfError(iFs.Connect());
sl@0
    38
	}
sl@0
    39
sl@0
    40
CCliCompleter::~CCliCompleter()
sl@0
    41
	{
sl@0
    42
	iFs.Close();
sl@0
    43
	}
sl@0
    44
sl@0
    45
void CCliCompleter::EstablishCompletionContext(TDesC& aBuf, TUint aPos, TDes& aKnownPart)
sl@0
    46
	{
sl@0
    47
	// Try and locate a double-quote to the left of the current cursor position
sl@0
    48
	TInt contextStart = aBuf.Mid(0, aPos).LocateReverse(TChar('"'));	
sl@0
    49
	TInt contextEnd;
sl@0
    50
	
sl@0
    51
	if(contextStart != KErrNotFound)
sl@0
    52
		{ // Double-quote found
sl@0
    53
		contextEnd = aPos - contextStart;
sl@0
    54
		// Grab a copy of the text we will be trying to complete
sl@0
    55
		aKnownPart = aBuf.Mid(contextStart, contextEnd);
sl@0
    56
		}
sl@0
    57
	else
sl@0
    58
		{ // Try from the last space character
sl@0
    59
		contextStart = aBuf.Mid(0, aPos).LocateReverse(TChar(' '));
sl@0
    60
sl@0
    61
		if(contextStart == KErrNotFound)
sl@0
    62
			{
sl@0
    63
			contextStart = 0;
sl@0
    64
			}
sl@0
    65
		else
sl@0
    66
			{
sl@0
    67
			contextStart += 1;
sl@0
    68
			}
sl@0
    69
			
sl@0
    70
		contextEnd = aPos - contextStart;
sl@0
    71
sl@0
    72
		aKnownPart = aBuf.Mid(contextStart, contextEnd);
sl@0
    73
		aKnownPart.Trim();
sl@0
    74
		}
sl@0
    75
	}
sl@0
    76
sl@0
    77
TBool CCliCompleter::AttemptCompletionL(TDes& aKnownPart, RPointerArray<HBufC>& aAlternatives)
sl@0
    78
	{
sl@0
    79
	// Turn the known part into something with a path
sl@0
    80
	TParse parsedKnownPart;
sl@0
    81
sl@0
    82
	// ShellFunction::GetFullPath() modifies the source path so create
sl@0
    83
	// a temporary buffer for a throwaway copy
sl@0
    84
	TBuf<KMaxPath> tmpKnownPart = aKnownPart;
sl@0
    85
	ShellFunction::StripQuotes(tmpKnownPart);
sl@0
    86
	tmpKnownPart.Append(KMatchAny);
sl@0
    87
	
sl@0
    88
	if(ShellFunction::GetFullPath(tmpKnownPart, parsedKnownPart) != KErrNone)
sl@0
    89
		{
sl@0
    90
		return EFalse;
sl@0
    91
		}
sl@0
    92
	
sl@0
    93
	CDir* entries;	
sl@0
    94
	if(iFs.GetDir(parsedKnownPart.FullName(), KEntryAttNormal | KEntryAttDir, ESortByName, entries) != KErrNone)
sl@0
    95
		{
sl@0
    96
		return EFalse;
sl@0
    97
		}
sl@0
    98
sl@0
    99
	CleanupStack::PushL(entries);
sl@0
   100
sl@0
   101
	TEntry entry;
sl@0
   102
	TBool result;
sl@0
   103
sl@0
   104
	if(entries->Count() == 1)
sl@0
   105
		{
sl@0
   106
		entry = (*entries)[0];
sl@0
   107
	
sl@0
   108
		TPtrC completedPart;	
sl@0
   109
		completedPart.Set(entry.iName.Mid(parsedKnownPart.NameAndExt().Length() - 1));
sl@0
   110
		aKnownPart.Append(completedPart);
sl@0
   111
sl@0
   112
		if(entry.IsDir()) aKnownPart.Append(KPathDelimiter);
sl@0
   113
		
sl@0
   114
		if(((TUint)aKnownPart[0] != TChar('"')) && 
sl@0
   115
			(aKnownPart.LocateF(TChar(' ')) != KErrNotFound))
sl@0
   116
			{
sl@0
   117
			aKnownPart.Insert(0, _L("\""));
sl@0
   118
			}
sl@0
   119
		
sl@0
   120
		result = ETrue;
sl@0
   121
		}
sl@0
   122
	else if(entries->Count() > 1)
sl@0
   123
		{
sl@0
   124
		TInt entryIdx;		
sl@0
   125
		
sl@0
   126
		// Find the smallest matching entry so as to not run off the end of
sl@0
   127
		// an index when trying to establish the greatest overlap between the
sl@0
   128
		// matches.  We're also caching the raw entries in a seperate array so
sl@0
   129
		// we can use them when displaying the ambiguous matches.
sl@0
   130
		TInt minLength = KMaxFileName;		
sl@0
   131
		
sl@0
   132
		for(entryIdx=0;entryIdx<entries->Count();entryIdx++)
sl@0
   133
			{
sl@0
   134
			entry = (*entries)[entryIdx];
sl@0
   135
			
sl@0
   136
			HBufC* buf = HBufC::NewLC(entry.iName.Length() + 100);
sl@0
   137
			*buf = entry.iName;
sl@0
   138
			if(entry.IsDir()) 
sl@0
   139
				{
sl@0
   140
				buf->Des().Append(KPathDelimiter);
sl@0
   141
				}
sl@0
   142
			aAlternatives.AppendL(buf);
sl@0
   143
			
sl@0
   144
			if(entry.iName.Length() < minLength)
sl@0
   145
				{
sl@0
   146
				minLength = entry.iName.Length();
sl@0
   147
				}
sl@0
   148
			}
sl@0
   149
		CleanupStack::Pop(entries->Count());
sl@0
   150
			
sl@0
   151
		// Find the greatest overlap between the matches.  Even though we can't
sl@0
   152
		// get a final match we can at least make a best-effort completion based 
sl@0
   153
		// on anything they've not told us but which matches anyway.
sl@0
   154
		
sl@0
   155
		// There's an asterisk on the end of the parsed filename that we want
sl@0
   156
		// to disregard when calculating the length of what we already know.
sl@0
   157
		TInt knownPartLength = parsedKnownPart.NameAndExt().Length() - 1;
sl@0
   158
		
sl@0
   159
		TInt matchLength = knownPartLength;
sl@0
   160
		TBool matching = ETrue;
sl@0
   161
		while(matching && matchLength < minLength)
sl@0
   162
			{			
sl@0
   163
			for(entryIdx=1;entryIdx<entries->Count();entryIdx++)
sl@0
   164
				{
sl@0
   165
				if(((*entries)[0].iName[matchLength]) != ((*entries)[entryIdx].iName[matchLength]))
sl@0
   166
					{
sl@0
   167
					matching = EFalse;
sl@0
   168
					}
sl@0
   169
				}
sl@0
   170
			if(matching) matchLength++;
sl@0
   171
			}
sl@0
   172
sl@0
   173
		if(matchLength > knownPartLength)
sl@0
   174
			{
sl@0
   175
			entry = (*entries)[0];
sl@0
   176
			
sl@0
   177
			TUint additionalKnownStart = knownPartLength;
sl@0
   178
			TUint additionalKnownLength = matchLength - knownPartLength;
sl@0
   179
			
sl@0
   180
			aKnownPart.Append(entry.iName.Mid(additionalKnownStart, additionalKnownLength));
sl@0
   181
			}
sl@0
   182
sl@0
   183
		result = EFalse;
sl@0
   184
		}
sl@0
   185
	else	
sl@0
   186
		{
sl@0
   187
		result = EFalse;
sl@0
   188
		}
sl@0
   189
	
sl@0
   190
	CleanupStack::PopAndDestroy(entries);
sl@0
   191
	
sl@0
   192
	return result;
sl@0
   193
	}
sl@0
   194
sl@0
   195
sl@0
   196
/*
sl@0
   197
	Note: method has the potential to modify the size of aAlternatives as 
sl@0
   198
	a side-effect of the call to ShellFunction::AlignTextIntoColumns().
sl@0
   199
*/
sl@0
   200
void CCliCompleter::DisplayAlternatives(RPointerArray<HBufC>& aAlternatives)
sl@0
   201
	{
sl@0
   202
	ShellFunction::AlignTextIntoColumns(aAlternatives);
sl@0
   203
	
sl@0
   204
	CShell::NewLine();
sl@0
   205
	for(TInt entryIdx=0;entryIdx<aAlternatives.Count();entryIdx++)
sl@0
   206
		{
sl@0
   207
		CShell::OutputStringToConsole(EFalse, *aAlternatives[entryIdx]);
sl@0
   208
		CShell::NewLine();
sl@0
   209
		}
sl@0
   210
	}