Merge lp://staging/~benoit.garret/tomdroid/storage-redesign into lp://staging/~tomdroid-maintainers/tomdroid/main
- storage-redesign
- Merge into main
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp://staging/~benoit.garret/tomdroid/storage-redesign |
Merge into: | lp://staging/~tomdroid-maintainers/tomdroid/main |
Diff against target: |
2075 lines (+648/-857) 16 files modified
AndroidManifest.xml (+1/-1) doc/dev/TODO (+3/-0) res/layout/load_web_note_dialog.xml (+0/-63) res/menu/main.xml (+1/-5) res/values/strings.xml (+3/-3) src/org/tomdroid/Note.java (+28/-18) src/org/tomdroid/NoteCollection.java (+0/-140) src/org/tomdroid/NoteManager.java (+154/-0) src/org/tomdroid/NoteProvider.java (+15/-1) src/org/tomdroid/ui/LoadWebNoteDialog.java (+0/-95) src/org/tomdroid/ui/Tomdroid.java (+33/-138) src/org/tomdroid/ui/ViewNote.java (+118/-106) src/org/tomdroid/util/AsyncNoteLoaderAndParser.java (+53/-41) src/org/tomdroid/util/NoteContentBuilder.java (+35/-77) src/org/tomdroid/xml/NoteContentHandler.java (+200/-0) src/org/tomdroid/xml/NoteHandler.java (+4/-169) |
To merge this branch: | bzr merge lp://staging/~benoit.garret/tomdroid/storage-redesign |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Olivier Bilodeau | Approve | ||
Review via email: mp+10978@code.staging.launchpad.net |
Commit message
Description of the change
Benoit Garret (benoit.garret) wrote : | # |
Olivier Bilodeau (plaxx) wrote : | # |
Big rough comment I quickly wrote down when I checked the commits. Its great work! Don't let my bad comments depress you in any way, I am a picky bastard. All of these items are easy to fix. Its just a matter of not losing track.
features
* remove close button, revno 142
* menuSyncWithSD remplaces automatic load, revno 143 (what about tango icon? for consistency)
* storage-redesign, revno 141, 144, 145, 146 (needs rework), 147, 148, 149, 150 (fixes problem introduced in 148), 151, 152, 153
foreseable bugs
* it doesn't do the right thing with a tomdroid/ filled sdcard right now (upgrade path broken)
* no mechansim to add notes in the list activity as of revno 144 (but its not necessary yet)
* revno 146, links directly from an activity to an external class that can take its time, bad. Always thread work that can be blocking (see http://
open design questions
* who should responsable of adding a note to the NoteProvider? Note, Async.. or NoteProvider? see revno 147
* Tomdroid UI with file exceptions.. I don't like that, I think we should abstract that away using a static class in util package maybe? revno 149
* is Java's guid methods working the same way as mono ones? revno 153, 154
issues
* revno 148, what's up with NoteHandler's job?
* revno 149, onListItemClick, we should do ID instead of filenames now? (maybe fixed by 151)
revno 152
* Note = new note() and setting content inside of ViewNote, that's not the spirit, ViewNote should fetch a note based on some criteria and ask it to show itself, it shouldn't have to deal with a note's details
* buildlinkify pattern, should it really end up there?
why is revno155 and 156 necessary? what is it solving?
revno 157 - review some TODO task withdrawn in this commit, are the TODO items removed really dealt with?
TODO
Integrate changes into ChangeLog / NEWS
Olivier Bilodeau (plaxx) wrote : | # |
I just cherrypicked the remove close commit.
Olivier Bilodeau (plaxx) wrote : | # |
I created a branch to re-work only your sd card changes: lp:~plaxx/tomdroid/load-from-sdcard
Only items remaining:
* do you have an SVG source for your refresh (sync) icon (for data/icon-src/)? what is it license?
* I used grayscaled tango icons so far, do you like tango's action/
Aside from these, its complete.
I branched out of revno 143 of your storage-redesign branch to avoid cruft and reverted the db change so I don't suggest a merge back in your storage-redesign but a merge straight to main/ instead. Give it an eyeball and let me know. If you want, branch it and do some more fixing.
Benoit Garret (benoit.garret) wrote : | # |
> Only items remaining:
> * do you have an SVG source for your refresh (sync) icon (for data/icon-src/)?
> what is it license?
I picked the icon in android git (http://
You can find it here: http://
> * I used grayscaled tango icons so far, do you like tango's action/view-
> refresh: http://
> ok, I *really* don't mind keeping yours, I'm just being a consistency freak ;)
I'm fine with your icon, the one I put was merely a placeholder before finding something that was more consistent with the other ones in Tomdroid.
And I agree with you, consistency should be enforced as much as we can.
Benoit Garret (benoit.garret) wrote : | # |
> Big rough comment I quickly wrote down when I checked the commits. Its great
> work! Don't let my bad comments depress you in any way, I am a picky bastard.
> All of these items are easy to fix. Its just a matter of not losing track.
I'm aware that the branch could use some work as I'm far from being an experienced programmer. But I'm comfortable with critics, keep them coming ;-).
> foreseable bugs
> * it doesn't do the right thing with a tomdroid/ filled sdcard right now
> (upgrade path broken)
The current behaviour is to overwrite the existing note with the same guid. This means it replaces the notes in the database with the ones on the SD card.
The problem I can see with this approach is that it doesn't delete the notes that don't exist anymore on the SD card. Apart from that, I don't see what would be broken in case of an upgrade.
> * no mechansim to add notes in the list activity as of revno 144 (but its not
> necessary yet)
The NoteProvider is used as the list store. This means the main list automatically picks up the notes that are inserted in the provider, there is no need to add them manually.
> * revno 146, links directly from an activity to an external class that can
> take its time, bad. Always thread work that can be blocking (see
> http://
Agreed, I put a TODO to put this code in a thread but I forgot about it.
> open design questions
> * who should responsable of adding a note to the NoteProvider? Note, Async..
> or NoteProvider? see revno 147
Good question. What I have in mind is an abstraction of the provider which is currently a bit cumbersome to use. Something like a NoteManager, responsible for dealing with the provider (ie. inserting notes, getting a Note object from the provider, etc).
This would make these operations easier to do as its interfaces would only deal with Note objects, but I don't know if adding something like this would be overkill or not.
> * Tomdroid UI with file exceptions.. I don't like that, I think we should
> abstract that away using a static class in util package maybe? revno 149
I completely agree with that. Moreover, I'm not comfortable with presenting the errors as modal popups in the application. Something less intrusive would be to use the notification area and only present the full error message if the user clicks on the notification.
> * is Java's guid methods working the same way as mono ones? revno 153, 154
I believe so, the java and mono implementation are based on a RFC. The mono one is based on the draft[0] while the java one is based on the actual RFC[1].
[0]http://
[1]http://
> issues
> * revno 148, what's up with NoteHandler's job?
Synchronization services like Snowy expect the note content to be sent as raw xml so I thought it would be a good idea to store it in the database.
The SpannableString
> * revno 149, onListItemClick, we ...
Olivier Bilodeau (plaxx) wrote : | # |
On Fri, Oct 2, 2009 at 2:21 PM, Benoit Garret <
<email address hidden>> wrote:
>
> > foreseable bugs
> > * it doesn't do the right thing with a tomdroid/ filled sdcard right now
> > (upgrade path broken)
>
> The current behaviour is to overwrite the existing note with the same guid.
> This means it replaces the notes in the database with the ones on the SD
> card.
>
>
I wasn't clear enough, what I meant was that when I first opened the app, it
was saying "no notes" although I knew that I had notes on the sd card. [Our
two] Users upgrading wouldn't expect that. In the sdcard branch, I added a
message that says that you need to sync first so this is fixed.
> The problem I can see with this approach is that it doesn't delete the
> notes that don't exist anymore on the SD card. Apart from that, I don't see
> what would be broken in case of an upgrade.
>
I added a TODO task in doc/dev/TODO to track that but I agree with you, this
is low-priority.
>
> > * no mechansim to add notes in the list activity as of revno 144 (but its
> not
> > necessary yet)
>
> The NoteProvider is used as the list store. This means the main list
> automatically picks up the notes that are inserted in the provider, there is
> no need to add them manually.
>
ok but the query on the provider is done at onCreate() time. What happens if
I add a note (I know this can't happen now but let's say it can) and come
back to the list without a re-run of onCreate() because the app was still in
memory. Will this be handled correctly? If you don't know, don't worry, we
will deal with it when the problem will surface.
[a few hours later]
Just did a propose for merge on your branch with some changes:
https:/
look at it while its manageable and i'll do some more reviewing when I have
time for it (maybe tomorrow night if not then it'll be next weekend..)
--
Olivier Bilodeau <email address hidden>
- 158. By Benoit Garret
-
Merged main (incl. changes from the load-from-sdcard branch)
- 159. By Benoit Garret
-
Merge lp:~plaxx/tomdroid/storage-redesign, rev. 159 & 160.
- 160. By Benoit Garret
-
Remove the NoteCollection, it isn't used anywhere.
- 161. By Benoit Garret
-
Remove the load note from web feature.
- 162. By Benoit Garret
-
Created a NoteManager to handle the interactions with the content provider.
- 163. By Benoit Garret
-
Note.java: use NoteBuilder to parse the xml content
ViewNote.java: handle the asynchronous nature of Note.getNoteContent
NoteBuiler.java: handle the note content instead of the full note (ie. return a SpannableStringBuilder instead of a Note) - 164. By Benoit Garret
-
Merged Olivier's branch
- 165. By Benoit Garret
-
Miscellaneous cleaning.
- 166. By Benoit Garret
-
Make the NoteManager methods static (the NoteManager didn't really have a state)
Olivier Bilodeau (plaxx) wrote : | # |
Wow! I can't believe how much cruft was removed by this work. There were ugly pieces I did that we got rid of thanks to you!
Ok, I finally merged, here are the few things I've changed in the merge commit:
- added a toaster dialog to say that /sdcard/tomdroid/ is empty if you do an sdcard sync with nothing in that folder
- added/removed comments
- ViewNote's inner classes now private (instead of public and package)
I'm very satisfied of what you did. Thanks again!
Now, if you pull this new main into web-sync, how much effort would it take you to have it working and manageable / reviewable for someone like me? :)
Preview Diff
1 | === modified file 'AndroidManifest.xml' |
2 | --- AndroidManifest.xml 2009-10-05 04:28:32 +0000 |
3 | +++ AndroidManifest.xml 2010-01-17 18:10:19 +0000 |
4 | @@ -26,7 +26,7 @@ |
5 | </intent-filter> |
6 | </activity> |
7 | |
8 | - <activity android:name=".ui.LoadWebNoteDialog" android:theme="@android:style/Theme.Dialog"></activity> |
9 | + |
10 | |
11 | <provider android:name="NoteProvider" |
12 | android:authorities="org.tomdroid.notes" |
13 | |
14 | === modified file 'doc/dev/TODO' |
15 | --- doc/dev/TODO 2009-06-25 01:17:57 +0000 |
16 | +++ doc/dev/TODO 2010-01-17 18:10:19 +0000 |
17 | @@ -16,6 +16,9 @@ |
18 | Port threading to Android's mechanism (maybe wait to check for 1.5's new API): |
19 | - Check Handler / Looper / AsyncQueryHandler classes |
20 | |
21 | +SD card sync: |
22 | +- Syncing from SD card only adds notes from the SD card and overwrite on identical guid. At some point, we'll have to consider deletions. |
23 | + |
24 | File format: (to be in sync with Tomdroid's) |
25 | - Why is title repeated in note text? |
26 | - check everrnote dtd for inspiration: http://www.evernote.com/about/developer/ |
27 | |
28 | === removed file 'res/layout/load_web_note_dialog.xml' |
29 | --- res/layout/load_web_note_dialog.xml 2009-06-21 20:21:30 +0000 |
30 | +++ res/layout/load_web_note_dialog.xml 1970-01-01 00:00:00 +0000 |
31 | @@ -1,63 +0,0 @@ |
32 | -<?xml version="1.0" encoding="utf-8"?> |
33 | -<!-- |
34 | - Tomdroid |
35 | - Tomboy on Android |
36 | - http://www.launchpad.net/tomdroid |
37 | - |
38 | - Copyright 2008 Olivier Bilodeau <olivier@bottomlesspit.org> |
39 | - |
40 | - This file is part of Tomdroid. |
41 | - |
42 | - Tomdroid is free software: you can redistribute it and/or modify |
43 | - it under the terms of the GNU General Public License as published by |
44 | - the Free Software Foundation, either version 3 of the License, or |
45 | - (at your option) any later version. |
46 | - |
47 | - Tomdroid is distributed in the hope that it will be useful, |
48 | - but WITHOUT ANY WARRANTY; without even the implied warranty of |
49 | - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
50 | - GNU General Public License for more details. |
51 | - |
52 | - You should have received a copy of the GNU General Public License |
53 | - along with Tomdroid. If not, see <http://www.gnu.org/licenses/>. |
54 | ---> |
55 | -<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" |
56 | - android:orientation="vertical" |
57 | - android:layout_width="fill_parent" |
58 | - android:layout_height="wrap_content" |
59 | - android:padding="10dip" |
60 | - > |
61 | - |
62 | - <TextView android:id="@+id/strURL" |
63 | - android:layout_width="fill_parent" |
64 | - android:layout_height="wrap_content" |
65 | - android:text="@string/strURL" |
66 | - /> |
67 | - |
68 | - <EditText android:id="@+id/txtURL" |
69 | - android:text="http://" |
70 | - android:singleLine="true" |
71 | - android:nextFocusDown="@+id/btnOk" |
72 | - android:layout_width="fill_parent" |
73 | - android:layout_height="wrap_content" |
74 | - android:layout_below="@+id/strURL" |
75 | - /> |
76 | - |
77 | - <Button android:id="@+id/btnOk" |
78 | - android:layout_width="wrap_content" |
79 | - android:layout_height="wrap_content" |
80 | - android:layout_below="@+id/txtURL" |
81 | - android:text="@string/btnOk" |
82 | - android:layout_alignParentRight="true" |
83 | - android:layout_marginLeft="10pt" |
84 | - /> |
85 | - |
86 | - <Button android:id="@+id/btnCancel" |
87 | - android:layout_width="wrap_content" |
88 | - android:layout_height="wrap_content" |
89 | - android:layout_toLeftOf="@+id/btnOk" |
90 | - android:layout_alignTop="@+id/btnOk" |
91 | - android:text="@string/btnCancel" |
92 | - /> |
93 | - |
94 | -</RelativeLayout> |
95 | \ No newline at end of file |
96 | |
97 | === modified file 'res/menu/main.xml' |
98 | --- res/menu/main.xml 2009-10-03 16:26:37 +0000 |
99 | +++ res/menu/main.xml 2010-01-17 18:10:19 +0000 |
100 | @@ -23,11 +23,7 @@ |
101 | --> |
102 | <menu xmlns:android="http://schemas.android.com/apk/res/android"> |
103 | |
104 | - <item |
105 | - android:icon="@drawable/icon_load_from_web" |
106 | - android:title="@string/menuLoadWebNote" |
107 | - android:id="@+id/menuLoadWebNote" |
108 | - /> |
109 | + |
110 | |
111 | <item |
112 | android:icon="@drawable/icon_about" |
113 | |
114 | === modified file 'res/values/strings.xml' |
115 | --- res/values/strings.xml 2009-10-03 16:26:37 +0000 |
116 | +++ res/values/strings.xml 2010-01-17 18:10:19 +0000 |
117 | @@ -32,7 +32,7 @@ |
118 | There are no notes in Tomdroid\'s database. Make sure you copied Tomboy\'s note files (*.note) in |
119 | the tomdroid/ directory on your sdcard then press \"Menu\" and \"Sync with SD Card\". |
120 | </string> |
121 | - <string name="menuLoadWebNote">Note from the Web</string> |
122 | + |
123 | <string name="menuSyncWithSD">Sync with SD Card</string> |
124 | <string name="menuAbout">About</string> |
125 | <string name="strWelcome"> |
126 | @@ -54,8 +54,8 @@ |
127 | </string> |
128 | |
129 | <!-- load_web_note_dialog.xml --> |
130 | - <string name="strLoadFromWebTitle">Note from the Web</string> |
131 | - <string name="strURL">Enter the Note\'s URL:</string> |
132 | + |
133 | + |
134 | <!-- TODO are these really needed!? --> |
135 | <string name="btnOk">Ok</string> |
136 | <string name="btnCancel">Cancel</string> |
137 | |
138 | === modified file 'src/org/tomdroid/Note.java' |
139 | --- src/org/tomdroid/Note.java 2009-06-21 20:25:16 +0000 |
140 | +++ src/org/tomdroid/Note.java 2010-01-17 18:10:19 +0000 |
141 | @@ -22,27 +22,26 @@ |
142 | */ |
143 | package org.tomdroid; |
144 | |
145 | +import java.util.UUID; |
146 | + |
147 | import org.joda.time.DateTime; |
148 | import org.joda.time.format.DateTimeFormatter; |
149 | import org.joda.time.format.ISODateTimeFormat; |
150 | +import org.tomdroid.util.NoteContentBuilder; |
151 | |
152 | -import android.text.Spannable; |
153 | +import android.os.Handler; |
154 | import android.text.SpannableStringBuilder; |
155 | -import android.text.style.StyleSpan; |
156 | |
157 | public class Note { |
158 | |
159 | // Static references to fields (used in Bundles, ContentResolvers, etc.) |
160 | public static final String ID = "_id"; |
161 | + public static final String GUID = "guid"; |
162 | public static final String TITLE = "title"; |
163 | public static final String MODIFIED_DATE = "modified_date"; |
164 | public static final String URL = "url"; |
165 | public static final String FILE = "file"; |
166 | - public static final String NOTE_CONTENT = "note-content"; |
167 | - public static final int NOTE_RECEIVED_AND_VALID = 1; |
168 | - public static final int NO_NOTES = 2; |
169 | - public static final int NOTE_BADURL_OR_PARSING_ERROR = 3; |
170 | - public static final String[] PROJECTION = { Note.ID, Note.TITLE, Note.FILE, Note.MODIFIED_DATE }; |
171 | + public static final String NOTE_CONTENT = "content"; |
172 | |
173 | // Logging info |
174 | private static final String TAG = "Note"; |
175 | @@ -56,12 +55,14 @@ |
176 | public static final float NOTE_SIZE_HUGE_FACTOR = 1.6f; |
177 | |
178 | // Members |
179 | - private SpannableStringBuilder noteContent = new SpannableStringBuilder(); |
180 | + private SpannableStringBuilder noteContent; |
181 | + private String xmlContent; |
182 | private String url; |
183 | private String fileName; |
184 | private String title; |
185 | private DateTime lastChangeDate; |
186 | private int dbId; |
187 | + private UUID guid; |
188 | |
189 | public Note() {} |
190 | |
191 | @@ -105,19 +106,28 @@ |
192 | this.dbId = id; |
193 | } |
194 | |
195 | - public SpannableStringBuilder getNoteContent() { |
196 | + public UUID getGuid() { |
197 | + return guid; |
198 | + } |
199 | + |
200 | + public void setGuid(String guid) { |
201 | + this.guid = UUID.fromString(guid); |
202 | + } |
203 | + |
204 | + // TODO: should this handler passed around evolve into an observer pattern? |
205 | + public SpannableStringBuilder getNoteContent(Handler handler) { |
206 | + |
207 | + // TODO not sure this is the right place to do this |
208 | + noteContent = new NoteContentBuilder().setCaller(handler).setInputSource(xmlContent).build(); |
209 | return noteContent; |
210 | } |
211 | - |
212 | - public void setNoteContent(SpannableStringBuilder noteContent) { |
213 | - this.noteContent = noteContent; |
214 | + |
215 | + public String getXmlContent() { |
216 | + return xmlContent; |
217 | } |
218 | - |
219 | - public SpannableStringBuilder getDisplayableNoteContent() { |
220 | - SpannableStringBuilder sNoteContent = new SpannableStringBuilder(getNoteContent()); |
221 | - |
222 | - sNoteContent.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 17, 35, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
223 | - return sNoteContent; |
224 | + |
225 | + public void setXmlContent(String xmlContent) { |
226 | + this.xmlContent = xmlContent; |
227 | } |
228 | |
229 | @Override |
230 | |
231 | === removed file 'src/org/tomdroid/NoteCollection.java' |
232 | --- src/org/tomdroid/NoteCollection.java 2009-06-21 22:20:10 +0000 |
233 | +++ src/org/tomdroid/NoteCollection.java 1970-01-01 00:00:00 +0000 |
234 | @@ -1,140 +0,0 @@ |
235 | -/* |
236 | - * Tomdroid |
237 | - * Tomboy on Android |
238 | - * http://www.launchpad.net/tomdroid |
239 | - * |
240 | - * Copyright 2008, 2009 Olivier Bilodeau <olivier@bottomlesspit.org> |
241 | - * |
242 | - * This file is part of Tomdroid. |
243 | - * |
244 | - * Tomdroid is free software: you can redistribute it and/or modify |
245 | - * it under the terms of the GNU General Public License as published by |
246 | - * the Free Software Foundation, either version 3 of the License, or |
247 | - * (at your option) any later version. |
248 | - * |
249 | - * Tomdroid is distributed in the hope that it will be useful, |
250 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
251 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
252 | - * GNU General Public License for more details. |
253 | - * |
254 | - * You should have received a copy of the GNU General Public License |
255 | - * along with Tomdroid. If not, see <http://www.gnu.org/licenses/>. |
256 | - */ |
257 | -package org.tomdroid; |
258 | - |
259 | -import java.io.File; |
260 | -import java.io.FileNotFoundException; |
261 | -import java.util.ArrayList; |
262 | -import java.util.Iterator; |
263 | -import java.util.List; |
264 | -import java.util.regex.Pattern; |
265 | - |
266 | -import org.tomdroid.ui.Tomdroid; |
267 | -import org.tomdroid.util.AsyncNoteLoaderAndParser; |
268 | - |
269 | -import android.os.Handler; |
270 | -import android.util.Log; |
271 | - |
272 | -// TODO Transform the NoteCollection into a Provider (see .../android-sdk-linux_x86-1.0_r1/docs/devel/data/contentproviders.html#creatingacontentprovider) |
273 | -// this would be more android-like |
274 | -public class NoteCollection { |
275 | - |
276 | - // TODO This is not efficient, I maintain two list, one for the UI and the other for the actual data |
277 | - // the collection of notes |
278 | - private List<Note> notes = new ArrayList<Note>(); |
279 | - |
280 | - // Logging info |
281 | - private static final String TAG = "NoteCollection"; |
282 | - |
283 | - public List<Note> getNotes() { |
284 | - return notes; |
285 | - } |
286 | - |
287 | - public void setNotes(List<Note> notes) { |
288 | - this.notes = notes; |
289 | - } |
290 | - |
291 | - public void addNote(Note note) { |
292 | - notes.add(note); |
293 | - } |
294 | - |
295 | - public boolean isEmpty() { |
296 | - return notes.isEmpty(); |
297 | - } |
298 | - |
299 | - // TODO there is most likely a better way to do this |
300 | - // TODO how does Tomboy deals with notes with duplicate titles? I have to check that out |
301 | - public synchronized Note findNoteFromTitle(String title) { |
302 | - if (Tomdroid.LOGGING_ENABLED) Log.d(TAG,"searching for note with title: "+title); |
303 | - Iterator<Note> i = notes.iterator(); |
304 | - while(i.hasNext()) { |
305 | - Note curNote = i.next(); |
306 | - if (curNote.getTitle().equalsIgnoreCase(title)) { |
307 | - return curNote; |
308 | - } |
309 | - } |
310 | - return null; |
311 | - } |
312 | - |
313 | - // TODO there is most likely a better way to do this |
314 | - public Note findNoteFromFilename(String filename) { |
315 | - if (Tomdroid.LOGGING_ENABLED) Log.d(TAG,"searching for note with filename: "+filename); |
316 | - Iterator<Note> i = notes.iterator(); |
317 | - while(i.hasNext()) { |
318 | - Note curNote = i.next(); |
319 | - if (curNote.getFileName().equals(filename)) { |
320 | - return curNote; |
321 | - } |
322 | - } |
323 | - return null; |
324 | - } |
325 | - |
326 | - // TODO also throw a empty exception that we will catch in tomdroid and display the empty notelist msg |
327 | - public void loadNotes(Handler hndl) throws FileNotFoundException { |
328 | - File notesRoot = new File(Tomdroid.NOTES_PATH); |
329 | - |
330 | - if (!notesRoot.exists()) { |
331 | - throw new FileNotFoundException("Tomdroid notes folder doesn't exist. It is configured to be at: "+Tomdroid.NOTES_PATH); |
332 | - } |
333 | - |
334 | - AsyncNoteLoaderAndParser asyncLoader = new AsyncNoteLoaderAndParser(notesRoot, this, hndl); |
335 | - asyncLoader.readAndParseNotes(); |
336 | - } |
337 | - |
338 | - /** |
339 | - * Builds a regular expression pattern that will match any of the note title currently in the collection. |
340 | - * Useful for the Linkify to create the links to the notes. |
341 | - * @return regexp pattern |
342 | - */ |
343 | - public synchronized Pattern buildNoteLinkifyPattern() { |
344 | - |
345 | - StringBuilder sb = new StringBuilder(); |
346 | - |
347 | - for (Note n : notes) { |
348 | - // Pattern.quote() here make sure that special characters in the note's title are properly escaped |
349 | - sb.append("("+Pattern.quote(n.getTitle())+")|"); |
350 | - } |
351 | - |
352 | - // get rid of the last | that is not needed (I know, its ugly.. better idea?) |
353 | - String pt = sb.substring(0, sb.length()-1); |
354 | - |
355 | - // return a compiled match pattern |
356 | - return Pattern.compile(pt); |
357 | - } |
358 | - |
359 | - // singleton pattern |
360 | - // TODO verify this singleton, I have no net access and I'm not quite sure I nailed it |
361 | - private static NoteCollection nc; |
362 | - |
363 | - // FIXME the contract provided by this singleton is not correct. |
364 | - // If we instantiate this singleton, we expect it to be able to search through notes, which would not be the case |
365 | - // since the loadNotes is called by Tomdroid and not the constructor or something else. |
366 | - public static NoteCollection getInstance() { |
367 | - if (nc == null) { |
368 | - nc = new NoteCollection(); |
369 | - } |
370 | - return nc; |
371 | - } |
372 | - |
373 | - |
374 | -} |
375 | |
376 | === added file 'src/org/tomdroid/NoteManager.java' |
377 | --- src/org/tomdroid/NoteManager.java 1970-01-01 00:00:00 +0000 |
378 | +++ src/org/tomdroid/NoteManager.java 2010-01-17 18:10:19 +0000 |
379 | @@ -0,0 +1,154 @@ |
380 | +/* |
381 | + * Tomdroid |
382 | + * Tomboy on Android |
383 | + * http://www.launchpad.net/tomdroid |
384 | + * |
385 | + * Copyright 2009, 2010 Benoit Garret <benoit.garret_launchpad@gadz.org>, Olivier Bilodeau <olivier@bottomlesspit.org> |
386 | + * |
387 | + * This file is part of Tomdroid. |
388 | + * |
389 | + * Tomdroid is free software: you can redistribute it and/or modify |
390 | + * it under the terms of the GNU General Public License as published by |
391 | + * the Free Software Foundation, either version 3 of the License, or |
392 | + * (at your option) any later version. |
393 | + * |
394 | + * Tomdroid is distributed in the hope that it will be useful, |
395 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
396 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
397 | + * GNU General Public License for more details. |
398 | + * |
399 | + * You should have received a copy of the GNU General Public License |
400 | + * along with Tomdroid. If not, see <http://www.gnu.org/licenses/>. |
401 | + */ |
402 | +package org.tomdroid; |
403 | + |
404 | +import org.tomdroid.ui.Tomdroid; |
405 | + |
406 | +import android.app.Activity; |
407 | +import android.content.ContentResolver; |
408 | +import android.content.ContentValues; |
409 | +import android.database.Cursor; |
410 | +import android.net.Uri; |
411 | +import android.util.Log; |
412 | +import android.widget.ListAdapter; |
413 | +import android.widget.SimpleCursorAdapter; |
414 | + |
415 | +public class NoteManager { |
416 | + |
417 | + public static final String[] FULL_PROJECTION = { Note.ID, Note.TITLE, Note.FILE, Note.NOTE_CONTENT, Note.MODIFIED_DATE }; |
418 | + public static final String[] LIST_PROJECTION = { Note.ID, Note.TITLE }; |
419 | + public static final String[] TITLE_PROJECTION = { Note.TITLE }; |
420 | + public static final String[] ID_PROJECTION = { Note.ID }; |
421 | + public static final String[] EMPTY_PROJECTION = {}; |
422 | + |
423 | + // static properties |
424 | + private static final String TAG = "NoteManager"; |
425 | + |
426 | + // gets a note from the content provider |
427 | + public static Note getNote(Activity activity, Uri uri) { |
428 | + |
429 | + Note note = null; |
430 | + |
431 | + // can we find a matching note? |
432 | + Cursor cursor = activity.managedQuery(uri, FULL_PROJECTION, null, null, null); |
433 | + // cursor must not be null and must return more than 0 entry |
434 | + if (!(cursor == null || cursor.getCount() == 0)) { |
435 | + |
436 | + // create the note from the cursor |
437 | + cursor.moveToFirst(); |
438 | + String noteContent = cursor.getString(cursor.getColumnIndexOrThrow(Note.NOTE_CONTENT)); |
439 | + String noteTitle = cursor.getString(cursor.getColumnIndexOrThrow(Note.TITLE)); |
440 | + |
441 | + note = new Note(); |
442 | + note.setXmlContent(noteContent); |
443 | + note.setTitle(noteTitle); |
444 | + } |
445 | + |
446 | + return note; |
447 | + } |
448 | + |
449 | + // puts a note in the content provider |
450 | + public static void putNote(Activity activity, Note note) { |
451 | + |
452 | + // verify if the note is already in the content provider |
453 | + |
454 | + // TODO make the query prettier (use querybuilder) |
455 | + Uri notes = Tomdroid.CONTENT_URI; |
456 | + String[] whereArgs = new String[1]; |
457 | + whereArgs[0] = note.getGuid().toString(); |
458 | + |
459 | + // The note identifier is the guid |
460 | + ContentResolver cr = activity.getContentResolver(); |
461 | + Cursor managedCursor = cr.query(notes, |
462 | + EMPTY_PROJECTION, |
463 | + Note.GUID + "= ?", |
464 | + whereArgs, |
465 | + null); |
466 | + activity.startManagingCursor(managedCursor); |
467 | + |
468 | + // Preparing the values to be either inserted or updated |
469 | + // depending on the result of the previous query |
470 | + ContentValues values = new ContentValues(); |
471 | + values.put(Note.TITLE, note.getTitle()); |
472 | + values.put(Note.FILE, note.getFileName()); |
473 | + values.put(Note.GUID, note.getGuid().toString()); |
474 | + values.put(Note.NOTE_CONTENT, note.getXmlContent()); |
475 | + |
476 | + if (managedCursor.getCount() == 0) { |
477 | + |
478 | + // This note is not in the database yet we need to insert it |
479 | + if (Tomdroid.LOGGING_ENABLED) Log.v(TAG,"A new note has been detected (not yet in db)"); |
480 | + |
481 | + Uri uri = cr.insert(Tomdroid.CONTENT_URI, values); |
482 | + |
483 | + if (Tomdroid.LOGGING_ENABLED) Log.v(TAG,"Note inserted in content provider. ID: "+uri+" TITLE:"+note.getTitle()+" GUID:"+note.getGuid()); |
484 | + } else { |
485 | + |
486 | + // Overwrite the previous note if it exists |
487 | + cr.update(Tomdroid.CONTENT_URI, values, Note.GUID+" = ?", whereArgs); |
488 | + |
489 | + if (Tomdroid.LOGGING_ENABLED) Log.v(TAG,"Note updated in content provider. TITLE:"+note.getTitle()+" GUID:"+note.getGuid()); |
490 | + } |
491 | + } |
492 | + |
493 | + public static ListAdapter getListAdapter(Activity activity) { |
494 | + |
495 | + // get a cursor representing all notes from the NoteProvider |
496 | + Uri notes = Tomdroid.CONTENT_URI; |
497 | + Cursor notesCursor = activity.managedQuery(notes, LIST_PROJECTION, null, null, null); |
498 | + |
499 | + // set up an adapter binding the TITLE field of the cursor to the list item |
500 | + String[] from = new String[] { Note.TITLE }; |
501 | + int[] to = new int[] { R.id.note_title }; |
502 | + return new SimpleCursorAdapter(activity, R.layout.main_list_item, notesCursor, from, to); |
503 | + } |
504 | + |
505 | + // gets the titles of the notes present in the db, used in ViewNote.buildLinkifyPattern() |
506 | + public static Cursor getTitles(Activity activity) { |
507 | + |
508 | + // get a cursor containing the notes titles |
509 | + return activity.managedQuery(Tomdroid.CONTENT_URI, TITLE_PROJECTION, null, null, null); |
510 | + } |
511 | + |
512 | + public static int getNoteId(Activity activity, String title) { |
513 | + |
514 | + int id = 0; |
515 | + |
516 | + // get the notes ids |
517 | + String[] whereArgs = { title }; |
518 | + Cursor cursor = activity.managedQuery(Tomdroid.CONTENT_URI, ID_PROJECTION, Note.TITLE+"=?", whereArgs, null); |
519 | + |
520 | + // cursor must not be null and must return more than 0 entry |
521 | + if (!(cursor == null || cursor.getCount() == 0)) { |
522 | + |
523 | + cursor.moveToFirst(); |
524 | + id = cursor.getInt(cursor.getColumnIndexOrThrow(Note.ID)); |
525 | + } |
526 | + else { |
527 | + // TODO send an error to the user |
528 | + if (Tomdroid.LOGGING_ENABLED) Log.d(TAG, "Cursor returned null or 0 notes"); |
529 | + } |
530 | + |
531 | + return id; |
532 | + } |
533 | +} |
534 | |
535 | === modified file 'src/org/tomdroid/NoteProvider.java' |
536 | --- src/org/tomdroid/NoteProvider.java 2009-09-29 04:16:27 +0000 |
537 | +++ src/org/tomdroid/NoteProvider.java 2010-01-17 18:10:19 +0000 |
538 | @@ -43,6 +43,7 @@ |
539 | package org.tomdroid; |
540 | |
541 | import java.util.HashMap; |
542 | +import java.util.UUID; |
543 | |
544 | import org.tomdroid.ui.Tomdroid; |
545 | |
546 | @@ -67,7 +68,7 @@ |
547 | // -- |
548 | private static final String DATABASE_NAME = "tomdroid-notes.db"; |
549 | private static final String DB_TABLE_NOTES = "notes"; |
550 | - private static final int DB_VERSION = 1; |
551 | + private static final int DB_VERSION = 2; |
552 | // TODO once properly implemented, sort by: KEY_MODIFIED_DATE + " DESC" |
553 | private static final String DEFAULT_SORT_ORDER = Note.ID; |
554 | |
555 | @@ -95,8 +96,10 @@ |
556 | public void onCreate(SQLiteDatabase db) { |
557 | db.execSQL("CREATE TABLE " + DB_TABLE_NOTES + " (" |
558 | + Note.ID + " INTEGER PRIMARY KEY," |
559 | + + Note.GUID + " TEXT," |
560 | + Note.TITLE + " TEXT," |
561 | + Note.FILE + " TEXT," |
562 | + + Note.NOTE_CONTENT + " TEXT," |
563 | + Note.MODIFIED_DATE + " INTEGER" |
564 | + ");"); |
565 | } |
566 | @@ -204,6 +207,11 @@ |
567 | if (values.containsKey(Note.MODIFIED_DATE) == false) { |
568 | values.put(Note.MODIFIED_DATE, now); |
569 | } |
570 | + |
571 | + // The guid is the unique identifier for a note so it has to be set. |
572 | + if (values.containsKey(Note.GUID) == false) { |
573 | + values.put(Note.GUID, UUID.randomUUID().toString()); |
574 | + } |
575 | |
576 | // TODO does this make sense? |
577 | if (values.containsKey(Note.TITLE) == false) { |
578 | @@ -214,6 +222,10 @@ |
579 | if (values.containsKey(Note.FILE) == false) { |
580 | values.put(Note.FILE, ""); |
581 | } |
582 | + |
583 | + if (values.containsKey(Note.NOTE_CONTENT) == false) { |
584 | + values.put(Note.NOTE_CONTENT, ""); |
585 | + } |
586 | |
587 | SQLiteDatabase db = dbHelper.getWritableDatabase(); |
588 | long rowId = db.insert(DB_TABLE_NOTES, Note.FILE, values); // not so sure I did the right thing here |
589 | @@ -280,8 +292,10 @@ |
590 | |
591 | notesProjectionMap = new HashMap<String, String>(); |
592 | notesProjectionMap.put(Note.ID, Note.ID); |
593 | + notesProjectionMap.put(Note.GUID, Note.GUID); |
594 | notesProjectionMap.put(Note.TITLE, Note.TITLE); |
595 | notesProjectionMap.put(Note.FILE, Note.FILE); |
596 | + notesProjectionMap.put(Note.NOTE_CONTENT, Note.NOTE_CONTENT); |
597 | notesProjectionMap.put(Note.MODIFIED_DATE, Note.MODIFIED_DATE); |
598 | } |
599 | } |
600 | |
601 | === removed file 'src/org/tomdroid/ui/LoadWebNoteDialog.java' |
602 | --- src/org/tomdroid/ui/LoadWebNoteDialog.java 2009-04-06 22:27:27 +0000 |
603 | +++ src/org/tomdroid/ui/LoadWebNoteDialog.java 1970-01-01 00:00:00 +0000 |
604 | @@ -1,95 +0,0 @@ |
605 | -/* |
606 | - * Tomdroid |
607 | - * Tomboy on Android |
608 | - * http://www.launchpad.net/tomdroid |
609 | - * |
610 | - * Copyright 2008 Olivier Bilodeau <olivier@bottomlesspit.org> |
611 | - * |
612 | - * This file is part of Tomdroid. |
613 | - * |
614 | - * Tomdroid is free software: you can redistribute it and/or modify |
615 | - * it under the terms of the GNU General Public License as published by |
616 | - * the Free Software Foundation, either version 3 of the License, or |
617 | - * (at your option) any later version. |
618 | - * |
619 | - * Tomdroid is distributed in the hope that it will be useful, |
620 | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
621 | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
622 | - * GNU General Public License for more details. |
623 | - * |
624 | - * You should have received a copy of the GNU General Public License |
625 | - * along with Tomdroid. If not, see <http://www.gnu.org/licenses/>. |
626 | - */ |
627 | -package org.tomdroid.ui; |
628 | - |
629 | -import org.tomdroid.R; |
630 | - |
631 | -import android.app.Activity; |
632 | -import android.content.Intent; |
633 | -import android.os.Bundle; |
634 | -import android.view.View; |
635 | -import android.view.View.OnClickListener; |
636 | -import android.widget.Button; |
637 | -import android.widget.EditText; |
638 | - |
639 | -/** |
640 | - * This class is in charge of returning only the string of the URL to fetch from. |
641 | - */ |
642 | -// TODO change superclass to a dialog (see .../docs/kb/commontasks.html#implementcallbacks) |
643 | -public class LoadWebNoteDialog extends Activity { |
644 | - |
645 | - // UI elements |
646 | - private EditText txtURL; |
647 | - |
648 | - @Override |
649 | - protected void onCreate(Bundle savedInstanceState) { |
650 | - super.onCreate(savedInstanceState); |
651 | - |
652 | - setContentView(R.layout.load_web_note_dialog); |
653 | - setTitle(R.string.strLoadFromWebTitle); |
654 | - |
655 | - // Connect UI elements to variables |
656 | - txtURL = (EditText) findViewById(R.id.txtURL); |
657 | - // txtURL.setText("http://www.bottomlesspit.org/files/note.xml"); |
658 | - Button btnOk = (Button)findViewById(R.id.btnOk); |
659 | - Button btnCancel = (Button)findViewById(R.id.btnCancel); |
660 | - |
661 | - // Annon inner-class for button listener |
662 | - btnOk.setOnClickListener(new OnClickListener() { |
663 | - |
664 | - public void onClick(View v) |
665 | - { |
666 | - okClicked(txtURL.getText().toString()); |
667 | - } |
668 | - }); |
669 | - |
670 | - // Annon inner-class for button listener |
671 | - btnCancel.setOnClickListener(new OnClickListener() { |
672 | - |
673 | - public void onClick(View v) |
674 | - { |
675 | - cancelClicked(); |
676 | - } |
677 | - }); |
678 | - |
679 | - |
680 | - } |
681 | - |
682 | - private void okClicked(String url) { |
683 | - |
684 | - Bundle bundle = new Bundle(); |
685 | - bundle.putString(Tomdroid.RESULT_URL_TO_LOAD, url); |
686 | - |
687 | - Intent i = new Intent(); |
688 | - i.putExtras(bundle); |
689 | - setResult(RESULT_OK, i); |
690 | - finish(); |
691 | - } |
692 | - |
693 | - private void cancelClicked() { |
694 | - |
695 | - setResult(RESULT_CANCELED); |
696 | - finish(); |
697 | - } |
698 | - |
699 | -} |
700 | |
701 | === modified file 'src/org/tomdroid/ui/Tomdroid.java' |
702 | --- src/org/tomdroid/ui/Tomdroid.java 2009-10-03 16:26:37 +0000 |
703 | +++ src/org/tomdroid/ui/Tomdroid.java 2010-01-17 18:10:19 +0000 |
704 | @@ -3,7 +3,7 @@ |
705 | * Tomboy on Android |
706 | * http://www.launchpad.net/tomdroid |
707 | * |
708 | - * Copyright 2008, 2009 Olivier Bilodeau <olivier@bottomlesspit.org> |
709 | + * Copyright 2008, 2009, 2010 Olivier Bilodeau <olivier@bottomlesspit.org> |
710 | * |
711 | * This file is part of Tomdroid. |
712 | * |
713 | @@ -22,15 +22,16 @@ |
714 | */ |
715 | package org.tomdroid.ui; |
716 | |
717 | +import java.io.File; |
718 | import java.io.FileNotFoundException; |
719 | |
720 | import org.tomdroid.Note; |
721 | -import org.tomdroid.NoteCollection; |
722 | +import org.tomdroid.NoteManager; |
723 | import org.tomdroid.R; |
724 | +import org.tomdroid.util.AsyncNoteLoaderAndParser; |
725 | |
726 | import android.app.AlertDialog; |
727 | import android.app.ListActivity; |
728 | -import android.content.ContentValues; |
729 | import android.content.DialogInterface; |
730 | import android.content.Intent; |
731 | import android.content.DialogInterface.OnClickListener; |
732 | @@ -38,14 +39,12 @@ |
733 | import android.database.Cursor; |
734 | import android.net.Uri; |
735 | import android.os.Bundle; |
736 | -import android.os.Handler; |
737 | -import android.os.Message; |
738 | import android.util.Log; |
739 | import android.view.Menu; |
740 | import android.view.MenuInflater; |
741 | import android.view.MenuItem; |
742 | import android.view.View; |
743 | -import android.widget.ArrayAdapter; |
744 | +import android.widget.ListAdapter; |
745 | import android.widget.ListView; |
746 | import android.widget.TextView; |
747 | |
748 | @@ -62,24 +61,14 @@ |
749 | // TODO hardcoded for now |
750 | public static final String NOTES_PATH = "/sdcard/tomdroid/"; |
751 | // Logging should be disabled for release builds |
752 | - public static final boolean LOGGING_ENABLED = false; |
753 | + public static final boolean LOGGING_ENABLED = true; |
754 | |
755 | // Logging info |
756 | private static final String TAG = "Tomdroid"; |
757 | |
758 | - // data keys |
759 | - public static final String RESULT_URL_TO_LOAD = "urlToLoad"; |
760 | - |
761 | - // Activity result resources |
762 | - private static final int ACTIVITY_GET_URL=0; |
763 | - private static final int ACTIVITY_VIEW=1; |
764 | - |
765 | - // domain elements |
766 | - private NoteCollection localNotes; |
767 | - |
768 | // UI to data model glue |
769 | - private ArrayAdapter<String> notesListAdapter; |
770 | private TextView listEmptyView; |
771 | + private ListAdapter adapter; |
772 | |
773 | // Bundle keys for saving state |
774 | private static final String WARNING_SHOWN = "w"; |
775 | @@ -111,15 +100,12 @@ |
776 | .show(); |
777 | } |
778 | |
779 | - // listAdapter that binds the UI to the notes names |
780 | - notesListAdapter = new ArrayAdapter<String>(this, R.layout.main_list_item); |
781 | - setListAdapter(notesListAdapter); |
782 | + adapter = NoteManager.getListAdapter(this); |
783 | + setListAdapter(adapter); |
784 | |
785 | // set the view shown when the list is empty |
786 | listEmptyView = (TextView)findViewById(R.id.list_empty); |
787 | getListView().setEmptyView(listEmptyView); |
788 | - |
789 | - localNotes = NoteCollection.getInstance(); |
790 | } |
791 | |
792 | @Override |
793 | @@ -134,17 +120,21 @@ |
794 | @Override |
795 | public boolean onOptionsItemSelected(MenuItem item) { |
796 | switch (item.getItemId()) { |
797 | - case R.id.menuLoadWebNote: |
798 | - showLoadWebNoteDialog(); |
799 | - return true; |
800 | - |
801 | case R.id.menuSyncWithSD: |
802 | - |
803 | - // start loading local notes |
804 | - if (LOGGING_ENABLED) Log.v(TAG, "Loading local notes"); |
805 | - |
806 | - try { |
807 | - localNotes.loadNotes(handler); |
808 | + |
809 | + // start loading local notes |
810 | + if (LOGGING_ENABLED) Log.v(TAG, "Loading local notes"); |
811 | + |
812 | + try { |
813 | + File notesRoot = new File(Tomdroid.NOTES_PATH); |
814 | + |
815 | + if (!notesRoot.exists()) { |
816 | + throw new FileNotFoundException("Tomdroid notes folder doesn't exist. It is configured to be at: "+Tomdroid.NOTES_PATH); |
817 | + } |
818 | + |
819 | + AsyncNoteLoaderAndParser asyncLoader = new AsyncNoteLoaderAndParser(this, notesRoot); |
820 | + asyncLoader.readAndParseNotes(); |
821 | + |
822 | } catch (FileNotFoundException e) { |
823 | //TODO put strings in an external resource |
824 | listEmptyView.setText(R.string.strListEmptyNoNotes); |
825 | @@ -158,8 +148,8 @@ |
826 | .show(); |
827 | e.printStackTrace(); |
828 | } |
829 | - |
830 | - return true; |
831 | + |
832 | + return true; |
833 | |
834 | case R.id.menuAbout: |
835 | showAboutDialog(); |
836 | @@ -216,109 +206,14 @@ |
837 | } |
838 | |
839 | @Override |
840 | - protected void onActivityResult(int requestCode, int resultCode, Intent data) { |
841 | - super.onActivityResult(requestCode, resultCode, data); |
842 | - |
843 | - switch(requestCode) { |
844 | - case ACTIVITY_GET_URL: |
845 | - if (resultCode == RESULT_OK) { |
846 | - String url = data.getExtras().getString(RESULT_URL_TO_LOAD); |
847 | - loadNoteFromURL(url); |
848 | - } |
849 | - } |
850 | - } |
851 | - |
852 | - private Handler handler = new Handler() { |
853 | - |
854 | - @Override |
855 | - public void handleMessage(Message msg) { |
856 | - |
857 | - // thread is done fetching a note and parsing went well |
858 | - if (msg.what == Note.NOTE_RECEIVED_AND_VALID) { |
859 | - |
860 | - // update the note list with this newly parsed note |
861 | - updateNoteListWith(msg.getData().getString(Note.TITLE)); |
862 | - |
863 | - } else if (msg.what == Note.NO_NOTES) { |
864 | - |
865 | - // if there are no notes, say so in the list_empty message |
866 | - listEmptyView.setText(R.string.strListEmptyNoNotes); |
867 | - } |
868 | - } |
869 | - }; |
870 | - |
871 | - @Override |
872 | protected void onListItemClick(ListView l, View v, int position, long id) { |
873 | - |
874 | - // get the clicked note |
875 | - Note n = localNotes.findNoteFromTitle(notesListAdapter.getItem(position)); |
876 | - |
877 | - Intent i = new Intent(Tomdroid.this, ViewNote.class); |
878 | - i.putExtra(Note.FILE, n.getFileName()); |
879 | - startActivityForResult(i, ACTIVITY_VIEW); |
880 | - |
881 | - } |
882 | - |
883 | - private void showLoadWebNoteDialog() { |
884 | - |
885 | - Intent i = new Intent(Tomdroid.this, LoadWebNoteDialog.class); |
886 | - startActivityForResult(i, ACTIVITY_GET_URL); |
887 | - } |
888 | - |
889 | - private void loadNoteFromURL(String url) { |
890 | - |
891 | - Intent i = new Intent(Tomdroid.this, ViewNote.class); |
892 | - i.putExtra(Note.URL, url); |
893 | - startActivity(i); |
894 | - } |
895 | - |
896 | - private void updateNoteListWith(String noteTitle) { |
897 | - |
898 | - // add note to the note list |
899 | - notesListAdapter.add(noteTitle); |
900 | - |
901 | - // get the note instance we will work with that instead from now on |
902 | - Note note = localNotes.findNoteFromTitle(noteTitle); |
903 | - |
904 | - // verify if the note is already in the content provider |
905 | - String[] projection = new String[] { |
906 | - Note.ID, |
907 | - Note.TITLE, |
908 | - }; |
909 | - |
910 | - // TODO I could see a problem where someone delete a note and recreate one with the same title. |
911 | - // It would been seen as not new although it is (it will have a new filename) |
912 | - // TODO make the query prettier (use querybuilder) |
913 | - Uri notes = Tomdroid.CONTENT_URI; |
914 | - String[] whereArgs = new String[1]; |
915 | - whereArgs[0] = noteTitle; |
916 | - Cursor managedCursor = managedQuery( notes, |
917 | - projection, |
918 | - Note.TITLE + "= ?", |
919 | - whereArgs, |
920 | - Note.TITLE + " ASC"); |
921 | - if (managedCursor.getCount() == 0) { |
922 | - |
923 | - // This note is not in the database yet we need to insert it |
924 | - if (LOGGING_ENABLED) Log.v(TAG,"A new note has been detected (not yet in db)"); |
925 | - |
926 | - // This add the note to the content Provider |
927 | - // TODO PoC code that should be removed in next iteration's refactoring (no notecollection, everything should come from the provider I guess?) |
928 | - ContentValues values = new ContentValues(); |
929 | - values.put(Note.TITLE, note.getTitle()); |
930 | - values.put(Note.FILE, note.getFileName()); |
931 | - Uri uri = getContentResolver().insert(CONTENT_URI, values); |
932 | - // now that we inserted the note put its ID in the note itself |
933 | - note.setDbId(Integer.parseInt(uri.getLastPathSegment())); |
934 | - |
935 | - if (LOGGING_ENABLED) Log.v(TAG,"Note inserted in content provider. ID: "+uri+" TITLE:"+noteTitle+" ID:"+note.getDbId()); |
936 | - } else { |
937 | - |
938 | - // find out the note's id and put it in the note |
939 | - if (managedCursor.moveToFirst()) { |
940 | - int idColumn = managedCursor.getColumnIndex(Note.ID); |
941 | - note.setDbId(managedCursor.getInt(idColumn)); |
942 | - } |
943 | - } |
944 | + |
945 | + Cursor item = (Cursor)adapter.getItem(position); |
946 | + int noteId = item.getInt( |
947 | + item.getColumnIndexOrThrow(Note.ID)); |
948 | + |
949 | + Uri intentUri = Uri.parse(Tomdroid.CONTENT_URI+"/"+noteId); |
950 | + Intent i = new Intent(Intent.ACTION_VIEW, intentUri, this, ViewNote.class); |
951 | + startActivity(i); |
952 | } |
953 | } |
954 | |
955 | === modified file 'src/org/tomdroid/ui/ViewNote.java' |
956 | --- src/org/tomdroid/ui/ViewNote.java 2009-06-21 20:25:16 +0000 |
957 | +++ src/org/tomdroid/ui/ViewNote.java 2010-01-17 18:10:19 +0000 |
958 | @@ -3,7 +3,7 @@ |
959 | * Tomboy on Android |
960 | * http://www.launchpad.net/tomdroid |
961 | * |
962 | - * Copyright 2008, 2009 Olivier Bilodeau <olivier@bottomlesspit.org> |
963 | + * Copyright 2008, 2009, 2010 Olivier Bilodeau <olivier@bottomlesspit.org> |
964 | * |
965 | * This file is part of Tomdroid. |
966 | * |
967 | @@ -22,14 +22,13 @@ |
968 | */ |
969 | package org.tomdroid.ui; |
970 | |
971 | -import java.net.MalformedURLException; |
972 | -import java.net.URL; |
973 | import java.util.regex.Matcher; |
974 | +import java.util.regex.Pattern; |
975 | |
976 | import org.tomdroid.Note; |
977 | -import org.tomdroid.NoteCollection; |
978 | +import org.tomdroid.NoteManager; |
979 | import org.tomdroid.R; |
980 | -import org.tomdroid.util.NoteBuilder; |
981 | +import org.tomdroid.util.NoteContentBuilder; |
982 | |
983 | import android.app.Activity; |
984 | import android.app.AlertDialog; |
985 | @@ -41,6 +40,7 @@ |
986 | import android.os.Bundle; |
987 | import android.os.Handler; |
988 | import android.os.Message; |
989 | +import android.text.SpannableStringBuilder; |
990 | import android.text.util.Linkify; |
991 | import android.text.util.Linkify.TransformFilter; |
992 | import android.util.Log; |
993 | @@ -50,14 +50,12 @@ |
994 | // TODO this class is starting to smell |
995 | public class ViewNote extends Activity { |
996 | |
997 | - private String url; |
998 | - private String file; |
999 | - |
1000 | // UI elements |
1001 | private TextView content; |
1002 | |
1003 | // Model objects |
1004 | private Note note; |
1005 | + private SpannableStringBuilder noteContent; |
1006 | |
1007 | // Logging info |
1008 | private static final String TAG = "ViewNote"; |
1009 | @@ -68,60 +66,11 @@ |
1010 | super.onCreate(savedInstanceState); |
1011 | |
1012 | setContentView(R.layout.note_view); |
1013 | - |
1014 | content = (TextView) findViewById(R.id.content); |
1015 | - |
1016 | final Intent intent = getIntent(); |
1017 | - |
1018 | Uri uri = intent.getData(); |
1019 | - if (uri == null) { |
1020 | - |
1021 | - // we were not fired by an Intent-filter so two choice here: |
1022 | - // get external web url or filename |
1023 | - Bundle extras = intent.getExtras(); |
1024 | - if (extras != null) { |
1025 | - |
1026 | - // lets grab both variables and test against null later |
1027 | - url = extras.getString(Note.URL); |
1028 | - file = extras.getString(Note.FILE); |
1029 | - |
1030 | - // Based on what was sent in the bundle, we either load from file or url |
1031 | - if (url != null) { |
1032 | - |
1033 | - if (Tomdroid.LOGGING_ENABLED) Log.v(TAG,"ViewNote started: Loading a note from Web URL."); |
1034 | - |
1035 | - try { |
1036 | - |
1037 | - note = new NoteBuilder().setCaller(handler).setInputSource(new URL(url)).build(); |
1038 | - } catch (MalformedURLException e) { |
1039 | - // TODO catch correctly |
1040 | - e.printStackTrace(); |
1041 | - |
1042 | - // TODO put error string in a translatable resource |
1043 | - new AlertDialog.Builder(this) |
1044 | - .setMessage("Invalid URL") |
1045 | - .setTitle("Error") |
1046 | - .setNeutralButton("Ok", new OnClickListener() { |
1047 | - public void onClick(DialogInterface dialog, int which) { |
1048 | - dialog.dismiss(); |
1049 | - finish(); |
1050 | - }}) |
1051 | - .show(); |
1052 | - } |
1053 | - |
1054 | - } else if (file != null) { |
1055 | - |
1056 | - if (Tomdroid.LOGGING_ENABLED) Log.v(TAG,"ViewNote started: Loading a note based on a filename."); |
1057 | - note = NoteCollection.getInstance().findNoteFromFilename(file); |
1058 | - showNote(); |
1059 | - } else { |
1060 | - |
1061 | - if (Tomdroid.LOGGING_ENABLED) Log.d(TAG,"ViewNote started: Bundle's content was not helpful to find which note to load.."); |
1062 | - } |
1063 | - } else { |
1064 | - if (Tomdroid.LOGGING_ENABLED) Log.d(TAG,"ViewNote started: No extra information in the bundle, we don't know what to load"); |
1065 | - } |
1066 | - } else { |
1067 | + |
1068 | + if (uri != null) { |
1069 | |
1070 | // We were triggered by an Intent URI |
1071 | if (Tomdroid.LOGGING_ENABLED) Log.d(TAG, "ViewNote started: Intent-filter triggered."); |
1072 | @@ -129,21 +78,45 @@ |
1073 | // TODO validate the good action? |
1074 | // intent.getAction() |
1075 | |
1076 | - // can we find a matching note? |
1077 | - Cursor cursor = managedQuery(uri, Note.PROJECTION, null, null, null); |
1078 | - // cursor must not be null and must return more than 0 entry |
1079 | - if (!(cursor == null || cursor.getCount() == 0)) { |
1080 | + // TODO verify that getNote is doing the proper validation |
1081 | + note = NoteManager.getNote(this, uri); |
1082 | + |
1083 | + if(note != null) { |
1084 | |
1085 | - cursor.moveToFirst(); |
1086 | - String noteFilename = cursor.getString(cursor.getColumnIndexOrThrow(Note.FILE)); |
1087 | - note = NoteCollection.getInstance().findNoteFromFilename(noteFilename); |
1088 | - showNote(); |
1089 | + noteContent = note.getNoteContent(handler); |
1090 | |
1091 | } else { |
1092 | |
1093 | // TODO send an error to the user |
1094 | - if (Tomdroid.LOGGING_ENABLED) Log.d(TAG, "Cursor returned null or 0 notes"); |
1095 | + if (Tomdroid.LOGGING_ENABLED) Log.d(TAG, "The note "+uri+" doesn't exist"); |
1096 | + |
1097 | + // TODO put error string in a translatable resource |
1098 | + new AlertDialog.Builder(this) |
1099 | + .setMessage("The requested note could not be found. If you see this error by " + |
1100 | + "mistake and you are able to replicate it, please file a bug!") |
1101 | + .setTitle("Error") |
1102 | + .setNeutralButton("Ok", new OnClickListener() { |
1103 | + public void onClick(DialogInterface dialog, int which) { |
1104 | + dialog.dismiss(); |
1105 | + finish(); |
1106 | + }}) |
1107 | + .show(); |
1108 | } |
1109 | + } else { |
1110 | + |
1111 | + if (Tomdroid.LOGGING_ENABLED) Log.d(TAG, "The Intent's data was null."); |
1112 | + |
1113 | + // TODO put error string in a translatable resource |
1114 | + new AlertDialog.Builder(this) |
1115 | + .setMessage("The requested note could not be found. If you see this error by " + |
1116 | + "mistake and you are able to replicate it, please file a bug!") |
1117 | + .setTitle("Error") |
1118 | + .setNeutralButton("Ok", new OnClickListener() { |
1119 | + public void onClick(DialogInterface dialog, int which) { |
1120 | + dialog.dismiss(); |
1121 | + finish(); |
1122 | + }}) |
1123 | + .show(); |
1124 | } |
1125 | } |
1126 | |
1127 | @@ -160,55 +133,41 @@ |
1128 | return true; |
1129 | } |
1130 | |
1131 | - private void showNote() { |
1132 | + private void showNote() { |
1133 | // show the note (spannable makes the TextView able to output styled text) |
1134 | - content.setText(note.getNoteContent(), TextView.BufferType.SPANNABLE); |
1135 | + content.setText(noteContent, TextView.BufferType.SPANNABLE); |
1136 | + setTitle(note.getTitle()); |
1137 | |
1138 | // add links to stuff that is understood by Android |
1139 | // TODO this is SLOWWWW!!!! |
1140 | Linkify.addLinks(content, Linkify.ALL); |
1141 | |
1142 | // This will create a link every time a note title is found in the text. |
1143 | - // The pattern is built by NoteCollection and contains a very dumb (title1)|(title2) escaped correctly |
1144 | - // Then we tranform the url from the note name to the note id to avoid characters that mess up with the URI (ex: ?) |
1145 | + // The pattern contains a very dumb (title1)|(title2) escaped correctly |
1146 | + // Then we transform the url from the note name to the note id to avoid characters that mess up with the URI (ex: ?) |
1147 | Linkify.addLinks(content, |
1148 | - NoteCollection.getInstance().buildNoteLinkifyPattern(), |
1149 | + buildNoteLinkifyPattern(), |
1150 | Tomdroid.CONTENT_URI+"/", |
1151 | null, |
1152 | - |
1153 | - // custom transform filter that takes the note's title part of the URI and translate it into the note id |
1154 | - // this was done to avoid problems with invalid characters in URI (ex: ? is the query separator but could be in a note title) |
1155 | - new TransformFilter() { |
1156 | - |
1157 | - public String transformUrl(Matcher m, String str) { |
1158 | - |
1159 | - // FIXME if this activity is called from another app and Tomdroid was never launched, getting here will probably make it crash |
1160 | - int id = 0; |
1161 | - try { |
1162 | - id = NoteCollection.getInstance().findNoteFromTitle(str).getDbId(); |
1163 | - } catch (Exception e) { |
1164 | - if (Tomdroid.LOGGING_ENABLED) Log.d(TAG, "NoteCollection accessed but it was not ready for it.."); |
1165 | - } |
1166 | - |
1167 | - // return something like content://org.tomdroid.notes/notes/3 |
1168 | - return Tomdroid.CONTENT_URI.toString()+"/"+id; |
1169 | - } |
1170 | - }); |
1171 | + noteTitleTransformFilter); |
1172 | } |
1173 | - |
1174 | - private Handler handler = new Handler() { |
1175 | - |
1176 | - @Override |
1177 | - public void handleMessage(Message msg) { |
1178 | - |
1179 | - // thread is done fetching note and parsing went well |
1180 | - if (msg.what == Note.NOTE_RECEIVED_AND_VALID) { |
1181 | - showNote(); |
1182 | - } else if (msg.what == Note.NOTE_BADURL_OR_PARSING_ERROR) { |
1183 | - |
1184 | - // TODO put this String in a translatable resource |
1185 | + |
1186 | + public Handler handler = new Handler() { |
1187 | + |
1188 | + @Override |
1189 | + public void handleMessage(Message msg) { |
1190 | + |
1191 | + //parsed ok - show |
1192 | + if(msg.what == NoteContentBuilder.PARSE_OK) { |
1193 | + showNote(); |
1194 | + |
1195 | + //parsed not ok - error |
1196 | + } else if(msg.what == NoteContentBuilder.PARSE_ERROR) { |
1197 | + |
1198 | + // TODO put this String in a translatable resource |
1199 | new AlertDialog.Builder(ViewNote.this) |
1200 | - .setMessage("Error loading note from the Web due to a network error or a parsing error.") |
1201 | + .setMessage("The requested note could not be parsed. If you see this error by " + |
1202 | + "mistake and you are able to replicate it, please file a bug!") |
1203 | .setTitle("Error") |
1204 | .setNeutralButton("Ok", new OnClickListener() { |
1205 | public void onClick(DialogInterface dialog, int which) { |
1206 | @@ -218,5 +177,58 @@ |
1207 | .show(); |
1208 | } |
1209 | } |
1210 | - }; |
1211 | + }; |
1212 | + |
1213 | + /** |
1214 | + * Builds a regular expression pattern that will match any of the note title currently in the collection. |
1215 | + * Useful for the Linkify to create the links to the notes. |
1216 | + * @return regexp pattern |
1217 | + */ |
1218 | + public Pattern buildNoteLinkifyPattern() { |
1219 | + |
1220 | + StringBuilder sb = new StringBuilder(); |
1221 | + Cursor cursor = NoteManager.getTitles(this); |
1222 | + |
1223 | + // cursor must not be null and must return more than 0 entry |
1224 | + if (!(cursor == null || cursor.getCount() == 0)) { |
1225 | + |
1226 | + String title; |
1227 | + |
1228 | + cursor.moveToFirst(); |
1229 | + |
1230 | + do { |
1231 | + title = cursor.getString(cursor.getColumnIndexOrThrow(Note.TITLE)); |
1232 | + |
1233 | + // Pattern.quote() here make sure that special characters in the note's title are properly escaped |
1234 | + sb.append("("+Pattern.quote(title)+")|"); |
1235 | + |
1236 | + } while (cursor.moveToNext()); |
1237 | + |
1238 | + // get rid of the last | that is not needed (I know, its ugly.. better idea?) |
1239 | + String pt = sb.substring(0, sb.length()-1); |
1240 | + |
1241 | + // return a compiled match pattern |
1242 | + return Pattern.compile(pt); |
1243 | + |
1244 | + } else { |
1245 | + |
1246 | + // TODO send an error to the user |
1247 | + if (Tomdroid.LOGGING_ENABLED) Log.d(TAG, "Cursor returned null or 0 notes"); |
1248 | + } |
1249 | + |
1250 | + return null; |
1251 | + } |
1252 | + |
1253 | + // custom transform filter that takes the note's title part of the URI and translate it into the note id |
1254 | + // this was done to avoid problems with invalid characters in URI (ex: ? is the query separator but could be in a note title) |
1255 | + TransformFilter noteTitleTransformFilter = new TransformFilter() { |
1256 | + |
1257 | + public String transformUrl(Matcher m, String str) { |
1258 | + |
1259 | + int id = NoteManager.getNoteId(ViewNote.this, str); |
1260 | + |
1261 | + // return something like content://org.tomdroid.notes/notes/3 |
1262 | + return Tomdroid.CONTENT_URI.toString()+"/"+id; |
1263 | + } |
1264 | + }; |
1265 | } |
1266 | |
1267 | === modified file 'src/org/tomdroid/util/AsyncNoteLoaderAndParser.java' |
1268 | --- src/org/tomdroid/util/AsyncNoteLoaderAndParser.java 2009-06-21 21:28:14 +0000 |
1269 | +++ src/org/tomdroid/util/AsyncNoteLoaderAndParser.java 2010-01-17 18:10:19 +0000 |
1270 | @@ -3,7 +3,7 @@ |
1271 | * Tomboy on Android |
1272 | * http://www.launchpad.net/tomdroid |
1273 | * |
1274 | - * Copyright 2009 Olivier Bilodeau <olivier@bottomlesspit.org> |
1275 | + * Copyright 2009, 2010 Olivier Bilodeau <olivier@bottomlesspit.org> |
1276 | * |
1277 | * This file is part of Tomdroid. |
1278 | * |
1279 | @@ -28,51 +28,49 @@ |
1280 | import java.io.FilenameFilter; |
1281 | import java.io.IOException; |
1282 | import java.io.InputStreamReader; |
1283 | +import java.io.Reader; |
1284 | import java.util.concurrent.ExecutorService; |
1285 | import java.util.concurrent.Executors; |
1286 | +import java.util.regex.Matcher; |
1287 | +import java.util.regex.Pattern; |
1288 | |
1289 | import javax.xml.parsers.ParserConfigurationException; |
1290 | import javax.xml.parsers.SAXParser; |
1291 | import javax.xml.parsers.SAXParserFactory; |
1292 | |
1293 | import org.tomdroid.Note; |
1294 | -import org.tomdroid.NoteCollection; |
1295 | +import org.tomdroid.NoteManager; |
1296 | import org.tomdroid.ui.Tomdroid; |
1297 | import org.tomdroid.xml.NoteHandler; |
1298 | import org.xml.sax.InputSource; |
1299 | import org.xml.sax.SAXException; |
1300 | import org.xml.sax.XMLReader; |
1301 | |
1302 | -import android.os.Bundle; |
1303 | -import android.os.Handler; |
1304 | -import android.os.Message; |
1305 | +import android.app.Activity; |
1306 | import android.util.Log; |
1307 | |
1308 | public class AsyncNoteLoaderAndParser { |
1309 | private final ExecutorService pool; |
1310 | private final static int poolSize = 1; |
1311 | + private Activity activity; |
1312 | private File path; |
1313 | - private NoteCollection noteCollection; |
1314 | - private Handler parentHandler; |
1315 | + |
1316 | + // regexp for <note-content..>...</note-content> |
1317 | + private static Pattern note_content = Pattern.compile(".*(<note-content.*>.*<\\/note-content>).*", Pattern.CASE_INSENSITIVE+Pattern.DOTALL); |
1318 | |
1319 | // logging related |
1320 | private final static String TAG = "AsyncNoteLoaderAndParser"; |
1321 | |
1322 | - public AsyncNoteLoaderAndParser(File path, NoteCollection nc, Handler hndl) { |
1323 | + public AsyncNoteLoaderAndParser(Activity a, File path) { |
1324 | + this.activity = a; |
1325 | this.path = path; |
1326 | + |
1327 | pool = Executors.newFixedThreadPool(poolSize); |
1328 | - noteCollection = nc; |
1329 | - parentHandler = hndl; |
1330 | } |
1331 | |
1332 | public void readAndParseNotes() { |
1333 | File[] fileList = path.listFiles(new NotesFilter()); |
1334 | |
1335 | - // If there are no notes, warn the UI through an empty message |
1336 | - if (fileList.length == 0) { |
1337 | - parentHandler.sendEmptyMessage(Note.NO_NOTES); |
1338 | - } |
1339 | - |
1340 | for (File file : fileList) { |
1341 | |
1342 | // give a filename to a thread and ask to parse it when nothing's left to do its over |
1343 | @@ -91,13 +89,14 @@ |
1344 | } |
1345 | |
1346 | /** |
1347 | - * The worker spawns a new note, parse the file its being given by the executor and add it to the NoteCollection |
1348 | + * The worker spawns a new note, parse the file its being given by the executor. |
1349 | */ |
1350 | class Worker implements Runnable { |
1351 | |
1352 | // the note to be loaded and parsed |
1353 | private Note note = new Note(); |
1354 | private File file; |
1355 | + final char[] buffer = new char[0x10000]; |
1356 | |
1357 | public Worker(File f) { |
1358 | file = f; |
1359 | @@ -106,7 +105,9 @@ |
1360 | public void run() { |
1361 | |
1362 | note.setFileName(file.getAbsolutePath()); |
1363 | - |
1364 | + // the note guid is not stored in the xml but in the filename |
1365 | + note.setGuid(file.getName().replace(".note", "")); |
1366 | + |
1367 | try { |
1368 | // Parsing |
1369 | // XML |
1370 | @@ -121,13 +122,12 @@ |
1371 | NoteHandler xmlHandler = new NoteHandler(note); |
1372 | xr.setContentHandler(xmlHandler); |
1373 | |
1374 | - |
1375 | - // Create the proper input source based on if its a local note or a web note |
1376 | - FileInputStream fin = new FileInputStream(file); |
1377 | - BufferedReader in = new BufferedReader(new InputStreamReader(fin), 8192); |
1378 | - InputSource is = new InputSource(in); |
1379 | - |
1380 | - if (Tomdroid.LOGGING_ENABLED) Log.v(TAG, "parsing note"); |
1381 | + // Create the proper input source |
1382 | + FileInputStream fin = new FileInputStream(file); |
1383 | + BufferedReader in = new BufferedReader(new InputStreamReader(fin), 8192); |
1384 | + InputSource is = new InputSource(in); |
1385 | + |
1386 | + if (Tomdroid.LOGGING_ENABLED) Log.d(TAG, "parsing note"); |
1387 | xr.parse(is); |
1388 | |
1389 | // TODO wrap and throw a new exception here |
1390 | @@ -138,26 +138,38 @@ |
1391 | } catch (IOException e) { |
1392 | e.printStackTrace(); |
1393 | } |
1394 | + |
1395 | + // extract the <note-content..>...</note-content> |
1396 | + if (Tomdroid.LOGGING_ENABLED) Log.d(TAG, "retrieving what is inside of note-content"); |
1397 | |
1398 | - synchronized (noteCollection) { |
1399 | - noteCollection.addNote(note); |
1400 | + // FIXME here we are re-reading the whole note just to grab note-content out, there is probably a best way to do this |
1401 | + StringBuilder out = new StringBuilder(); |
1402 | + try { |
1403 | + int read; |
1404 | + Reader reader = new InputStreamReader(new FileInputStream(file), "UTF-8"); |
1405 | + |
1406 | + do { |
1407 | + read = reader.read(buffer, 0, buffer.length); |
1408 | + if (read>0) { |
1409 | + out.append(buffer, 0, read); |
1410 | + } |
1411 | + } |
1412 | + while (read>=0); |
1413 | + |
1414 | + Matcher m = note_content.matcher(out.toString()); |
1415 | + if (m.find()) { |
1416 | + note.setXmlContent(m.group()); |
1417 | + } else { |
1418 | + if (Tomdroid.LOGGING_ENABLED) Log.w(TAG, "Something went wrong trying to grab the note-content out of a note"); |
1419 | + } |
1420 | + |
1421 | + } catch (IOException e) { |
1422 | + // TODO handle properly |
1423 | + e.printStackTrace(); |
1424 | + if (Tomdroid.LOGGING_ENABLED) Log.w(TAG, "Something went wrong trying to read the note"); |
1425 | } |
1426 | |
1427 | - // notify UI that we are done here and send result |
1428 | - warnHandler(); |
1429 | + NoteManager.putNote(AsyncNoteLoaderAndParser.this.activity, note); |
1430 | } |
1431 | - |
1432 | - private void warnHandler() { |
1433 | - |
1434 | - // notify the main UI that we are done here (sending an ok along with the note's title) |
1435 | - Message msg = Message.obtain(); |
1436 | - Bundle bundle = new Bundle(); |
1437 | - bundle.putString(Note.TITLE, note.getTitle()); |
1438 | - msg.setData(bundle); |
1439 | - msg.what = Note.NOTE_RECEIVED_AND_VALID; |
1440 | - |
1441 | - parentHandler.sendMessage(msg); |
1442 | - } |
1443 | - |
1444 | } |
1445 | } |
1446 | |
1447 | === renamed file 'src/org/tomdroid/util/NoteBuilder.java' => 'src/org/tomdroid/util/NoteContentBuilder.java' |
1448 | --- src/org/tomdroid/util/NoteBuilder.java 2009-06-21 20:25:16 +0000 |
1449 | +++ src/org/tomdroid/util/NoteContentBuilder.java 2010-01-17 18:10:19 +0000 |
1450 | @@ -3,7 +3,7 @@ |
1451 | * Tomboy on Android |
1452 | * http://www.launchpad.net/tomdroid |
1453 | * |
1454 | - * Copyright 2008, 2009 Olivier Bilodeau <olivier@bottomlesspit.org> |
1455 | + * Copyright 2008, 2009, 2010 Olivier Bilodeau <olivier@bottomlesspit.org> |
1456 | * |
1457 | * This file is part of Tomdroid. |
1458 | * |
1459 | @@ -22,43 +22,30 @@ |
1460 | */ |
1461 | package org.tomdroid.util; |
1462 | |
1463 | -import java.io.BufferedInputStream; |
1464 | -import java.io.BufferedReader; |
1465 | -import java.io.File; |
1466 | -import java.io.FileInputStream; |
1467 | -import java.io.InputStream; |
1468 | -import java.io.InputStreamReader; |
1469 | -import java.net.URL; |
1470 | +import java.io.StringReader; |
1471 | |
1472 | import javax.xml.parsers.SAXParser; |
1473 | import javax.xml.parsers.SAXParserFactory; |
1474 | |
1475 | -import org.tomdroid.Note; |
1476 | import org.tomdroid.ui.Tomdroid; |
1477 | -import org.tomdroid.xml.NoteHandler; |
1478 | +import org.tomdroid.xml.NoteContentHandler; |
1479 | import org.xml.sax.InputSource; |
1480 | -import org.xml.sax.XMLReader; |
1481 | |
1482 | -import android.os.Bundle; |
1483 | import android.os.Handler; |
1484 | import android.os.Message; |
1485 | +import android.text.SpannableStringBuilder; |
1486 | import android.util.Log; |
1487 | |
1488 | -/* |
1489 | - * For now, you should only use this class for a Note fetched through the network |
1490 | - * TODO remove duplication between here and AsyncNoteLoaderAndParser |
1491 | - * |
1492 | - */ |
1493 | -public class NoteBuilder implements Runnable { |
1494 | +public class NoteContentBuilder implements Runnable { |
1495 | + |
1496 | + public static final int PARSE_OK = 0; |
1497 | + public static final int PARSE_ERROR = 1; |
1498 | |
1499 | // Metadata for the Note that will be built |
1500 | - private File file; |
1501 | - private URL url; |
1502 | - // true means local note and false means Web note |
1503 | - private Boolean noteTypeLocal; // using the Object only to be able to test against null |
1504 | + private InputSource noteContentIs; |
1505 | |
1506 | // the object being built |
1507 | - private Note note = new Note(); |
1508 | + private SpannableStringBuilder noteContent = new SpannableStringBuilder(); |
1509 | |
1510 | private final String TAG = "NoteBuilder"; |
1511 | |
1512 | @@ -66,94 +53,65 @@ |
1513 | private Thread runner; |
1514 | private Handler parentHandler; |
1515 | |
1516 | - public NoteBuilder () {} |
1517 | + public NoteContentBuilder () {} |
1518 | |
1519 | - public NoteBuilder setCaller(Handler parent) { |
1520 | + public NoteContentBuilder setCaller(Handler parent) { |
1521 | |
1522 | parentHandler = parent; |
1523 | return this; |
1524 | } |
1525 | |
1526 | - public NoteBuilder setInputSource(File f) { |
1527 | - |
1528 | - file = f; |
1529 | - note.setFileName(file.getAbsolutePath()); |
1530 | - noteTypeLocal = new Boolean(true); |
1531 | - return this; |
1532 | - } |
1533 | - |
1534 | - public NoteBuilder setInputSource(URL u) { |
1535 | - |
1536 | - url = u; |
1537 | - noteTypeLocal = new Boolean(false); |
1538 | - return this; |
1539 | - } |
1540 | - |
1541 | - public Note build() { |
1542 | + public NoteContentBuilder setInputSource(String nc) { |
1543 | + |
1544 | + noteContentIs = new InputSource(new StringReader(nc)); |
1545 | + return this; |
1546 | + } |
1547 | + |
1548 | + public SpannableStringBuilder build() { |
1549 | |
1550 | runner = new Thread(this); |
1551 | runner.start(); |
1552 | - return note; |
1553 | + return noteContent; |
1554 | } |
1555 | |
1556 | public void run() { |
1557 | |
1558 | + boolean successful = true; |
1559 | + |
1560 | try { |
1561 | // Parsing |
1562 | // XML |
1563 | // Get a SAXParser from the SAXPArserFactory |
1564 | SAXParserFactory spf = SAXParserFactory.newInstance(); |
1565 | + |
1566 | + // trashing the namespaces but keep prefixes (since we don't have the xml header) |
1567 | + spf.setFeature("http://xml.org/sax/features/namespaces", false); |
1568 | + spf.setFeature("http://xml.org/sax/features/namespace-prefixes", true); |
1569 | SAXParser sp = spf.newSAXParser(); |
1570 | - |
1571 | - // Get the XMLReader of the SAXParser we created |
1572 | - XMLReader xr = sp.getXMLReader(); |
1573 | - |
1574 | - // Create a new ContentHandler, send it this note to fill and apply it to the XML-Reader |
1575 | - NoteHandler xmlHandler = new NoteHandler(note); |
1576 | - xr.setContentHandler(xmlHandler); |
1577 | - |
1578 | - if (noteTypeLocal == null) { |
1579 | - // TODO find the proper exception to throw here. |
1580 | - throw new IllegalArgumentException("You are not respecting NoteBuilder's contract."); |
1581 | - } |
1582 | - |
1583 | - // Create the proper input source based on if its a local note or a web note |
1584 | - InputSource is; |
1585 | - if (noteTypeLocal) { |
1586 | |
1587 | - FileInputStream fin = new FileInputStream(file); |
1588 | - BufferedReader in = new BufferedReader(new InputStreamReader(fin)); |
1589 | - is = new InputSource(in); |
1590 | - } else { |
1591 | - is = new InputSource(new BufferedInputStream((InputStream) url.getContent())); |
1592 | - } |
1593 | - |
1594 | if (Tomdroid.LOGGING_ENABLED) Log.v(TAG, "parsing note"); |
1595 | - xr.parse(is); |
1596 | + sp.parse(noteContentIs, new NoteContentHandler(noteContent)); |
1597 | } catch (Exception e) { |
1598 | + e.printStackTrace(); |
1599 | // TODO handle error in a more granular way |
1600 | - warnHandler(false); |
1601 | + Log.e(TAG, "There was an error parsing the note."); |
1602 | + successful = false; |
1603 | } |
1604 | |
1605 | - // notify UI that we are done here and send result |
1606 | - warnHandler(true); |
1607 | + warnHandler(successful); |
1608 | } |
1609 | |
1610 | - private void warnHandler(boolean successfull) { |
1611 | + private void warnHandler(boolean successful) { |
1612 | |
1613 | // notify the main UI that we are done here (sending an ok along with the note's title) |
1614 | Message msg = Message.obtain(); |
1615 | - if (successfull) { |
1616 | - Bundle bundle = new Bundle(); |
1617 | - bundle.putString(Note.TITLE, note.getTitle()); |
1618 | - msg.setData(bundle); |
1619 | - msg.what = Note.NOTE_RECEIVED_AND_VALID; |
1620 | + if (successful) { |
1621 | + msg.what = PARSE_OK; |
1622 | } else { |
1623 | |
1624 | - msg.what = Note.NOTE_BADURL_OR_PARSING_ERROR; |
1625 | + msg.what = PARSE_ERROR; |
1626 | } |
1627 | |
1628 | parentHandler.sendMessage(msg); |
1629 | } |
1630 | - |
1631 | } |
1632 | |
1633 | === added file 'src/org/tomdroid/xml/NoteContentHandler.java' |
1634 | --- src/org/tomdroid/xml/NoteContentHandler.java 1970-01-01 00:00:00 +0000 |
1635 | +++ src/org/tomdroid/xml/NoteContentHandler.java 2010-01-17 18:10:19 +0000 |
1636 | @@ -0,0 +1,200 @@ |
1637 | +/* |
1638 | + * Tomdroid |
1639 | + * Tomboy on Android |
1640 | + * http://www.launchpad.net/tomdroid |
1641 | + * |
1642 | + * Copyright 2008, 2009, 2010 Olivier Bilodeau <olivier@bottomlesspit.org> |
1643 | + * |
1644 | + * This file is part of Tomdroid. |
1645 | + * |
1646 | + * Tomdroid is free software: you can redistribute it and/or modify |
1647 | + * it under the terms of the GNU General Public License as published by |
1648 | + * the Free Software Foundation, either version 3 of the License, or |
1649 | + * (at your option) any later version. |
1650 | + * |
1651 | + * Tomdroid is distributed in the hope that it will be useful, |
1652 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
1653 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
1654 | + * GNU General Public License for more details. |
1655 | + * |
1656 | + * You should have received a copy of the GNU General Public License |
1657 | + * along with Tomdroid. If not, see <http://www.gnu.org/licenses/>. |
1658 | + */ |
1659 | +package org.tomdroid.xml; |
1660 | + |
1661 | +import org.tomdroid.Note; |
1662 | +import org.xml.sax.Attributes; |
1663 | +import org.xml.sax.SAXException; |
1664 | +import org.xml.sax.helpers.DefaultHandler; |
1665 | + |
1666 | +import android.text.Spannable; |
1667 | +import android.text.SpannableStringBuilder; |
1668 | +import android.text.style.BackgroundColorSpan; |
1669 | +import android.text.style.BulletSpan; |
1670 | +import android.text.style.LeadingMarginSpan; |
1671 | +import android.text.style.RelativeSizeSpan; |
1672 | +import android.text.style.StrikethroughSpan; |
1673 | +import android.text.style.StyleSpan; |
1674 | +import android.text.style.TypefaceSpan; |
1675 | + |
1676 | +/* |
1677 | + * This class is responsible for parsing the xml note content |
1678 | + * and formatting the contents in a SpannableStringBuilder |
1679 | + */ |
1680 | +public class NoteContentHandler extends DefaultHandler { |
1681 | + |
1682 | + // position keepers |
1683 | + private boolean inNoteContentTag = false; |
1684 | + private boolean inBoldTag = false; |
1685 | + private boolean inItalicTag = false; |
1686 | + private boolean inStrikeTag = false; |
1687 | + private boolean inHighlighTag = false; |
1688 | + private boolean inMonospaceTag = false; |
1689 | + private boolean inSizeSmallTag = false; |
1690 | + private boolean inSizeLargeTag = false; |
1691 | + private boolean inSizeHugeTag = false; |
1692 | + private int inListLevel = 0; |
1693 | + private boolean inListItem = false; |
1694 | + |
1695 | + // -- Tomboy's notes XML tags names -- |
1696 | + // Style related |
1697 | + private final static String NOTE_CONTENT = "note-content"; |
1698 | + private final static String BOLD = "bold"; |
1699 | + private final static String ITALIC = "italic"; |
1700 | + private final static String STRIKETHROUGH = "strikethrough"; |
1701 | + private final static String HIGHLIGHT = "highlight"; |
1702 | + private final static String MONOSPACE = "monospace"; |
1703 | + private final static String SMALL = "size:small"; |
1704 | + private final static String LARGE = "size:large"; |
1705 | + private final static String HUGE = "size:huge"; |
1706 | + // Bullet list-related |
1707 | + private final static String LIST = "list"; |
1708 | + private final static String LIST_ITEM = "list-item"; |
1709 | + |
1710 | + // accumulate notecontent is this var since it spans multiple xml tags |
1711 | + private SpannableStringBuilder ssb; |
1712 | + |
1713 | + public NoteContentHandler(SpannableStringBuilder noteContent) { |
1714 | + |
1715 | + this.ssb = noteContent; |
1716 | + } |
1717 | + |
1718 | + @Override |
1719 | + public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { |
1720 | + |
1721 | + if (name.equals(NOTE_CONTENT)) { |
1722 | + |
1723 | + // we are under the note-content tag |
1724 | + // we will append all its nested tags so I create a string builder to do that |
1725 | + inNoteContentTag = true; |
1726 | + } |
1727 | + |
1728 | + // if we are in note-content, keep and convert formatting tags |
1729 | + // TODO is XML CaSe SeNsItIve? if not change equals to equalsIgnoreCase and apply to endElement() |
1730 | + if (inNoteContentTag) { |
1731 | + if (name.equals(BOLD)) { |
1732 | + inBoldTag = true; |
1733 | + } else if (name.equals(ITALIC)) { |
1734 | + inItalicTag = true; |
1735 | + } else if (name.equals(STRIKETHROUGH)) { |
1736 | + inStrikeTag = true; |
1737 | + } else if (name.equals(HIGHLIGHT)) { |
1738 | + inHighlighTag = true; |
1739 | + } else if (name.equals(MONOSPACE)) { |
1740 | + inMonospaceTag = true; |
1741 | + } else if (name.equals(SMALL)) { |
1742 | + inSizeSmallTag = true; |
1743 | + } else if (name.equals(LARGE)) { |
1744 | + inSizeLargeTag = true; |
1745 | + } else if (name.equals(HUGE)) { |
1746 | + inSizeHugeTag = true; |
1747 | + } else if (name.equals(LIST)) { |
1748 | + inListLevel++; |
1749 | + } else if (name.equals(LIST_ITEM)) { |
1750 | + inListItem = true; |
1751 | + } |
1752 | + } |
1753 | + |
1754 | + } |
1755 | + |
1756 | + @Override |
1757 | + public void endElement(String uri, String localName, String name) |
1758 | + throws SAXException { |
1759 | + |
1760 | + if (name.equals(NOTE_CONTENT)) { |
1761 | + inNoteContentTag = false; |
1762 | + } |
1763 | + |
1764 | + // if we are in note-content, keep and convert formatting tags |
1765 | + if (inNoteContentTag) { |
1766 | + if (name.equals(BOLD)) { |
1767 | + inBoldTag = false; |
1768 | + } else if (name.equals(ITALIC)) { |
1769 | + inItalicTag = false; |
1770 | + } else if (name.equals(STRIKETHROUGH)) { |
1771 | + inStrikeTag = false; |
1772 | + } else if (name.equals(HIGHLIGHT)) { |
1773 | + inHighlighTag = false; |
1774 | + } else if (name.equals(MONOSPACE)) { |
1775 | + inMonospaceTag = false; |
1776 | + } else if (name.equals(SMALL)) { |
1777 | + inSizeSmallTag = false; |
1778 | + } else if (name.equals(LARGE)) { |
1779 | + inSizeLargeTag = false; |
1780 | + } else if (name.equals(HUGE)) { |
1781 | + inSizeHugeTag = false; |
1782 | + } else if (name.equals(LIST)) { |
1783 | + inListLevel--; |
1784 | + } else if (name.equals(LIST_ITEM)) { |
1785 | + inListItem = false; |
1786 | + } |
1787 | + } |
1788 | + } |
1789 | + |
1790 | + @Override |
1791 | + public void characters(char[] ch, int start, int length) |
1792 | + throws SAXException { |
1793 | + |
1794 | + String currentString = new String(ch, start, length); |
1795 | + |
1796 | + if (inNoteContentTag) { |
1797 | + // while we are in note-content, append |
1798 | + ssb.append(currentString, start, length); |
1799 | + int strLenStart = ssb.length()-length; |
1800 | + int strLenEnd = ssb.length(); |
1801 | + |
1802 | + // apply style if required |
1803 | + // TODO I haven't tested nested tags yet |
1804 | + if (inBoldTag) { |
1805 | + ssb.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
1806 | + } |
1807 | + if (inItalicTag) { |
1808 | + ssb.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
1809 | + } |
1810 | + if (inStrikeTag) { |
1811 | + ssb.setSpan(new StrikethroughSpan(), strLenStart, ssb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
1812 | + } |
1813 | + if (inHighlighTag) { |
1814 | + ssb.setSpan(new BackgroundColorSpan(Note.NOTE_HIGHLIGHT_COLOR), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
1815 | + } |
1816 | + if (inMonospaceTag) { |
1817 | + ssb.setSpan(new TypefaceSpan(Note.NOTE_MONOSPACE_TYPEFACE), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
1818 | + } |
1819 | + if (inSizeSmallTag) { |
1820 | + ssb.setSpan(new RelativeSizeSpan(Note.NOTE_SIZE_SMALL_FACTOR), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
1821 | + } |
1822 | + if (inSizeLargeTag) { |
1823 | + ssb.setSpan(new RelativeSizeSpan(Note.NOTE_SIZE_LARGE_FACTOR), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
1824 | + } |
1825 | + if (inSizeHugeTag) { |
1826 | + ssb.setSpan(new RelativeSizeSpan(Note.NOTE_SIZE_HUGE_FACTOR), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
1827 | + } |
1828 | + if (inListItem) { |
1829 | + // TODO new sexier bullets? |
1830 | + // Show a leading margin that is as wide as the nested level we are in |
1831 | + ssb.setSpan(new LeadingMarginSpan.Standard(10*inListLevel), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
1832 | + ssb.setSpan(new BulletSpan(), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
1833 | + } |
1834 | + } |
1835 | + } |
1836 | +} |
1837 | |
1838 | === modified file 'src/org/tomdroid/xml/NoteHandler.java' |
1839 | --- src/org/tomdroid/xml/NoteHandler.java 2009-06-21 21:59:41 +0000 |
1840 | +++ src/org/tomdroid/xml/NoteHandler.java 2010-01-17 18:10:19 +0000 |
1841 | @@ -3,7 +3,7 @@ |
1842 | * Tomboy on Android |
1843 | * http://www.launchpad.net/tomdroid |
1844 | * |
1845 | - * Copyright 2008 Olivier Bilodeau <olivier@bottomlesspit.org> |
1846 | + * Copyright 2008, 2009, 2010 Olivier Bilodeau <olivier@bottomlesspit.org> |
1847 | * |
1848 | * This file is part of Tomdroid. |
1849 | * |
1850 | @@ -22,169 +22,51 @@ |
1851 | */ |
1852 | package org.tomdroid.xml; |
1853 | |
1854 | -import org.joda.time.format.DateTimeFormatter; |
1855 | -import org.joda.time.format.ISODateTimeFormat; |
1856 | import org.tomdroid.Note; |
1857 | import org.xml.sax.Attributes; |
1858 | import org.xml.sax.SAXException; |
1859 | import org.xml.sax.helpers.DefaultHandler; |
1860 | |
1861 | -import android.text.Spannable; |
1862 | -import android.text.SpannableStringBuilder; |
1863 | -import android.text.style.BackgroundColorSpan; |
1864 | -import android.text.style.BulletSpan; |
1865 | -import android.text.style.LeadingMarginSpan; |
1866 | -import android.text.style.RelativeSizeSpan; |
1867 | -import android.text.style.StrikethroughSpan; |
1868 | -import android.text.style.StyleSpan; |
1869 | -import android.text.style.TypefaceSpan; |
1870 | - |
1871 | -/* |
1872 | - * I don't know if I'm doing the right thing but I think that giving this class |
1873 | - * the responsibility of filling the note is something quite cohesive and hope |
1874 | - * the coupling involved won't do much damage. I guess time will tell. |
1875 | - */ |
1876 | public class NoteHandler extends DefaultHandler { |
1877 | |
1878 | // position keepers |
1879 | private boolean inTitleTag = false; |
1880 | private boolean inLastChangeDateTag = false; |
1881 | - private boolean inNoteTag = false; |
1882 | - private boolean inTextTag = false; |
1883 | - private boolean inNoteContentTag = false; |
1884 | - private boolean inNoteContentTagMustGrabTitle = true; // hack to grab title and make it big |
1885 | - private boolean inBoldTag = false; |
1886 | - private boolean inItalicTag = false; |
1887 | - private boolean inStrikeTag = false; |
1888 | - private boolean inHighlighTag = false; |
1889 | - private boolean inMonospaceTag = false; |
1890 | - private boolean inSizeSmallTag = false; |
1891 | - private boolean inSizeLargeTag = false; |
1892 | - private boolean inSizeHugeTag = false; |
1893 | - private int inListLevel = 0; |
1894 | - private boolean inListItem = false; |
1895 | |
1896 | // -- Tomboy's notes XML tags names -- |
1897 | // Metadata related |
1898 | private final static String TITLE = "title"; |
1899 | private final static String LAST_CHANGE_DATE = "last-change-date"; |
1900 | - // Style related |
1901 | - private final static String NOTE_CONTENT = "note-content"; |
1902 | - private final static String BOLD = "bold"; |
1903 | - private final static String ITALIC = "italic"; |
1904 | - private final static String STRIKETHROUGH = "strikethrough"; |
1905 | - private final static String HIGHLIGHT = "highlight"; |
1906 | - private final static String MONOSPACE = "monospace"; |
1907 | - // Sizes are using a namespace identifier size. Ex: <size:small></size:small> |
1908 | - private final static String NS_SIZE = "http://beatniksoftware.com/tomboy/size"; |
1909 | - private final static String SMALL = "small"; |
1910 | - private final static String LARGE = "large"; |
1911 | - private final static String HUGE = "huge"; |
1912 | - // Bullet list-related |
1913 | - private final static String LIST = "list"; |
1914 | - private final static String LIST_ITEM = "list-item"; |
1915 | - |
1916 | - // accumulate notecontent is this var since it spans multiple xml tags |
1917 | - private SpannableStringBuilder ssb; |
1918 | |
1919 | // link to model |
1920 | private Note note; |
1921 | |
1922 | public NoteHandler(Note note) { |
1923 | this.note = note; |
1924 | - |
1925 | - // we will use the SpannableStringBuilder from the note |
1926 | - this.ssb = note.getNoteContent(); |
1927 | } |
1928 | |
1929 | @Override |
1930 | public void startElement(String uri, String localName, String name, Attributes attributes) throws SAXException { |
1931 | |
1932 | - // TODO validate top-level tag for tomboy notes and throw exception if its the wrong version number (maybe offer to parse also?) |
1933 | - |
1934 | - if (localName.equals(NOTE_CONTENT)) { |
1935 | + // TODO validate top-level tag for tomboy notes and throw exception if its the wrong version number (maybe offer to parse also?) |
1936 | |
1937 | - // we are under the note-content tag |
1938 | - // we will append all its nested tags so I create a string builder to do that |
1939 | - inNoteContentTag = true; |
1940 | - } else if (localName.equals(TITLE)) { |
1941 | + if (localName.equals(TITLE)) { |
1942 | inTitleTag = true; |
1943 | } else if (localName.equals(LAST_CHANGE_DATE)) { |
1944 | inLastChangeDateTag = true; |
1945 | } |
1946 | |
1947 | - // if we are in note-content, keep and convert formatting tags |
1948 | - // TODO is XML CaSe SeNsItIve? if not change equals to equalsIgnoreCase and apply to endElement() |
1949 | - if (inNoteContentTag) { |
1950 | - if (localName.equals(BOLD)) { |
1951 | - inBoldTag = true; |
1952 | - } else if (localName.equals(ITALIC)) { |
1953 | - inItalicTag = true; |
1954 | - } else if (localName.equals(STRIKETHROUGH)) { |
1955 | - inStrikeTag = true; |
1956 | - } else if (localName.equals(HIGHLIGHT)) { |
1957 | - inHighlighTag = true; |
1958 | - } else if (localName.equals(MONOSPACE)) { |
1959 | - inMonospaceTag = true; |
1960 | - } else if (uri.equals(NS_SIZE)) { |
1961 | - // now check for the different possible sizes |
1962 | - if (localName.equals(SMALL)) { |
1963 | - inSizeSmallTag = true; |
1964 | - } else if (localName.equals(LARGE)) { |
1965 | - inSizeLargeTag = true; |
1966 | - } else if (localName.equals(HUGE)) { |
1967 | - inSizeHugeTag = true; |
1968 | - } |
1969 | - } else if (localName.equals(LIST)) { |
1970 | - inListLevel++; |
1971 | - } else if (localName.equals(LIST_ITEM)) { |
1972 | - inListItem = true; |
1973 | - } |
1974 | - } |
1975 | - |
1976 | } |
1977 | |
1978 | @Override |
1979 | public void endElement(String uri, String localName, String name) |
1980 | throws SAXException { |
1981 | |
1982 | - if (localName.equals(NOTE_CONTENT)) { |
1983 | - |
1984 | - // note-content is over, we can set the builded note to Note's noteContent |
1985 | - inNoteContentTag = false; |
1986 | - } else if (localName.equals(TITLE)) { |
1987 | + if (localName.equals(TITLE)) { |
1988 | inTitleTag = false; |
1989 | } else if (localName.equals(LAST_CHANGE_DATE)) { |
1990 | inLastChangeDateTag = false; |
1991 | } |
1992 | - |
1993 | - // if we are in note-content, keep and convert formatting tags |
1994 | - if (inNoteContentTag) { |
1995 | - if (localName.equals(BOLD)) { |
1996 | - inBoldTag = false; |
1997 | - } else if (localName.equals(ITALIC)) { |
1998 | - inItalicTag = false; |
1999 | - } else if (localName.equals(STRIKETHROUGH)) { |
2000 | - inStrikeTag = false; |
2001 | - } else if (localName.equals(HIGHLIGHT)) { |
2002 | - inHighlighTag = false; |
2003 | - } else if (localName.equals(MONOSPACE)) { |
2004 | - inMonospaceTag = false; |
2005 | - } else if (uri.equals(NS_SIZE)) { |
2006 | - // now check for the different possible sizes |
2007 | - if (localName.equals(SMALL)) { |
2008 | - inSizeSmallTag = false; |
2009 | - } else if (localName.equals(LARGE)) { |
2010 | - inSizeLargeTag = false; |
2011 | - } else if (localName.equals(HUGE)) { |
2012 | - inSizeHugeTag = false; |
2013 | - } |
2014 | - } else if (localName.equals(LIST)) { |
2015 | - inListLevel--; |
2016 | - } else if (localName.equals(LIST_ITEM)) { |
2017 | - inListItem = false; |
2018 | - } |
2019 | - } |
2020 | } |
2021 | |
2022 | // FIXME we'll have to think about how we handle the title soon.. IMHO there's a problem with duplicating the data from the <title> tag and also putting it straight into the note.. this will have to be reported to tomboy |
2023 | @@ -202,52 +84,5 @@ |
2024 | // DateTimeFormatter fmt = ISODateTimeFormat.dateTime(); |
2025 | // note.setLastChangeDate(fmt.parseDateTime(currentString)); |
2026 | } |
2027 | - |
2028 | - if (inNoteContentTag) { |
2029 | - // while we are in note-content, append |
2030 | - ssb.append(currentString, start, length); |
2031 | - int strLenStart = ssb.length()-length; |
2032 | - int strLenEnd = ssb.length(); |
2033 | - |
2034 | - // the first line of the note-content tag is the note's title. It must be big like in tomboy. |
2035 | - // TODO tomboy's fileformat suggestion: title should not be repeated in the note-content. This is ugly IMHO |
2036 | - if (inNoteContentTagMustGrabTitle) { |
2037 | - ssb.setSpan(new RelativeSizeSpan(Note.NOTE_SIZE_HUGE_FACTOR), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
2038 | - inNoteContentTagMustGrabTitle = false; |
2039 | - } |
2040 | - |
2041 | - // apply style if required |
2042 | - // TODO I haven't tested nested tags yet |
2043 | - if (inBoldTag) { |
2044 | - ssb.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
2045 | - } |
2046 | - if (inItalicTag) { |
2047 | - ssb.setSpan(new StyleSpan(android.graphics.Typeface.ITALIC), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
2048 | - } |
2049 | - if (inStrikeTag) { |
2050 | - ssb.setSpan(new StrikethroughSpan(), strLenStart, ssb.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
2051 | - } |
2052 | - if (inHighlighTag) { |
2053 | - ssb.setSpan(new BackgroundColorSpan(Note.NOTE_HIGHLIGHT_COLOR), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
2054 | - } |
2055 | - if (inMonospaceTag) { |
2056 | - ssb.setSpan(new TypefaceSpan(Note.NOTE_MONOSPACE_TYPEFACE), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
2057 | - } |
2058 | - if (inSizeSmallTag) { |
2059 | - ssb.setSpan(new RelativeSizeSpan(Note.NOTE_SIZE_SMALL_FACTOR), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
2060 | - } |
2061 | - if (inSizeLargeTag) { |
2062 | - ssb.setSpan(new RelativeSizeSpan(Note.NOTE_SIZE_LARGE_FACTOR), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
2063 | - } |
2064 | - if (inSizeHugeTag) { |
2065 | - ssb.setSpan(new RelativeSizeSpan(Note.NOTE_SIZE_HUGE_FACTOR), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
2066 | - } |
2067 | - if (inListItem) { |
2068 | - // TODO new sexier bullets? |
2069 | - // Show a leading margin that is as wide as the nested level we are in |
2070 | - ssb.setSpan(new LeadingMarginSpan.Standard(10*inListLevel), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
2071 | - ssb.setSpan(new BulletSpan(), strLenStart, strLenEnd, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); |
2072 | - } |
2073 | - } |
2074 | } |
2075 | } |
I'm finished with the work on this branch. I believe this is a good foundation for the snowy sync and other future features.
I tested it as best as I could fixing the bugs along the way, I don't think there should be many left.