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