keepyourhead 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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