keepyourhead 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. data/COPYING.txt +674 -0
  2. data/LICENSE.rdoc +20 -0
  3. data/README.rdoc +3 -0
  4. data/bin/keepyourhead +6 -0
  5. data/data/glade/DialogEditLatex.glade +180 -0
  6. data/data/glade/DialogEditText.glade +66 -0
  7. data/data/glade/DialogTrainStart.glade +101 -0
  8. data/data/glade/WindowEdit.glade +1419 -0
  9. data/data/glade/WindowTrain.glade +271 -0
  10. data/data/images/error_back.png +0 -0
  11. data/data/images/error_front.png +0 -0
  12. data/data/images/loading_back.png +0 -0
  13. data/data/images/loading_front.png +0 -0
  14. data/lib/Keepyourhead.rb +62 -0
  15. data/lib/Keepyourhead/Application.rb +94 -0
  16. data/lib/Keepyourhead/Cache.rb +233 -0
  17. data/lib/Keepyourhead/Compilation.rb +38 -0
  18. data/lib/Keepyourhead/Images.rb +62 -0
  19. data/lib/Keepyourhead/Preferences.rb +52 -0
  20. data/lib/Keepyourhead/Requirements.rb +72 -0
  21. data/lib/Keepyourhead/Resources.rb +45 -0
  22. data/lib/Keepyourhead/Training.rb +132 -0
  23. data/lib/Keepyourhead/Utils.rb +97 -0
  24. data/lib/Keepyourhead/Version.rb +43 -0
  25. data/lib/Keepyourhead/database/Base.rb +77 -0
  26. data/lib/Keepyourhead/database/BaseStatistic.rb +63 -0
  27. data/lib/Keepyourhead/database/BaseTopicFlashcardContainer.rb +43 -0
  28. data/lib/Keepyourhead/database/Collection.rb +43 -0
  29. data/lib/Keepyourhead/database/Database.rb +139 -0
  30. data/lib/Keepyourhead/database/File.rb +224 -0
  31. data/lib/Keepyourhead/database/FileRoot.rb +44 -0
  32. data/lib/Keepyourhead/database/Flashcard.rb +116 -0
  33. data/lib/Keepyourhead/database/Topic.rb +40 -0
  34. data/lib/Keepyourhead/database/Visitor.rb +33 -0
  35. data/lib/Keepyourhead/database/XmlAccessor.rb +315 -0
  36. data/lib/Keepyourhead/gui/Action.rb +91 -0
  37. data/lib/Keepyourhead/gui/DialogEditLatex.rb +132 -0
  38. data/lib/Keepyourhead/gui/DialogEditText.rb +104 -0
  39. data/lib/Keepyourhead/gui/DialogTrainStart.rb +63 -0
  40. data/lib/Keepyourhead/gui/FlashcardViewController.rb +112 -0
  41. data/lib/Keepyourhead/gui/WindowEdit.rb +469 -0
  42. data/lib/Keepyourhead/gui/WindowEditActions.rb +440 -0
  43. data/lib/Keepyourhead/gui/WindowEditAdapters.rb +329 -0
  44. data/lib/Keepyourhead/gui/WindowTrain.rb +167 -0
  45. data/lib/Keepyourhead/style/Style.rb +48 -0
  46. data/lib/Keepyourhead/style/StyleLatex.rb +235 -0
  47. metadata +100 -0
@@ -0,0 +1,440 @@
1
+ # Copyright 2008 Burghard Oliver
2
+ #
3
+ # This file is part of KeepYourHead.
4
+ #
5
+ # KeepYourHead is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # KeepYourHead is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with KeepYourHead. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+
19
+ module KeepYourHead
20
+ class WindowEdit
21
+ def initActions
22
+ @actions = {}
23
+ Actions.each { |name, procExecuteable|
24
+ action = Action.new self, name
25
+ action.procExecuteable = procExecuteable
26
+
27
+ name2 = name.gsub( /[A-Z]/ ) { |s| "_" + s.downcase }[1..-1]
28
+
29
+ menuItem = @glade.get_widget("menuitem_#{name2}")
30
+ toolButton = @glade.get_widget("toolbutton_#{name2}")
31
+
32
+ # print "not found menuItem for #{name2}" unless menuItem
33
+ # print "not found toolButton for #{name2}" unless toolButton
34
+
35
+ action.addActivator menuItem if menuItem
36
+ action.addActivator toolButton if toolButton
37
+
38
+ @actions[name] = action
39
+ }
40
+ end
41
+
42
+ def callAction(name, *args)
43
+ assert @actions[name.to_s] and @actions[name.to_s].executeable?
44
+
45
+ @actions[name.to_s].activate( *args )
46
+ end
47
+
48
+ MapNameToClass = {
49
+ "flashcard" => Database::Flashcard,
50
+ "topic" => Database::Topic,
51
+ "collection" => Database::Collection,
52
+ }
53
+ AcceptStrict = {
54
+ Database::Database => [Database::File],
55
+ Database::File => [Database::Collection],
56
+ Database::Collection => [Database::Topic, Database::Flashcard],
57
+ Database::Topic => [Database::Topic, Database::Flashcard],
58
+ Database::Flashcard => []
59
+ }
60
+ def self.canInsertStrict(parent, other)
61
+ return false unless parent and other
62
+
63
+ type =
64
+ case other
65
+ when String
66
+ MapNameToClass[other.downcase]
67
+ when REXML::Element
68
+ MapNameToClass[other.name.downcase]
69
+ when Class
70
+ other
71
+ else
72
+ throw ExceptionNotImplemented.new
73
+ end
74
+
75
+ assert AcceptStrict[parent.class]
76
+
77
+ AcceptStrict[parent.class].include? type
78
+ end
79
+
80
+ def self.canInsertInterpreted( parent, other )
81
+ return false unless parent and other
82
+ canInsertStrict( parent, other ) or ( MyAdaptor.parent(parent) and canInsertInterpreted( MyAdaptor.parent(parent), other ) )
83
+ end
84
+
85
+ def self.insertStrictAfter( parent, node, after )
86
+ assert node
87
+ assert node.kind_of?(REXML::Element)
88
+ assert canInsertStrict( parent, node.name )
89
+ MyAdaptor.insertAfter( parent, node, after )
90
+ end
91
+
92
+ def self.insertInterpretedAfter( parent, node, after )
93
+ assert node
94
+ assert node.kind_of?(REXML::Element)
95
+ assert canInsertInterpreted( parent, node.name)
96
+
97
+ if canInsertStrict( parent, node ) then
98
+ insertStrictAfter( parent, node, after )
99
+ else
100
+ assert MyAdaptor.parent(parent)
101
+ insertInterpretedAfter( MyAdaptor.parent(parent), node, parent )
102
+ end
103
+ end
104
+
105
+
106
+
107
+
108
+
109
+ Actions = [
110
+ [ "New", proc { true } ],
111
+ [ "Open", proc { true } ],
112
+ [ "Save", proc { |obj|
113
+ obj.selected && [Database::File, Database::Collection, Database::Topic,Database::Flashcard].include?(obj.selected.class) &&
114
+ obj.selected.file.changed
115
+ } ],
116
+ [ "SaveAs", proc { |obj|
117
+ obj.selected && [Database::File, Database::Collection, Database::Topic,Database::Flashcard].include?(obj.selected.class)
118
+ } ],
119
+ [ "SaveAll", proc { |obj|
120
+ true
121
+ } ],
122
+ [ "Close", proc { |obj|
123
+ obj.selected && [Database::File, Database::Collection, Database::Topic,Database::Flashcard].include?(obj.selected.class)
124
+ } ],
125
+
126
+ [ "Paste", proc { |obj|
127
+ text = Gtk::Clipboard.get(Gdk::Selection::CLIPBOARD).wait_for_text
128
+
129
+ dom = REXML::Document.new text
130
+ node = dom.root
131
+
132
+ node && canInsertInterpreted( obj.selected, node.name )
133
+ } ],
134
+ [ "Copy", proc { |obj|
135
+ obj.selected && [Database::Collection, Database::Topic,Database::Flashcard].include?(obj.selected.class)
136
+ } ],
137
+ [ "Cut", proc { |obj|
138
+ obj.selected && [Database::Collection, Database::Topic,Database::Flashcard].include?(obj.selected.class)
139
+ } ],
140
+ [ "AddTopic", proc { |obj|
141
+ obj.selected && canInsertInterpreted( obj.selected, Database::Topic)
142
+ }],
143
+ [ "AddFlashcard", proc { |obj|
144
+ obj.selected && canInsertInterpreted( obj.selected, Database::Flashcard)
145
+ }],
146
+ [ "AddCollection", proc { |obj|
147
+ obj.selected && canInsertInterpreted( obj.selected, Database::Collection)
148
+ }],
149
+ [ "Delete", proc { |obj|
150
+ obj.selected && [Database::Collection, Database::Topic, Database::Flashcard].include?(obj.selected.class)
151
+ }],
152
+ [ "Left", proc { |obj|
153
+ if obj.selected then
154
+ parent = MyAdaptor.parent(obj.selected)
155
+ if parent then
156
+ parent2 = MyAdaptor.parent(parent)
157
+ if parent2 then
158
+ return canInsertStrict( parent2, obj.selected.class)
159
+ end
160
+ end
161
+ end
162
+ false
163
+ }],
164
+ [ "Right", proc { |obj|
165
+ if obj.selected then
166
+ parent = MyAdaptor.nextSibling(obj.selected)
167
+ if parent then
168
+ return canInsertStrict( parent, obj.selected.class)
169
+ end
170
+ end
171
+ false
172
+ }],
173
+ [ "Up", proc { |obj|
174
+ if obj.selected && [Database::File, Database::Collection, Database::Topic, Database::Flashcard].include?(obj.selected.class) then
175
+ other = MyAdaptor.previousSibling obj.selected
176
+ if other then
177
+ return true
178
+ end
179
+ end
180
+ false
181
+ }],
182
+ [ "Down", proc { |obj|
183
+ if obj.selected && [Database::File, Database::Collection, Database::Topic, Database::Flashcard].include?(obj.selected.class) then
184
+ other = MyAdaptor.nextSibling obj.selected
185
+ if other then
186
+ return true
187
+ end
188
+ end
189
+ false
190
+ }],
191
+ [ "Train", proc { |obj|
192
+ true
193
+ }],
194
+ [ "About", proc { |obj|
195
+ true
196
+ }],
197
+ [ "RemoveStatistics", proc { |obj|
198
+ obj.selected && [Database::File, Database::Collection, Database::Topic, Database::Flashcard].include?(obj.selected.class)
199
+ }],
200
+ [ "Quit", proc { |obj|
201
+ true
202
+ }],
203
+ ]
204
+
205
+
206
+
207
+
208
+ def actionBefore
209
+ end
210
+ def actionAfter
211
+ updateView
212
+ end
213
+
214
+ def onActionNew
215
+ self.database.fileNew
216
+ end
217
+ def onActionOpen
218
+ dialog = Gtk::FileChooserDialog.new("Open File",
219
+ @window,
220
+ Gtk::FileChooser::ACTION_OPEN,
221
+ nil,
222
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
223
+ [Gtk::Stock::OPEN, Gtk::Dialog::RESPONSE_ACCEPT])
224
+
225
+ # dialog.current_folder = ::File.expand_path "~"
226
+
227
+ filter = Gtk::FileFilter.new
228
+ filter.name = "Flashcards (*.xfc)"
229
+ filter.add_pattern "*.xfc"
230
+ dialog.add_filter( filter )
231
+ filter = Gtk::FileFilter.new
232
+ filter.name = "all"
233
+ filter.add_pattern "*"
234
+ dialog.add_filter( filter )
235
+
236
+ if dialog.run == Gtk::Dialog::RESPONSE_ACCEPT
237
+ filename = ::File.expand_path dialog.filename
238
+ self.database.fileOpen( filename )
239
+ end
240
+ dialog.destroy
241
+ end
242
+
243
+ def onActionSaveAll
244
+ database.files.each { |file|
245
+ fileSave file if file.changed
246
+ }
247
+ end
248
+
249
+ def fileSaveAs(file)
250
+ dialog = Gtk::FileChooserDialog.new("Save File",
251
+ @window,
252
+ Gtk::FileChooser::ACTION_SAVE,
253
+ nil,
254
+ [Gtk::Stock::CANCEL, Gtk::Dialog::RESPONSE_CANCEL],
255
+ [Gtk::Stock::SAVE, Gtk::Dialog::RESPONSE_ACCEPT])
256
+
257
+ # dialog.current_folder = ::File.expand_path "~"
258
+
259
+ filter = Gtk::FileFilter.new
260
+ filter.name = "Flashcards (*.xfc)"
261
+ filter.add_pattern "*.xfc"
262
+ dialog.add_filter( filter )
263
+ filter = Gtk::FileFilter.new
264
+ filter.name = "all"
265
+ filter.add_pattern "*"
266
+ dialog.add_filter( filter )
267
+
268
+ dialog.current_name = "unnamed.xfc"
269
+
270
+ response = dialog.run
271
+ filename = dialog.filename
272
+ dialog.destroy
273
+
274
+ if response == Gtk::Dialog::RESPONSE_ACCEPT
275
+ file.saveAs filename
276
+ true
277
+ else
278
+ false
279
+ end
280
+ end
281
+ def fileSave(file)
282
+ if file.filename then
283
+ file.save
284
+ else
285
+ fileSaveAs file
286
+ end
287
+ end
288
+ def filePrepareToClose( file )
289
+ if file.changed then
290
+ dialog = Gtk::MessageDialog.new(
291
+ @window, Gtk::Dialog::MODAL, Gtk::MessageDialog::WARNING,
292
+ Gtk::MessageDialog::BUTTONS_NONE,
293
+ "Save changes ?" )
294
+ dialog.add_button( "Ja", Gtk::Dialog::RESPONSE_YES )
295
+ dialog.add_button( "Nein", Gtk::Dialog::RESPONSE_NO )
296
+ dialog.add_button( "Abbrechen", Gtk::Dialog::RESPONSE_CANCEL )
297
+
298
+ response = dialog.run
299
+ dialog.destroy
300
+
301
+ case response
302
+ when Gtk::Dialog::RESPONSE_YES
303
+ fileSave file
304
+ not file.changed
305
+ when Gtk::Dialog::RESPONSE_NO
306
+ true
307
+ when Gtk::Dialog::RESPONSE_CANCEL,
308
+ Gtk::Dialog::RESPONSE_DELETE_EVENT
309
+ false
310
+ else
311
+ false
312
+ end
313
+
314
+ else
315
+ true
316
+ end
317
+ end
318
+
319
+ def onActionSave
320
+ fileSave self.selected.file
321
+ end
322
+ def onActionSaveAs
323
+ fileSaveAs self.selected.file
324
+ end
325
+ def onActionClose
326
+ if filePrepareToClose( self.selected.file ) then
327
+ database.fileClose self.selected.file
328
+ end
329
+ end
330
+
331
+ def onActionPaste
332
+ Gtk::Clipboard.get(Gdk::Selection::CLIPBOARD).request_text{ |clipboard, text|
333
+ dom = REXML::Document.new text
334
+ node = dom.root
335
+
336
+ self.class.insertInterpretedAfter self.selected, node, MyAdaptor.lastChild(self.selected)
337
+ }
338
+ end
339
+ def onActionCut
340
+ text = ""
341
+ REXML::Formatters::Default.new.write @selected.node, text
342
+
343
+ Gtk::Clipboard.get(Gdk::Selection::CLIPBOARD).text = text
344
+ MyAdaptor.remove self.selected
345
+ end
346
+ def onActionCopy
347
+ text = ""
348
+ REXML::Formatters::Default.new.write @selected.node, text
349
+ Gtk::Clipboard.get(Gdk::Selection::CLIPBOARD).text = text
350
+ end
351
+
352
+ def onActionAddTopic
353
+ self.class.insertInterpretedAfter self.selected, Database::Topic.createNode(self.selected.file), MyAdaptor.lastChild(self.selected)
354
+ end
355
+ def onActionAddFlashcard
356
+ self.class.insertInterpretedAfter self.selected, Database::Flashcard.createNode(self.selected.file), MyAdaptor.lastChild(self.selected)
357
+ end
358
+ def onActionAddCollection
359
+ self.class.insertInterpretedAfter self.selected, Database::Collection.createNode(self.selected.file), MyAdaptor.lastChild(self.selected)
360
+ end
361
+ def onActionDelete
362
+ MyAdaptor.remove self.selected
363
+ end
364
+ def onActionLeft
365
+ parent = MyAdaptor.parent(self.selected)
366
+ parent2 = MyAdaptor.parent(parent)
367
+ other = MyAdaptor.previousSibling( parent )
368
+ node = MyAdaptor.remove( self.selected )
369
+ self.class.insertStrictAfter( parent2, node, other)
370
+ end
371
+ def onActionRight
372
+ parent = MyAdaptor.nextSibling(self.selected)
373
+ node = MyAdaptor.remove( self.selected )
374
+ self.class.insertStrictAfter( parent, node, nil)
375
+ end
376
+ def onActionUp
377
+ if @selected.class == Database::File then
378
+ database.moveUp @selected
379
+ else
380
+ parent = MyAdaptor.parent @selected
381
+ other = MyAdaptor.previousSibling @selected
382
+ other = MyAdaptor.previousSibling other
383
+
384
+ node = MyAdaptor.remove @selected
385
+ MyAdaptor.insertAfter parent, node, other
386
+ end
387
+ end
388
+ def onActionDown
389
+ if @selected.class == Database::File then
390
+ database.moveDown @selected
391
+ else
392
+ parent = MyAdaptor.parent @selected
393
+ other = MyAdaptor.nextSibling @selected
394
+
395
+ node = MyAdaptor.remove @selected
396
+ MyAdaptor.insertAfter parent, node, other
397
+ end
398
+ end
399
+ def onActionTrain
400
+ dialog = DialogQuestionStart.new
401
+ if dialog.run then
402
+ max_questions, max_minutes = dialog.max_questions, dialog.max_minutes
403
+ dialog.destroy
404
+
405
+ training = FlashcardTraining.new(database, max_questions, max_minutes * 60)
406
+ WindowQuestion.new(self, training)
407
+ else
408
+ dialog.destroy
409
+ end
410
+ end
411
+ def onActionAbout
412
+ # aboutDialog = Gtk::AboutDialog.new
413
+ Gtk::AboutDialog.show @window, {
414
+ # :artists => nil,
415
+ :authors => [Project::AUTHOR_WITH_EMAIL],
416
+ :comments => Project::SUMMARY,
417
+ :copyright => Project::COPYRIGHT,
418
+ :license => Project::LICENSE,
419
+ :name => Project::NAME,
420
+ :version => Project::VERSION,
421
+ :website => Project::HOMEPAGE,
422
+ "program-name" => Project::NAME,
423
+ }
424
+ end
425
+ def onActionRemoveStatistics
426
+ @selected.removeStatistics
427
+ end
428
+ def onActionQuit
429
+ ret = true
430
+
431
+ database.files.inject(true) { |ret, file|
432
+ ret &&= filePrepareToClose( file )
433
+ }
434
+
435
+ @window.destroy if ret
436
+ end
437
+ end
438
+ end
439
+
440
+
@@ -0,0 +1,329 @@
1
+ # Copyright 2008 Burghard Oliver
2
+ #
3
+ # This file is part of KeepYourHead.
4
+ #
5
+ # KeepYourHead is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # KeepYourHead is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with KeepYourHead. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+
19
+ module KeepYourHead
20
+ class Adaptor
21
+ def name(object)
22
+ throw ExceptionNotImplimented.new
23
+ end
24
+
25
+ def parent(object)
26
+ throw ExceptionNotImplimented.new
27
+ end
28
+ def firstChild(object)
29
+ throw ExceptionNotImplimented.new
30
+ end
31
+ def nextSibling(object)
32
+ throw ExceptionNotImplimented.new
33
+ end
34
+ def previousSibling(object)
35
+ throw ExceptionNotImplimented.new
36
+ end
37
+
38
+ def createChild(parent)
39
+ throw ExceptionNotImplimented.new
40
+ end
41
+ def insertAfter(parent,item,other)
42
+ throw ExceptionNotImplimented.new
43
+ end
44
+ def remove(item)
45
+ throw ExceptionNotImplimented.new
46
+ end
47
+
48
+ def realization(object)
49
+ throw ExceptionNotImplimented.new
50
+ end
51
+ end
52
+
53
+ class AdaptorDatabase < Adaptor
54
+ def name(object)
55
+ throw ExceptionNotImplimented.new
56
+ end
57
+
58
+ def parent(object)
59
+ nil
60
+ end
61
+ def firstChild(object)
62
+ object.files[0]
63
+ end
64
+ def nextSibling(object)
65
+ nil
66
+ end
67
+ def previousSibling(object)
68
+ nil
69
+ end
70
+
71
+ def createChild(parent)
72
+ throw ExceptionNotImplimented.new
73
+ end
74
+ def insertAfter(parent,item,other)
75
+ throw ExceptionNotImplimented.new
76
+ end
77
+ def remove(item)
78
+ throw ExceptionNotImplimented.new
79
+ end
80
+
81
+ def realization(object)
82
+ object
83
+ end
84
+ end
85
+
86
+ class AdaptorFile < Adaptor
87
+ def name(object)
88
+ object.filename ? ::File.basename(object.filename) : "(unbenannt)"
89
+ end
90
+
91
+ def parent(object)
92
+ object.database
93
+ end
94
+ def firstChild(object)
95
+ object.root.collections[0]
96
+ end
97
+ def nextSibling(object)
98
+ files = object.database.files
99
+ idx = files.index object
100
+ if idx == files.length - 1 then
101
+ nil
102
+ else
103
+ files[idx+1]
104
+ end
105
+ end
106
+ def previousSibling(object)
107
+ files = object.database.files
108
+ idx = files.index object
109
+ if idx == 0 then
110
+ nil
111
+ else
112
+ files[idx-1]
113
+ end
114
+ end
115
+
116
+ def insertAfter(parent,item,other)
117
+ if other then
118
+ parent.root.collectionInsertAfter(item,other)
119
+ else
120
+ parent.root.collectionInsertFirst(item)
121
+ end
122
+ end
123
+ def remove(item)
124
+ throw ExceptionNotImplimented.new
125
+ end
126
+ def realization(object)
127
+ object
128
+ end
129
+ end
130
+
131
+ class AdaptorCollection < Adaptor
132
+ def name(object)
133
+ object.name
134
+ end
135
+
136
+ def parent(object)
137
+ object.file
138
+ end
139
+ def firstChild(object)
140
+ object.items[0]
141
+ end
142
+ def nextSibling(object)
143
+ object.parent.collectionNext(object)
144
+ end
145
+ def previousSibling(object)
146
+ object.parent.collectionPrevious(object)
147
+ end
148
+
149
+ def insertAfter(parent,item,other)
150
+ if other then
151
+ parent.itemInsertAfter(item,other)
152
+ else
153
+ parent.itemInsertFirst(item)
154
+ end
155
+ end
156
+ def remove(item)
157
+ item.parent.collectionRemove item
158
+ end
159
+ def realization(object)
160
+ object.node
161
+ end
162
+ end
163
+
164
+ class AdaptorTopic < Adaptor
165
+ def name(object)
166
+ object.name
167
+ end
168
+
169
+ def parent(object)
170
+ object.parent
171
+ end
172
+ def firstChild(object)
173
+ object.items[0]
174
+ end
175
+ def nextSibling(object)
176
+ object.parent.itemNext object
177
+ end
178
+ def previousSibling(object)
179
+ object.parent.itemPrevious object
180
+ end
181
+
182
+ def createChild(parent)
183
+ end
184
+ def insertAfter(parent,item,other)
185
+ if other then
186
+ parent.itemInsertAfter(item,other)
187
+ else
188
+ parent.itemInsertFirst(item)
189
+ end
190
+ end
191
+ def remove(item)
192
+ item.parent.itemRemove item
193
+ end
194
+ def realization(object)
195
+ object.node
196
+ end
197
+ end
198
+
199
+ class AdaptorFlashcard < Adaptor
200
+ def name(object)
201
+ object.name
202
+ end
203
+
204
+ def parent(object)
205
+ object.parent
206
+ end
207
+ def firstChild(object)
208
+ nil
209
+ end
210
+ def nextSibling(object)
211
+ object.parent.itemNext object
212
+ end
213
+ def previousSibling(object)
214
+ object.parent.itemPrevious object
215
+ end
216
+
217
+ def createChild(parent)
218
+ end
219
+ def insertAfter(parent,item,other)
220
+ if other then
221
+ parent.itemInsertAfter(item,other)
222
+ else
223
+ parent.itemInsertFirst(item)
224
+ end
225
+ end
226
+ def remove(item)
227
+ item.parent.itemRemove item
228
+ end
229
+ def realization(object)
230
+ object.node
231
+ end
232
+ end
233
+
234
+ class AdaptorHandler
235
+ Adaptors = {
236
+ Database::Database => AdaptorDatabase.new,
237
+ Database::File => AdaptorFile.new,
238
+ Database::Collection => AdaptorCollection.new,
239
+ Database::Topic => AdaptorTopic.new,
240
+ Database::Flashcard => AdaptorFlashcard.new,
241
+ }
242
+
243
+ def name(object)
244
+ Adaptors[object.class].name object
245
+ end
246
+
247
+ def parent(object)
248
+ Adaptors[object.class].parent object
249
+ end
250
+ def firstChild(object)
251
+ Adaptors[object.class].firstChild object
252
+ end
253
+ def nextSibling(object)
254
+ Adaptors[object.class].nextSibling object
255
+ end
256
+ def previousSibling(object)
257
+ Adaptors[object.class].previousSibling object
258
+ end
259
+
260
+ def createChild(parent)
261
+ Adaptors[object.class].createChild object
262
+ end
263
+ def insertAfter(parent,item,other)
264
+ Adaptors[parent.class].insertAfter parent, item, other
265
+ end
266
+ def remove(object)
267
+ Adaptors[object.class].remove object
268
+ end
269
+
270
+ def realization(object)
271
+ Adaptors[object.class].realization object
272
+ end
273
+
274
+ #for better use
275
+
276
+ def insertLast(parent, item)
277
+ insertAfter(parent, item, lastChild(parent) )
278
+ end
279
+ def lastChild(parent)
280
+ c = firstChild(parent)
281
+
282
+ return nil unless c
283
+
284
+ while o = nextSibling(c)
285
+ c = o
286
+ end
287
+ c
288
+ end
289
+ def children(parent)
290
+ children = []
291
+ c = firstChild(parent)
292
+ while c do
293
+ children << c
294
+ c = nextSibling(c)
295
+ end
296
+ children
297
+ end
298
+
299
+
300
+ def moveUp(item)
301
+ if item.class == Database::File then
302
+ item.database.moveUp item
303
+ else
304
+ parent = self.parent item
305
+ other = self.previousSibling item
306
+ other = self.previousSibling other
307
+
308
+ node = self.remove item
309
+ self.insertAfter parent, node, other
310
+ end
311
+ end
312
+ def moveDown(item)
313
+ if item.class == Database::File then
314
+ item.database.moveDown item
315
+ else
316
+ parent = self.parent item
317
+ other = self.nextSibling item
318
+
319
+ node = self.remove item
320
+ self.insertAfter parent, node, other
321
+ end
322
+ end
323
+ end
324
+
325
+
326
+ MyAdaptor = AdaptorHandler.new
327
+
328
+
329
+ end