|
1 /* |
|
2 * Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "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 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * Implementation of RecentUrlStore |
|
16 * |
|
17 * |
|
18 */ |
|
19 |
|
20 |
|
21 |
|
22 // INCLUDE FILES |
|
23 #include "RecentUrlStore.h" |
|
24 |
|
25 // EXTERNAL DATA STRUCTURES |
|
26 |
|
27 // EXTERNAL FUNCTION PROTOTYPES |
|
28 |
|
29 // CONSTANTS |
|
30 |
|
31 // MACROS |
|
32 |
|
33 // LOCAL CONSTANTS AND MACROS |
|
34 _LIT(KRecentUrlDBFile, "c:\\private\\%08x\\RecentUrlStore.db"); |
|
35 |
|
36 _LIT(KSQLInsertVersion, "INSERT INTO dbversion (dbver) VALUES ('1.0')"); |
|
37 |
|
38 /* |
|
39 * Database columns: |
|
40 * History - counter used to order the urls latest first |
|
41 * Url - url of visited page |
|
42 */ |
|
43 _LIT(KVersionTableSQL, "CREATE TABLE dbversion(dbver CHAR(10))"); |
|
44 _LIT(KRecentUrlTableSQL, "CREATE TABLE recenturl(history COUNTER, domain VARCHAR(50), url VARCHAR(250), title VARCHAR(250))"); |
|
45 const TUint KDomainSize = 50; |
|
46 const TUint KUrlSize = 250; |
|
47 const TUint KTitleSize = 250; |
|
48 |
|
49 _LIT(KIndex1SQL, "CREATE INDEX updateidx ON recenturl (history)"); |
|
50 |
|
51 _LIT(KSQLInsert, "INSERT INTO recenturl (domain,url,title) VALUES ('%S','%S', '%S')"); |
|
52 _LIT(KSQLDelete, "DELETE FROM recenturl WHERE url = '%S'"); |
|
53 _LIT(KSQLSelect, "SELECT url,title FROM recenturl WHERE domain LIKE '%S*' OR url LIKE '*://%S*' ORDER BY history desc"); |
|
54 _LIT(KSQLSelectAll, "SELECT url,title FROM recenturl ORDER BY history desc"); |
|
55 const TUint KUrlCol = 1; |
|
56 const TUint KTitleCol = 2; |
|
57 |
|
58 const TUint KMaxRows = 100; |
|
59 |
|
60 _LIT(KDomainDelim, "."); // domain starts after first '.' and ends after second '.' |
|
61 |
|
62 // MODULE DATA STRUCTURES |
|
63 |
|
64 // LOCAL FUNCTION PROTOTYPES |
|
65 |
|
66 // FORWARD DECLARATIONS |
|
67 |
|
68 // ============================= FUNCTIONS =============================== |
|
69 |
|
70 // ----------------------------------------------------------------------------- |
|
71 // CRecentUrlStore::NewLC |
|
72 // Two-phased constructor. |
|
73 // ----------------------------------------------------------------------------- |
|
74 EXPORT_C CRecentUrlStore * CRecentUrlStore::NewL () |
|
75 { |
|
76 CRecentUrlStore* self = new (ELeave) CRecentUrlStore(); |
|
77 self->ConstructL(); |
|
78 return self; |
|
79 |
|
80 } |
|
81 |
|
82 // ----------------------------------------------------------------------------- |
|
83 // CRecentUrlStore::CRecentUrlStore |
|
84 // C++ default constructor can NOT contain any code, that might leave. |
|
85 // ----------------------------------------------------------------------------- |
|
86 CRecentUrlStore::CRecentUrlStore(): |
|
87 iFirstTimeOpened(ETrue) |
|
88 { |
|
89 |
|
90 } |
|
91 |
|
92 // ----------------------------------------------------------------------------- |
|
93 // CRecentUrlStore::ConstructL |
|
94 // Symbian 2nd phase constructor can leave. |
|
95 // ----------------------------------------------------------------------------- |
|
96 void CRecentUrlStore::ConstructL() |
|
97 { |
|
98 |
|
99 // Create the file name from UID |
|
100 RProcess myProcess; |
|
101 TBuf <256>buf; |
|
102 buf.Format(KRecentUrlDBFile, myProcess.Identity()); |
|
103 iRecentUrlDBFile = buf.AllocL(); |
|
104 |
|
105 User::LeaveIfError(iDbSession.Connect()); |
|
106 |
|
107 } |
|
108 |
|
109 //----------------------------------------------------------------------------- |
|
110 // CRecentUrlStore Destructor |
|
111 //----------------------------------------------------------------------------- |
|
112 CRecentUrlStore::~CRecentUrlStore() |
|
113 { |
|
114 iDbSession.Close(); |
|
115 delete iRecentUrlDBFile; |
|
116 } |
|
117 |
|
118 |
|
119 //----------------------------------------------------------------------------- |
|
120 // CRecentUrlStore::GetData |
|
121 // params aUrl - Url filter |
|
122 // Returns matching urls. |
|
123 //----------------------------------------------------------------------------- |
|
124 EXPORT_C TInt CRecentUrlStore::GetData (CDesCArray& aUrls, CDesCArray& aTitles, const TDesC& aUrl) |
|
125 { |
|
126 RDbNamedDatabase dataBase; |
|
127 TInt err = OpenDatabase(dataBase); |
|
128 if (err == KErrNone) |
|
129 { |
|
130 TRAP(err, GetDataL(dataBase, aUrls, aTitles, aUrl)); |
|
131 dataBase.Close(); |
|
132 } |
|
133 return err; |
|
134 } |
|
135 //----------------------------------------------------------------------------- |
|
136 // CRecentUrlStore::GetData |
|
137 // params aUrl - Url filter |
|
138 // Returns matching urls. |
|
139 //----------------------------------------------------------------------------- |
|
140 void CRecentUrlStore::GetDataL (RDbNamedDatabase& aDataBase, |
|
141 CDesCArray& aUrls, CDesCArray& aTitles, const TDesC& aUrl) |
|
142 { |
|
143 |
|
144 TInt rowCount(0); |
|
145 |
|
146 // select values from the database filtered by url |
|
147 if (aUrl.Length()) |
|
148 { |
|
149 HBufC* domain = aUrl.AllocLC(); |
|
150 domain->Des().LowerCase(); |
|
151 iSQLStatement.Format(KSQLSelect, domain, domain); |
|
152 CleanupStack::PopAndDestroy(); |
|
153 } |
|
154 else |
|
155 { |
|
156 iSQLStatement.Format(KSQLSelectAll); |
|
157 } |
|
158 |
|
159 |
|
160 RDbView view; |
|
161 |
|
162 TInt err = view.Prepare(aDataBase, TDbQuery(iSQLStatement)); |
|
163 if (err == KErrNone) |
|
164 { |
|
165 err = view.EvaluateAll(); |
|
166 if (err == KErrNone) |
|
167 { |
|
168 view.FirstL(); |
|
169 // loop through rows and build the list |
|
170 while (view.AtRow() && rowCount++ < KMaxRows) |
|
171 { |
|
172 view.GetL(); |
|
173 aUrls.AppendL(view.ColDes(KUrlCol)); |
|
174 aTitles.AppendL(view.ColDes(KTitleCol)); |
|
175 view.NextL(); |
|
176 } |
|
177 /* |
|
178 * This loop will keep the number of rows in the database at a reasonable size by |
|
179 * deleting old rows (deletes rows beyond KMaxRows). Should be at most 1 row deleted. |
|
180 * Its more efficiant to delete it here than in the SaveData because in this function |
|
181 * we already have the list and know its size |
|
182 */ |
|
183 while (view.AtRow()) |
|
184 { |
|
185 view.GetL(); |
|
186 iSQLStatement.Format(KSQLDelete, &aUrl); |
|
187 aDataBase.Execute(iSQLStatement); |
|
188 view.NextL(); |
|
189 } |
|
190 } |
|
191 } |
|
192 view.Close(); |
|
193 } |
|
194 |
|
195 //----------------------------------------------------------------------------- |
|
196 // CRecentUrlStore::DeleteData |
|
197 // Deletes a single row from the database. |
|
198 //----------------------------------------------------------------------------- |
|
199 EXPORT_C void CRecentUrlStore::DeleteData (const TDesC& aUrl) |
|
200 { |
|
201 RDbNamedDatabase dataBase; |
|
202 if (OpenDatabase(dataBase) == KErrNone) |
|
203 { |
|
204 iSQLStatement.Format(KSQLDelete, &aUrl); |
|
205 dataBase.Execute(iSQLStatement); |
|
206 dataBase.Close(); |
|
207 } |
|
208 } |
|
209 |
|
210 //----------------------------------------------------------------------------- |
|
211 // CRecentUrlStore::SaveDataL |
|
212 // Save the url in store. |
|
213 //----------------------------------------------------------------------------- |
|
214 EXPORT_C void CRecentUrlStore::SaveData (const TDesC& aUrl, const TDesC& aTitle) |
|
215 { |
|
216 RDbNamedDatabase dataBase; |
|
217 TInt urlLength (aUrl.Length()); |
|
218 |
|
219 // shouldn't happen but if it's too long for the data store just skip it! |
|
220 if (urlLength > KUrlSize) |
|
221 { |
|
222 return; |
|
223 } |
|
224 |
|
225 if (OpenDatabase(dataBase) == KErrNone) |
|
226 { |
|
227 // find the point where the domain starts and ends |
|
228 TInt domainLength(urlLength); |
|
229 TInt domainStart(0); |
|
230 |
|
231 TInt startPos = aUrl.Find(KDomainDelim); |
|
232 if (startPos != KErrNotFound) |
|
233 { |
|
234 domainStart = startPos + (KDomainDelim().Length()); // first char after delim |
|
235 TInt len = aUrl.Right(urlLength - domainStart).Find(KDomainDelim); |
|
236 if (len > 0) // ignore delim following delim. we don't want an empty string |
|
237 { |
|
238 domainLength = len; |
|
239 } |
|
240 else |
|
241 { |
|
242 domainLength -= domainStart; |
|
243 } |
|
244 } |
|
245 |
|
246 // make sure it's not too big for the data store |
|
247 domainLength = (domainLength > KDomainSize) ? KDomainSize : domainLength; |
|
248 TInt titleLength = (aTitle.Length() > KTitleSize) ? KTitleSize : aTitle.Length(); |
|
249 |
|
250 HBufC* domain = aUrl.Mid(domainStart,domainLength).AllocLC(); |
|
251 domain->Des().LowerCase(); |
|
252 HBufC* title = aTitle.Left(titleLength).AllocLC(); |
|
253 |
|
254 // delete and re-insert |
|
255 iSQLStatement.Format(KSQLDelete, &aUrl); |
|
256 dataBase.Execute(iSQLStatement); |
|
257 iSQLStatement.Format(KSQLInsert, domain, &aUrl, title); |
|
258 CleanupStack::PopAndDestroy(2); // domain, title |
|
259 |
|
260 dataBase.Execute(iSQLStatement); |
|
261 dataBase.Close(); |
|
262 } |
|
263 } |
|
264 |
|
265 //----------------------------------------------------------------------------- |
|
266 // CRecentUrlStore::ClearData |
|
267 // Clear the store. |
|
268 //----------------------------------------------------------------------------- |
|
269 EXPORT_C void CRecentUrlStore::ClearData () |
|
270 { |
|
271 // the quickest way to clear the data is to re-create it |
|
272 TRAP_IGNORE(CreateDatabaseL()); |
|
273 } |
|
274 |
|
275 |
|
276 // private |
|
277 //----------------------------------------------------------------------------- |
|
278 // CRecentUrlStore::DeleteOldRowsL |
|
279 //----------------------------------------------------------------------------- |
|
280 void CRecentUrlStore::DeleteOldRowsL (RDbNamedDatabase& aDataBase) |
|
281 { |
|
282 |
|
283 TInt rowCount(0); |
|
284 |
|
285 iSQLStatement.Format(KSQLSelectAll); |
|
286 |
|
287 RDbView view; |
|
288 |
|
289 TInt err = view.Prepare(aDataBase, TDbQuery(iSQLStatement)); |
|
290 if (err == KErrNone) |
|
291 { |
|
292 err = view.EvaluateAll(); |
|
293 if (err == KErrNone) |
|
294 { |
|
295 view.FirstL(); |
|
296 // loop through rows we want to keep |
|
297 while (view.AtRow() && rowCount++ < KMaxRows) |
|
298 { |
|
299 view.NextL(); |
|
300 } |
|
301 // delete the rows that are old |
|
302 while (view.AtRow()) |
|
303 { |
|
304 view.DeleteL(); |
|
305 view.NextL(); |
|
306 } |
|
307 } |
|
308 } |
|
309 view.Close(); |
|
310 } |
|
311 |
|
312 //----------------------------------------------------------------------------- |
|
313 // CRecentUrlStore::OpenDatabase |
|
314 // Open the data store. |
|
315 //----------------------------------------------------------------------------- |
|
316 TInt CRecentUrlStore::OpenDatabase(RDbNamedDatabase& aDataBase) |
|
317 { |
|
318 TInt error = KErrNone; |
|
319 // open the database - create if it doesn't exist |
|
320 error = aDataBase.Open(iDbSession, *iRecentUrlDBFile); |
|
321 // compact it once during our session |
|
322 if (error == KErrNone && iFirstTimeOpened) |
|
323 { |
|
324 TRAP_IGNORE(DeleteOldRowsL(aDataBase)); |
|
325 aDataBase.Compact(); |
|
326 iFirstTimeOpened = EFalse; |
|
327 } |
|
328 |
|
329 if (error != KErrNone) |
|
330 { |
|
331 TRAP(error,CreateDatabaseL()); |
|
332 if (error == KErrNone) |
|
333 { |
|
334 error = aDataBase.Open(iDbSession, *iRecentUrlDBFile); |
|
335 } |
|
336 } |
|
337 return error; |
|
338 } |
|
339 |
|
340 //----------------------------------------------------------------------------- |
|
341 // CRecentUrlStore::CreateDatabaseL |
|
342 // Create the data store. |
|
343 //----------------------------------------------------------------------------- |
|
344 void CRecentUrlStore::CreateDatabaseL() |
|
345 { |
|
346 RDbNamedDatabase dataBase; |
|
347 User::LeaveIfError(dataBase.Replace(iDbSession, *iRecentUrlDBFile)); |
|
348 |
|
349 CleanupClosePushL(dataBase); |
|
350 User::LeaveIfError(dataBase.Execute(KVersionTableSQL)); |
|
351 User::LeaveIfError(dataBase.Execute(KRecentUrlTableSQL)); |
|
352 User::LeaveIfError(dataBase.Execute(KIndex1SQL)); |
|
353 User::LeaveIfError(dataBase.Execute(KSQLInsertVersion)); |
|
354 CleanupStack::PopAndDestroy();//dataBase |
|
355 |
|
356 } |
|
357 |
|
358 // End of File |