Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

75 % functional calendar

- structure can no wrap arrays, as of old.
- 55 examples, 0 failures
- fixed localemodel issues.
- model_connector fixed somewhat
  • Loading branch information...
commit 80a18a766d9f5cb9e73a38ffef3116ca224d0861 1 parent 24a7884
@EugeneBrazwick authored
Showing with 907 additions and 685 deletions.
  1. +6 −1 TODOlist
  2. +5 −1 bin/reform_launcher.rb
  3. +25 −33 lib/reform/abstractitemview.rb
  4. +17 −35 lib/reform/abstractlistview.rb
  5. +12 −13 lib/reform/app.rb
  6. +1 −1  lib/reform/contrib/widgets/calendarcolorcombo.rb
  7. +15 −23 lib/reform/control.rb
  8. +112 −112 lib/reform/examples/01_widgets/calendar.rb
  9. +3 −4 lib/reform/examples/01_widgets/calendar_prelim_a.rb
  10. +4 −1 lib/reform/examples/01_widgets/calendar_prelim_b.rb
  11. +1 −5 lib/reform/examples/01_widgets/calendar_prelim_c.rb
  12. +42 −37 lib/reform/examples/01_widgets/calendar_prelim_d.rb
  13. +12 −15 lib/reform/model.rb
  14. +149 −111 lib/reform/models/calendar_model.rb
  15. +61 −36 lib/reform/models/locale_model.rb
  16. +113 −42 lib/reform/models/rstore.rb
  17. +8 −50 lib/reform/models/structure.rb
  18. +87 −89 lib/reform/widgets/calendarwidget.rb
  19. +8 −1 lib/reform/widgets/checkbox.rb
  20. +6 −10 lib/reform/widgets/combobox.rb
  21. +16 −27 lib/reform/widgets/date.rb
  22. +5 −1 lib/reform/widgets/formlayout.rb
  23. +4 −2 lib/reform/widgets/frame.rb
  24. +14 −30 lib/reform/widgets/list.rb
  25. +77 −0 spec/reform/checkbox_spec.rb
  26. +91 −0 spec/reform/combo_spec.rb
  27. +2 −2 spec/rstore_spec.rb
  28. +11 −3 spec/structure_spec.rb
View
7 TODOlist
@@ -222,7 +222,8 @@ Current state:
observed correctly. It should add a toplevel observer, and not work really different than how the
application handles changes right now.
0041 Mon Sep 12 22:22:37 CEST 2011
- after building the qtbindings gem, it cannot be loaded! Some caching issue, because it
+ after building the qtbindings gem, it cannot be loaded! Some caching issue, because it. qtbindings is inconvenient. Constructors are
+ hacked and slow.
works after that.
0042 Thu Sep 22 21:07:50 CEST 2011
Need RStore::Item class to create auto-persistent subclasses, that allow more complicated
@@ -253,3 +254,7 @@ Current state:
-0045 Sat Oct 8 12:23:12 CEST 2011. Regression. analogclock2/3 don't rotate properly.
The arms OK, but the empty does nothing...
Sat Oct 8 19:41:00 CEST 2011 Fixed. postSetup -> model_postSetup
+0046 Sat Oct 15 21:14:45 CEST 2011. Using 'x' to set a bool prop is deprecated.
+Either say 'x true' or 'x!'.
+0047 Sat Oct 15 21:15:23 CEST 2011. qtbindings is inconvenient. Constructors are
+hacked and slow. bugs are hard to trace due to 'method_missing' crap.
View
6 bin/reform_launcher.rb
@@ -19,6 +19,10 @@
prelims.check_installation
# It is also tempting to say `exec $RUBY $PWD/gui/mainform.rb &`
# Otherwise we get a stuck terminal.... So:
- spawn ENV['RUBY'], *ARGV
+ if !File::exists?(ARGV[0]) && ARGV[0][-3, 3] != '.rb'
+ spawn ENV['RUBY'], ARGV[0] + '.rb', *(ARGV[1..-1])
+ else
+ spawn ENV['RUBY'], *ARGV
+ end
end
end
View
58 lib/reform/abstractitemview.rb
@@ -71,10 +71,10 @@ def columnCount parent = Qt::ModelIndex.new
# If the list has 1000 rows, expect 8000 calls to this method. So it should be as fast as possible.
def data index, role = Qt::DisplayRole
-# tag "data at #{index.row}, role = #{role} DisplayRole=#{Qt::DisplayRole}, EditRole=#{Qt::EditRole}, SizeHintRole=#{Qt::SizeHintRole}"
- record = localmodel.row(index.row)
+ #tag "#{self}#data at #{index.row}, role = #{role} DisplayRole=#{Qt::DisplayRole}, EditRole=#{Qt::EditRole}, SizeHintRole=#{Qt::SizeHintRole}, localmodel=#{localmodel}"
+ record = localmodel.model_row(index.row)
is_model = record.respond_to?(:model?) && record.model?
-# tag "localmodel= #{localmodel.value.inspect}, row = #{index.row}, record = #{record.inspect}"
+# tag "localmodel= #{localmodel.inspect}, row = #{index.row}, record = #{record.inspect}"
return Qt::Variant.new if record.nil?
# it is far too dangerous defaulting this
# tag "Qt::SizeHintRole = #{Qt::SizeHintRole.inspect}, to_i -> #{Qt::SizeHintRole.to_i}"
@@ -176,14 +176,14 @@ def flags index
end
def mimeTypes
- tag "mimeTypes"
+ #tag "mimeTypes"
[localmodel.mimeType]
end
def mimeData indexes
# tag "mimeData"
return nil if indexes.empty?
- localmodel.mimeData(indexes.map { |i| localmodel.row(i.row) })
+ localmodel.mimeData(indexes.map { |i| localmodel.model_row(i.row) })
end
end # module QAbstractItemModel
@@ -192,7 +192,7 @@ class QItemModel < Qt::AbstractItemModel
private
def initialize reformmodel, reformview
super(reformmodel)
-# tag "QItemModel.new(#{reformmodel}, #{reformview}"
+ # tag "QItemModel.new(#{reformmodel}, #{reformview}"
@localmodel = reformmodel # apparently.
@view = reformview
end
@@ -230,8 +230,11 @@ def self.declare_connector symbol, name = ('item' + symbol.to_s).to_sym
# the 'local' connector, that connects to the local 'model'
# and if set is applied as 'getter' to fetch the strings belonging to each object
# within the model
+ # if unset the view will attempt to make something out of the data itself
declare_connector :display, :local_connector
+ # since local_connector refers to what is displayed, these aliases
+ # make that more clear
alias :display_connector :local_connector
alias :display :local_connector
@@ -265,7 +268,7 @@ def type value = nil
end
def var2data variant
- tag "var2data, type = #{@type.inspect}"
+# tag "var2data, type = #{@type.inspect}"
# IMPORTANT: String === String results in false!!!
case @type.to_s
when 'String' then variant.to_string
@@ -276,11 +279,7 @@ def var2data variant
end
end
-# def label lab = nil
-# return @label if lab.nil?
-# @label = lab
-# end
-
+ # this is how the external key is referred
def connector value = nil, &block
return super unless value || block
super
@@ -304,18 +303,10 @@ def connectors hash = nil
connector(hash[:external]) if hash[:external] # otherwise unaffected
end
-
end # class ColumnRef
private # AbstractItemView methods
- def initialize parent, qtc
- super
-# tag "AbstractItemView.new"
- # columns are controls
-# @columns = [] So we don't really need this
- end
-
SelectionModeMap = { :none => Qt::AbstractItemView::NoSelection,
:extended => Qt::AbstractItemView::ExtendedSelection,
:single => Qt::AbstractItemView::SingleSelection,
@@ -345,20 +336,16 @@ def noSelection
end
def createColumnRef
-# tag "createColumnRef"
+# tag "createColumnRef"
ColumnRef.new(self)
end
def whenCurrentItemChanged &block
- raise 'DEPRECATED, and wrong code'
-# connect(@qtc, SIGNAL('currentItemChanged(QTreeWidgetItem*,QTreeWidgetItem*)'), self) do |current, prev|
-# rfCallBlockBack(current, prev, &block)
-# end
+ raise 'DEPRECATED'
end
def whenItemChanged &block
- raise 'DEPRECATED, and wrong code'
-# connect(@qtc, SIGNAL('itemChanged(QTreeWidgetItem*,int)'), self) { |item, colnr| rfCallBlockBack(item, colnr, &block) }
+ raise 'DEPRECATED'
end
def setLocalModel aModel
@@ -378,12 +365,12 @@ def setLocalModel aModel
end
def createQModel
-# tag "createQModel"
+# tag "createQModel"
QItemModel.new(@localmodel, self)
end
def column quickyhash = nil, &initblock
-# tag "column"
+# tag "column"
ref = createColumnRef
if quickyhash
ref.setupQuickyhash(quickyhash)
@@ -411,19 +398,24 @@ def postSetup
end
# override, assign to @localmodel, not to @model
- def addModel control, hash, &block
+ def addModel control, hash = nil, &block
control.setup hash, &block
@localmodel = control
- control.parent = self
+ #control.parent = self no such method 'parent=' .. required ?
added control
end
- # the default is :id.
+ # the default is :id. This tells the view how to retrieve the 'key'
+ # from a row.
def key_connector value = nil
return @key_connector unless value
@key_connector = value
end
+ # a model_connector gives us the local model, as part of the global model.
+ # For example calendermodel has 'weekdays' which can be used to fill a
+ #combobox. So a model_connector is an alternative for providing a local model
+ # otherwise. It does apply to $qApp.model or form.model
def model_connector value = nil
return @model_connector unless value
@model_connector = value
@@ -442,4 +434,4 @@ def updateModel aModel, propagation
end # class AbstractItemView
-end # module Reform
+end # module Reform
View
52 lib/reform/abstractlistview.rb
@@ -24,13 +24,13 @@ class AbstractListView < AbstractItemView
QAbstractListModel = QAbstractItemModel
- # this class forms the hinge between 'list' (or 'combo' etc) and any 'model' (like ruby_model/simpledata)
- # It is meant to work with Structure
+ # this class forms the hinge between 'list' (or 'combo' etc) and any 'model' (like Structure)
class QModel < Qt::AbstractListModel
include QAbstractListModel
private
def initialize reformmodel, reformview
+# tag "new QModel"
if Qt::Object === reformmodel
super(reformmodel)
else
@@ -106,24 +106,6 @@ def initialize reformmodel, reformview
=end
public
-# def itemData index
-# super.tag{|r| tag "itemData -> #{r.inspect}"}
-# end
-#
-# def modelReset
-# tag "modelReset emitted"
-# super
-# end
-
-# def reset
-# tag "reset called"
-# super
-# end
-#
-# def roleNames
-# super.tag{|r| tag "roleNames -> #{r.inspect}"}
-# end
-
end # class QModel
private # methods of AbstractListView
@@ -144,7 +126,7 @@ def col0
:connector, :connectors
def createQModel
-# tag "creating QModel"
+# tag "creating QModel, localmodel = #@localmodel"
QModel.new(@localmodel, self)
end
@@ -153,20 +135,19 @@ def createQModel
In that case it is pretty useless. Maybe handy for debugging
=end
def activated model, cid, idx, data_idx = nil
- tag "YES, 'activated'!!!, idx = #{idx}, cid=#{cid}, model=#{model},
- data_to_transmit=#{@localmodel.index2value(idx, self).inspect}, debug_track = #@debug_track"
- # BROKEN CODE ALERT: index2value is not in Model
- model.model_apply_setter cid, @localmodel.index2value(idx, col0), self #, debug_track: true
+ #tag "YES, 'activated'!!!, idx = #{idx}, cid=#{cid}, model=#{model},
+ data_to_transmit=#{@localmodel.model_index2value(idx, self).inspect}, debug_track = #@debug_track"
+ model.model_apply_setter cid, @localmodel.model_index2value(idx, col0), self #, debug_track: true
end
#override. Select the correct index in the view based on the single value
# that we connect to.
def applyModel value
-# tag "#{self}::apply_model #{value.inspect}, #{@model}, cid=#{connector.inspect}"
- if modcon = col0.connectors[:model]
+ #tag "#{self}::applyModel #{value.inspect}, #@model, cid=#{connector.inspect}"
+ if modcon = @model_connector
# change the contents first
-# tag "applying model_connector #@model_connector"
- setLocalModel @model.model_apply_getter(modcon)#.tap{|r| tag "setLocalModel(#{r.value.inspect})!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" }
+ #tag "applying model_connector #{modcon}"
+ setLocalModel @model.model_apply_getter(modcon)#.tap{|r| tag "setLocalModel(#{r.inspect})!!!!!!!!!!!!!!!!!!!!!!!!!!!!!" }
end
# it's not entirely clear when the events are triggered
# - currentIndexChanged(int)
@@ -176,13 +157,14 @@ def applyModel value
# capabilities that operate on the local model.
# Note that the setter is supposed to accept the VALUE at the given index
# and the getter receives the VALUE too.
-# tag "calling value2index(#{value}, use_as_id = #{use_as_id}"
- if i = @localmodel.value2index(value, col0)
- raise "#{@model}.value2index(#{value.inspect}) -> #{i}???, caller=#{caller.join("\n")}" unless Fixnum === i
-# tag "Calling setCurrentIndex(#{i})"
+ #tag "calling #{@localmodel}#model_value2index(#{value}, col0 = #{col0}"
+ if i = @localmodel.model_value2index(value, col0)
+ raise "#{@model}.model_value2index(#{value.inspect}) -> #{i}???, caller=#{caller.join("\n")}" unless Fixnum === i
+ #tag "Calling setCurrentIndex(#{i})"
setCurrentIndex i
else
-# STDERR.puts tr("Warning: could not locate value %s in %s") % [value.inspect, self.to_s]
+ #tag "COULD NOT LOCATE #{value.inspect}"
+ STDERR.print "Warning: could not locate value %s in %s\n" % [value.inspect, self.to_s] if $VERBOSE
setCurrentIndex 0
end
end # def apply_model
@@ -200,4 +182,4 @@ def check_propagation_change propagation, cid
public # methods of AbstractListView
end # class AbstractListView
-end
+end
View
25 lib/reform/app.rb
@@ -35,7 +35,9 @@ def trace onoff = true
end
# this is the ugly way to make 'with' in ruby. CURRENT STATE: unused
- # also this will not work 'with x do attrib = 3'
+ # also this will not work: 'with x do attrib = 3'
+ # It should then still be: 'with x do self.attrib = 3'. Which is a lot more
+ # complicated than 'x.attrib = 3'.
def with arg, &block
arg.instance_eval(&block)
end
@@ -409,7 +411,7 @@ def registerControlClassProxy_i name, thePath
reform_class = instantiator[:reform_class]
options = instantiator[:options]
qt_implementor_class = instantiator[:qt_implementor_class]
- raise ArgumentError, "Bad hash #{quicky} passed to instantiator '#{name}'" unless quicky == nil || Hash === quicky
+ raise ArgumentError, "Bad param #{quicky.inspect} passed to instantiator '#{name}'" unless quicky == nil || Hash === quicky
# tag "quicky hash = #{quicky.inspect}"
# It's important to use parent_qtc_to_use, since it must be a true widget.
# Normally, 'qparent' would be '@qtc' itself
@@ -494,19 +496,18 @@ module ModelContext
# shortcut. You can then say simple_data 'hallo', 'world'
def simple_data *val
- STDERR.puts "DEPRECATED, use 'struct' iso simple_data/simpledata"
- ruby_model value: if val.length == 1 then val[0] else val end
+ raise "DEPRECATED, use 'struct' iso simple_data/simpledata"
end
- alias :simpledata :simple_data
+ # alias :simpledata :simple_data
def struct *val, &block
-# tag "struct(#{val.inspect})"
+ #tag "struct(#{val.inspect})"
if block
# tag "using block"
addModel(Structure.new.build(&block))
else
- structure value: if val.length == 1 then val[0] else val end
+ addModel(Structure.new(if val.length == 1 && Hash === val[0] then val[0] else val end))
end
end
@@ -885,8 +886,7 @@ def define quickyhash = nil, &block
# shortcut. You can then say simple_data 'hallo', 'world'
def simple_data *val
- STDERR.puts "simple_data is DEPRECATED, use 'struct'"
- ruby_model value: if val.length == 1 then val[0] else val end
+ raise "simple_data is DEPRECATED, use 'struct'"
end
alias :simpledata :simple_data
@@ -910,13 +910,12 @@ def font f = nil, &block
end
end
- def struct hash, &block
-# tag "struct"
- raise 'struct now requires a hash in all cases' unless Hash === hash
+ def struct *val, &block
+# tag "struct"
if block
addModel(Structure.new.build(&block))
else
- structure val
+ addModel(Structure.new(if val.length == 1 && Hash === val[0] then val[0] else val end))
end
end
View
2  lib/reform/contrib/widgets/calendarcolorcombo.rb
@@ -23,7 +23,7 @@ module Reform
class CalendarComboBox < ComboBox
def initialize parent, qtc
super
- model Qt::red => tr('Red'),
+ struct Qt::red => tr('Red'),
Qt::blue => tr('Blue'),
Qt::black => tr('Black'),
Qt::magenta => tr('Magenta')
View
38 lib/reform/control.rb
@@ -53,18 +53,6 @@ class DynamicPoint < DynamicAttribute; end
#
class Control < Qt::Object
-# class Animation < Control
-#
-# private # Animation methods
-# # our parent is the parent of the DynamicAttribute so it could be a GraphicsItem.
-# # Which is a Qt::Object, even if Qt::GraphicsItem is not
-# def initialize attrib
-# # tag "Assigned attrib and propertyname '#{@qtc.propertyName}'"
-# end
-#
-# end
-
-
private # Control methods
# create a new Control, using the frame as 'owner', and qtc as the wrapped Qt::Widget
@@ -365,6 +353,7 @@ def connector value = nil, &block
end
end
+ #alias :connect :connector STUPID: connect already exists !
def propagateModel aModel, propagation
# tag "#{self}#propagateModel(#{aModel}, #{propagation.inspect}"
# we keep clear of children with their own 'effective' models, which means that the
@@ -382,11 +371,15 @@ def propagateModel aModel, propagation
# end
end
- # data is the connector applied on the model. This is only called if we 'want data',
- # if we have a connector,
- # if the model has a getter for it, and
- # if the connector is in the 'changed' list of the propagation
+ # data is the result of applying :connector on the model that was propagated to us
+ # This is only called if
+ # - we 'want data',
+ # - we have a connector,
+ # - the model has a getter for it, and
+ # - the connector is in the 'changed' list of the propagation
def applyModel data
+# tag "applyModel IGNORED!!"
+ STDERR.print "WARNING: applyModel is ignored" if $VERBOSE
end
protected # Control methods
@@ -606,8 +599,10 @@ def addState control, quickyhash = nil, &block
end
# :nodoc: called by +add+ if the control was a model
- def addModel control, hash, &block
+ def addModel control, hash = nil, &block
# @model ||= nil
+ # setup may use 'parent'
+ control.parent = self
control.setup hash, &block
# want_data! this is a toplevel call. There is no need to do this.
# and it wrong for comboboxes or lists that are assigned local data.
@@ -617,7 +612,6 @@ def addModel control, hash, &block
@model = control
# @model.addObserver(self) if @model
# end
- control.parent = self
added control
end
@@ -811,12 +805,15 @@ def updateModel aModel, propagation
end
if aModel.respond_to?(:model?) && aModel.model?
# tag "apply getter '#{cid}' to aModel"
+ STDERR.print "#{self}::updMod, get data by application of #{cid}, do_apply=#{do_apply}" if propagation.debug_track?
data = aModel.model_apply_getter(cid)
elsif Proc === cid
# tag "apply getter '#{cid}' to aModel"
+ STDERR.print "#{self}::updMod, get data by application of proc, do_apply=#{do_apply}" if propagation.debug_track?
data = cid.call(aModel)
else
# tag "take aModel as is"
+ STDERR.print "#{self}::updMod, get data 'as is', do_apply=#{do_apply}" if propagation.debug_track?
data = aModel
end
# for simple fields the connected model is the container.
@@ -881,11 +878,6 @@ def find klass = nil, name = nil, &block
alias :findChildren :find
- # can be used as a bool too. For comboboxes and tables this may be set, while effectiveModel is nil.
-# def model
-# instance_variable_defined?(:@model) ? @model : nil
-# end
-
def geometry=(*value)
@qtc.geometry = *value
end
View
224 lib/reform/examples/01_widgets/calendar.rb
@@ -1,6 +1,6 @@
#!/usr/bin/ruby
-# Copyright (c) 2010 Eugene Brazwick
+# Copyright (c) 2010-2011 Eugene Brazwick
require 'reform/app'
@@ -35,65 +35,66 @@ class Const < Qt::Object
title tr('Preview')
calendarwidget {
name :calendarWidget
-# minimumDate Const::MinimumDate # dd-mm-yy(yy)? or yyyy.mm.dd or mm[^-]dd[^-]yy(yy)?
-# maximumDate Const::MaximumDate # or dd.MMM.yy(yy)? or MMM.dd.yy(yy)?
-# # or yy(yy)?.MMM.dd
- # or split in three triple integers y m d
- # or int/string triples dMy yMd Mdy as long y > 31
-# gridVisible true
-# whenMonthChanged { } # reformatCalendarPage } # FIXME ??? cannot exist
- makecenter # center it in containerwidget, with a stretchy space around it.
+ # we connect to the calendar model, 'as is'
+ connector :self
}
} # groupbox
# general options group box UR
groupbox { # generalOptionsGroupBox
layoutpos 1 # by default it goes down, we want to add a column here
title tr('General Options')
- combobox { # localeCombo
- # use Qt locale languagelist, and for each locale add the
- # countriesForLanguage(lang).
- # the currentlocale must be made the default value and thus function
- # as the 'connecting' modelpart, we should simply set calendar.language_and_country
- name :locale
- locale_model
- labeltext tr('&Locale') # quicky label association, becomes a 'buddy'
- }
- combobox { # firstDayCombo
- # or datasource({k=>v,...}) or datasource Hash[k=>v,...]
- model CalendarModel::WeekDaysFromSun2Sat
- name :firstDayOfWeek # should return a Qt::XXXday
- }
- # as demo, I write it in full, but could place 'label' in combobox here as well
- label { # firstDayLabel
- text tr('Wee&k starts on:')
- buddy :firstDayOfWeek
- }
- combobox { # selectionModeCombo
- model CalendarWidget::PossibleSelections
- labeltext tr('&Selection mode:')
- }
- hbox { # checkBoxLayout
- checkbox { # gridCheckBox
- text tr('&Grid')
- name :gridVisible?
- }
- spacer stretch: 1 # stretchable open space in between
- checkbox { # navigationCheckBox
- text tr('&Navigation Bar')
- name :navigationBarVisible?
- }
- } # hbox
- combobox {# horizontalHeaderCombo
- name :horizontalHeaderFormat
- model CalendarWidget::PossibleHorizontalHeaderOptions
-# currentIndex 1 # this alters the model on initialization, even!!
- labeltext tr('&Horizontal header:')
- }
- combobox { # verticalHeaderCombo
- name :verticalHeaderFormat
- model CalendarWidget::PossibleVerticalHeaderOptions
- labeltext tr('&Vertical header:')
- }
+ vbox {
+ formlayout {
+ combobox { # localeCombo
+ # use Qt locale languagelist, and for each locale add the
+ # countriesForLanguage(lang).
+ # the currentlocale must be made the default value and thus function
+ locale_model
+ connector :locale
+ labeltext tr('&Locale') # quicky label association, becomes a 'buddy'
+ }
+ combobox { # firstDayCombo
+ model_connector [:model_root, :weekdays]
+ name :firstDayOfWeek # 'needed' for buddy
+ connector :firstDayOfWeek
+ }
+ # as demo, I write it in full, but could place 'label' in combobox here as well
+ label { # firstDayLabel
+ text tr('Wee&k starts on:')
+ buddy :firstDayOfWeek
+ }
+ combobox { # selectionModeCombo
+ # I could have said: model_connector [:model_root, :possibleSelections]
+ struct Reform::CalendarModel::PossibleSelections
+ labeltext tr('&Selection mode:')
+ connector :selectionMode
+ }
+ }
+ hbox { # checkBoxLayout
+ checkbox { # gridCheckBox
+ text tr('&Grid')
+ connector :gridVisible?
+ }
+ spacer stretch: 1 # stretchable open space in between
+ checkbox { # navigationCheckBox
+ text tr('&Navigation Bar')
+ connector :navigationBarVisible?
+ }
+ } # hbox
+ formlayout {
+ combobox {# horizontalHeaderCombo
+ struct Reform::CalendarModel::PossibleHorizontalHeaderOptions
+ connector :horizontalHeaderFormat
+ # currentIndex 1 # this alters the model on initialization, even!!
+ labeltext tr('&Horizontal header:')
+ }
+ combobox { # verticalHeaderCombo
+ struct Reform::CalendarModel::PossibleVerticalHeaderOptions
+ connector :verticalHeaderFormat
+ labeltext tr('&Vertical header:')
+ }
+ } # formlayout
+ } # vbox
} # generalOptionsGroupBox
# dates group box BL
@@ -102,26 +103,28 @@ class Const < Qt::Object
date { # minimumDateEdit
displayFormat 'MMM d yyyy'
dateRange Const::MinimumDate, Const::MaximumDate
- name :minimumDate
+ connector :minimumDate
labeltext tr('&Minimum Date:')
}
date { # currentDateEdit
displayFormat 'MMM d yyyy'
dateRange Const::MinimumDate, Const::MaximumDate
- name :selectedDate
+ connector :selectedDate
labeltext tr('&Current Date:')
}
date { # maximumDateEdit
displayFormat 'MMM d yyyy'
dateRange Const::MinimumDate, Const::MaximumDate
- name :maximumDate
+ connector :maximumDate
labeltext tr('Ma&ximum Date:')
}
} # dateGroupBox
# textformats group box BR
groupbox { # TextFormatsGroupBox
title tr('Text Formats')
- calendarcolorcombo { # contrib widget
+ vbox {
+ formlayout {
+ calendarcolorcombo { # contrib widget
# it should be possible to make such a thing
# within the application here.
=begin
@@ -138,41 +141,41 @@ class Const < Qt::Object
proper context. Maybe we should call it a 'macro'.
We 'can' a 'control' so 'can_control'. But it looks like a question...
=end
- currentKey Qt::black
- labeltext tr('&Weekday color:')
- whenActivated do |data, idx|
- format = Qt::TextCharFormat.new
- format.foreground = Qt::Brush.new(data) # .to_color
- calendarWidget.setWeekdayTextFormat(Qt::Monday, format);
- calendarWidget.setWeekdayTextFormat(Qt::Tuesday, format);
- calendarWidget.setWeekdayTextFormat(Qt::Wednesday, format);
- calendarWidget.setWeekdayTextFormat(Qt::Thursday, format);
- calendarWidget.setWeekdayTextFormat(Qt::Friday, format);
- end
- }
- combobox { # weekendColorCombo
- model Const::PossibleColors
- currentKey Qt::red
- labeltext tr('Week&end color:')
- whenActivated do |data, idx|
- (format = Qt::TextCharFormat.new).foreground = Qt::Brush.new(data)
- calendarWidget.setWeekdayTextFormat Qt::Saturday, format
- calendarWidget.setWeekdayTextFormat Qt::Sunday, format
- end
- }
- combobox {
- model tr('Bold'), tr('Italic'), tr('Green'), tr('Plain')
- labeltext tr('&Header text:')
- whenActivated do |data, idx|
- format = Qt::TextCharFormat.new
- case idx
- when 0 then format.fontWeight = Qt::Font::Bold
- when 1 then format.fontItalic = true
- when 2 then format.foreground = Qt::Brush.new(Qt::green)
- end
- calendarWidget.headerTextFormat format
- end
- }
+ currentIndex 2
+ labeltext tr('&Weekday color:')
+ whenActivated do |data, key|
+ format = Qt::TextCharFormat.new
+ format.foreground = Qt::Brush.new(data) # .to_color
+ calendarWidget.setWeekdayTextFormat(Qt::Monday, format);
+ calendarWidget.setWeekdayTextFormat(Qt::Tuesday, format);
+ calendarWidget.setWeekdayTextFormat(Qt::Wednesday, format);
+ calendarWidget.setWeekdayTextFormat(Qt::Thursday, format);
+ calendarWidget.setWeekdayTextFormat(Qt::Friday, format);
+ end
+ }
+ combobox { # weekendColorCombo
+ struct Const::PossibleColors
+ currentIndex 0
+ labeltext tr('Week&end color:')
+ whenActivated do |data, key|
+ (format = Qt::TextCharFormat.new).foreground = Qt::Brush.new(key)
+ calendarWidget.setWeekdayTextFormat Qt::Saturday, format
+ calendarWidget.setWeekdayTextFormat Qt::Sunday, format
+ end
+ }
+ combobox {
+ struct tr('Bold'), tr('Italic'), tr('Green'), tr('Plain')
+ labeltext tr('&Header text:')
+ whenActivated do |data, key|
+ format = Qt::TextCharFormat.new
+ case idx
+ when 0 then format.fontWeight = Qt::Font::Bold
+ when 1 then format.fontItalic = true
+ when 2 then format.foreground = Qt::Brush.new(Qt::green)
+ end
+ calendarWidget.headerTextFormat format
+ end
+ }
=begin
these two are problematic.
Since they are NOT part of Qt::CalendarWidget it seems ugly to still
@@ -180,24 +183,21 @@ class Const < Qt::Object
solution 1) extend both model + widget with subclasses, maybe even in this form.
solution 2) just ad hoc code it, similar to the example
=end
- hbox { # checkBoxLayout
- checkbox {
- name :firstFridayCheckbox
- connector false
- text tr('&First Friday in blue')
- whenClicked { |checked| updateModel(@model) }
- }
- spacer stretch: 1
- checkbox {
- name :mayFirstCheckbox
- connector false
- text tr('May &1 in red')
- whenClicked do |checked|
-# tag "whenClicked, self=#{self}, calling whenCon"
- updateModel(@model)
- end
- }
- } # hbox
+ } # formlayout
+ hbox { # checkBoxLayout
+ checkbox {
+ name :firstFridayCheckbox
+ connector false
+ text tr('&First Friday in blue')
+ }
+ spacer stretch: 1
+ checkbox {
+ name :mayFirstCheckbox
+ connector false
+ text tr('May &1 in red')
+ }
+ } # hbox
+ } # vbox
} # textFormatsGroupBox
} # layout
# tag "setting whenConnected form callback"
@@ -220,4 +220,4 @@ class Const < Qt::Object
end
end
} # form
-} # app
+} # app
View
7 lib/reform/examples/01_widgets/calendar_prelim_a.rb
@@ -1,6 +1,6 @@
#!/usr/bin/ruby -w
-# Copyright (c) 2010 Eugene Brazwick
+# Copyright (c) 2010-2011 Eugene Brazwick
require 'reform/app'
@@ -10,6 +10,7 @@ class Const < Qt::Object
end
Reform::app {
+# using calendarwidget which is in lib/reform/widgets
calendarwidget {
name :calendarWidget
# this silently ignores illegal inputs:
@@ -19,8 +20,6 @@ class Const < Qt::Object
# or split in three triple integers y m d
# or int/string triples dMy yMd Mdy as long y > 31
gridVisible true
- # would it be better if it were named 'whenMonthChanged'
- # since that's what a page is, basically.
whenMonthChanged { }
}
-}
+}
View
5 lib/reform/examples/01_widgets/calendar_prelim_b.rb
@@ -24,6 +24,9 @@ class Const < Qt::Object
whenMonthChanged { }
makecenter
}
+ combobox {
+ locale_model
+ }
# FIXME, ugly
# proposed: row[0] { minimumHeight value }
# so a method 'row' that creates a dummy object with '[]' as method, accepting
@@ -32,4 +35,4 @@ class Const < Qt::Object
# setRowMinimumHeight(0, @containing_form.calendarWidget.sizeHint.height)
# setColumnMinimumWidth(0, @containing_form.calendarWidget.sizeHint.width)
}
-}
+}
View
6 lib/reform/examples/01_widgets/calendar_prelim_c.rb
@@ -10,10 +10,8 @@ class Const < Qt::Object
end
Reform::app {
-# groupbox {
# this setup is a failure for some reason. At this point calendar.rb got into the groove
# however. What's the use of groupbox???
- # leaving it out shows that makecenter works even on its own....
calendarwidget {
name :calendarWidget
# this silently ignores illegal inputs:
@@ -24,7 +22,5 @@ class Const < Qt::Object
# or int/string triples dMy yMd Mdy as long y > 31
gridVisible true
whenMonthChanged { }
- makecenter # this induces a gridlayout!
}
-# }
-}
+}
View
79 lib/reform/examples/01_widgets/calendar_prelim_d.rb
@@ -6,33 +6,35 @@
Reform::app {
groupbox { # generalOptionsGroupBox
title tr('General Options')
- size 480, 300
-# formlayout { # outerLayout
- combobox { # localeCombo
- # use Qt locale languagelist, and for each locale add the
- # countriesForLanguage(lang).
- # the currentlocale must be made the default value and thus function
- # as the 'connecting' modelpart, we should simply set calendar.language_and_country
- name :language_and_country
- model ['something']
- labeltext tr('&Locale') # quicky label association, becomes a 'buddy'
+ sizeHint 480, 300
+ grid {
+ formlayout {
+ combobox { # localeCombo
+ # use Qt locale languagelist, and for each locale add the
+ # countriesForLanguage(lang).
+ # the currentlocale must be made the default value and thus function
+ # as the 'connecting' modelpart, we should simply set calendar.language_and_country
+ connector :language_and_country
+ struct 'just', 'a', 'test', 'array', 'of', 'data'
+ labeltext tr('&Locale') # quicky label association, becomes a 'buddy'
+ }
+ combobox { # firstDayCombo
+ # or datasource({k=>v,...}) or datasource Hash[k=>v,...]
+ struct Reform::CalendarModel::WeekDaysFromSun2Sat
+ connector :weekstart # should return a Qt::XXXday
+ name :weekstart # to attach the label to
+ }
+ # as demo, I write it in full, but could place 'label' in combobox here as well
+ label { # firstDayLabel
+ text tr('Wee&k starts on:')
+ buddy :weekstart
+ }
+ combobox { # selectionModeCombo
+ struct Reform::CalendarWidget::PossibleSelections
+ labeltext tr('&Selection mode:')
+ }
}
- combobox { # firstDayCombo
- # or datasource({k=>v,...}) or datasource Hash[k=>v,...]
- model CalendarModel::WeekDaysFromSun2Sat
- name :weekstart # should return a Qt::XXXday
- }
- # as demo, I write it in full, but could place 'label' in combobox here as well
- label { # firstDayLabel
- text tr('Wee&k starts on:')
- buddy :weekstart
- }
- combobox { # selectionModeCombo
- model CalendarWidget::PossibleSelections
- labeltext tr('&Selection mode:')
- }
- hbox { # checkBoxLayout
-# FIXME: these are missing !!!! hbox fails here, checkbox works fine!!!
+ hbox { # checkBoxLayout
checkbox { # gridCheckBox
text tr('&Grid')
name :gridVisible?
@@ -43,16 +45,19 @@
checked true
}
} # hbox
- combobox {# horizontalHeaderCombo
- name :horizontalHeaderOption
- model CalendarWidget::PossibleHorizontalHeaderOptions
- currentIndex 1 # this alters the model on initialization, even!!
- labeltext tr('&Horizontal header:')
+ formlayout {
+ combobox {# horizontalHeaderCombo
+ connector :horizontalHeaderOption
+ struct Reform::CalendarWidget::PossibleHorizontalHeaderOptions
+ currentIndex 1 # this alters the model on initialization, even!!
+ labeltext tr('&Horizontal header:')
+ }
+ combobox { # verticalHeaderCombo
+ struct Reform::CalendarWidget::PossibleVerticalHeaderOptions
+ labeltext tr('&Vertical header:')
+ }
}
- combobox { # verticalHeaderCombo
- model CalendarWidget::PossibleVerticalHeaderOptions
- labeltext tr('&Vertical header:')
- }
-# } # formlayout
+ } # grid
} # generalOptionsGroupBox
-}
+}
+
View
27 lib/reform/model.rb
@@ -522,6 +522,7 @@ def commit_work
@root.model_commit_work @altered_owners
end
+ # called from commit
def propagate_changes
# tag "#{self}.COMMIT WORK, @@tran= #{@@transaction}, aborted=#@aborted, sender = #@sender"
# NOTE: tr() only works on Qt::Object...
@@ -715,7 +716,9 @@ def self.included mod
# this saves a lot of duplication. The block is passed the transaction.
def model_pickup_tran sender = nil
+# tag "model_pickup_tran(#{sender})"
if tran = Transaction.transaction
+# tag "already exists, ignoring sender"
yield(tran)
else
Transaction.new(model_root, sender) do |tr|
@@ -740,11 +743,12 @@ def model_propagateChange propagation
# (@observers ||= nil) and @observers.each do |o|
raise 'ouch' unless model_root == self
# root = self # model_root
-# tag "model_propagateChange, self=#{self}, parent = #{@model_parent}, root = #{model_root}"
- if p = model_parent
+# tag "model_propagateChange, self=#{self}, parent = #{@parent}, root = #{model_root}"
+ if p = parent
p.updateModel self, propagation
else
- STDERR.puts "Warning: propagateChange is ignored if your model (#{self}) has no rootparent!!" if $VERBOSE
+# tag "ALERT, no parent..."
+ STDERR.print "Warning: propagateChange is ignored if your model (#{self}) has no parent!!\n" if $VERBOSE
end
# end
end
@@ -869,7 +873,7 @@ def model_setupQuickyhash hash
# Control compat
def addTo parent, hash, &block
# tag "#{self}::addTo"
- model_parent.addModel self, hash, &block
+ parent.addModel self, hash, &block
end
# Control compat
@@ -924,7 +928,7 @@ def empty?
# grab a row, can return a Model or simple data like Numeric, String etc.
# It should never return an Array or Hash or a complex instance that is not Model.
def model_row(numeric_idx)
- raise "#{self.class}#row is not implemented"
+ raise "#{self.class}#model_row is not implemented"
end
# iterate the rows
@@ -952,6 +956,7 @@ def model_value
# try to retrieve key from value by looking to a field called 'id'
# Unfortunately sometimes the value is not a model but a raw hash.
+ # The proces can be tweaked by setting up a key_connector.
def model_value2key value, view # or widget
# note that Strings have to_i as well.
case value
@@ -1040,11 +1045,11 @@ def model_mimeData records
end
def model_value2index value, view
- raise 'NIY: model_value2index'
+ raise "NIY: #{self.class}#model_value2index"
end
def model_index2value numeric_idx, view
- raise 'NIY: model_index2value'
+ raise "NIY: #{self.class}#model_index2value"
end
# callback, called when the transaction is just started and no work has been done yet
@@ -1079,14 +1084,6 @@ def initialize parent = nil, qtc = nil
@model_parent = parent
end
-# def length # not likely
-# @qtc.rowCount # and rowCount requires an index too...
-# end
-
- # Model already has this but something strange is going on!!
-# def addTo parent, hash, &block
-# parent.addModel self, hash, &block
-# end
end
end # module Reform
View
260 lib/reform/models/calendar_model.rb
@@ -1,9 +1,10 @@
-# Copyright (c) 2010 Eugene Brazwick
+# Copyright (c) 2010-2011 Eugene Brazwick
module Reform
- require_relative '../model'
+ require 'reform/model'
+ require 'Qt'
=begin rdoc
@@ -50,130 +51,167 @@ class CalendarModel < AbstractModel
# based on first three letters of locale converted monthnames.
private
- def initialize parent, qtc
- super()
- @minimumDate = CalendarModel::to_date 'Sep', 14, 1752 # start of modern calendar
- # (in the US!!!! the rest of the world had it two centuries sooner)
- @maximumDate = CalendarModel::to_date 'Dec', 31, 2999
- @selectionMode = Qt::CalendarWidget::SingleSelection
- @horizontalHeaderFormat = Qt::CalendarWidget::ShortDayNames
- @verticalHeaderFormat = Qt::CalendarWidget::ISOWeekNumbers
- @navigationBarVisible = true
- @gridVisible = false
- @firstDayOfWeek = Qt::Sunday
- @selectedDate = nil # Qt::Date.new (dangerous, let's say 'nil' represent Qt.Date.new)
- @locale = ENV['LANG'].sub(/\..*/, '') || 'C'
-# @selectedDate = CalendarModel::to_date
+ def initialize parent, qtc
+ super()
+ @minimumDate = CalendarModel::to_date 'Sep', 14, 1752 # start of modern calendar
+ # (in the US!!!! the rest of the world had it two centuries sooner)
+ @maximumDate = CalendarModel::to_date 'Dec', 31, 2999
+ @selectionMode = Qt::CalendarWidget::SingleSelection
+ @horizontalHeaderFormat = Qt::CalendarWidget::ShortDayNames
+ @verticalHeaderFormat = Qt::CalendarWidget::ISOWeekNumbers
+ @navigationBarVisible = true
+ @gridVisible = false
+ @firstDayOfWeek = Qt::Sunday
+ @selectedDate = nil # Qt::Date.new (dangerous, let's say 'nil' represent Qt.Date.new)
+ @locale = ENV['LANG'].sub(/\..*/, '') || 'C'
+ # @selectedDate = CalendarModel::to_date
=begin HOLES
1) locale
2) colors
3) headerformat
=end
- end
-
- def self.calcmonth str
- str = str.upcase
- for m in (1..12)
- Qt::Date::shortMonthName(m).upcase == str and return m
end
- for m in (1..12)
- Qt::Date::longMonthName(m).upcase == str and return m
+
+ def self.calcmonth str
+ str = str.upcase
+ for m in (1..12)
+ Qt::Date::shortMonthName(m).upcase == str and return m
+ end
+ for m in (1..12)
+ Qt::Date::longMonthName(m).upcase == str and return m
+ end
+ raise ArgumentError, tr('Unable to parse monthname') + " '#{str}'"
end
- raise ArgumentError, tr('Unable to parse monthname') + " '#{str}'"
- end
public
- dynamic_accessor :minimumDate, :maximumDate, :selectionMode,
- :horizontalHeaderFormat, :verticalHeaderFormat,
- :firstDayOfWeek, :selectedDate, :locale
+ model_dynamic_accessor :minimumDate, :maximumDate, :selectionMode,
+ :horizontalHeaderFormat, :verticalHeaderFormat,
+ :firstDayOfWeek, :selectedDate, :locale
+
+ model_dynamic_bool :navigationBarVisible, :gridVisible
+
+ # convert arguments to a Qt::Date (not a ruby Time)
+ # Possibly understood arguments:
+ # string matching dd-mm-yy(yy)? or yyyy.mm.dd or mm[^-]dd[^-]yy(yy)?
+ # string matching dd.MMM.yy(yy)? or MMM.dd.yy(yy)?
+ # string matching yy(yy)?.MMM.dd
+ # split in three triple integers y m d
+ # int/string triples dMy yMd Mdy as long y > 31
+ #
+ # This method raises ArgumentError on any bad arguments or invalid date
+ # results.
+ #
+ # Any month string must match the Qt shortname for that month, in the active
+ # locale. I assume they are always 3 long.
+ # However if the string does not match any shortname then it will be matched with the longname
+ # automatically. This match is case insensitive.
+ #
+ # So '01-01-10' is understood, so is, '2010 Februari 2', or 1,1,10, or
+ # 2, 'feb', 2010
+ # And '04/30/2011' is the same as '30-04-2011'
+ def self.to_date *arg
+ # tag "to_date #{arg.inspect}"
+ l = arg.length
+ raise ArgumentError, tr("invalid date") + " '#{arg.inspect}'" if l != 1 && l != 3
+ if l == 1
+ case date = arg[0].to_str
+ when /(\d{1,2})-(\d{1,2})-(\d\d(\d\d)?)/
+ # tag "continental, $1=#$1, $2=#$2,$3=#$3"
+ d, m, y = $1, $2, $3
+ # tag "dmy= #{d}, #{m}, #{y}"
+ when /(?<month>\d{1,2})(?<sep>\W)(?<day>\d{1,2})\k<sep>(?<year>\d\d(\d\d)?)/
+ # tag "american, '#{$1}' '#{$2}' '#{$3}' '#{$4}' '#{$5}'"
+ # tag "MATCHDATA: #{$~.inspect}"
+ d, m, y = $~[:day], $~[:month], $~[:year]
+ when /(?<year>\d{4})(?<sep>\W)(?<month>\d{1,2})\k<sep>(?<day>\d{1,2})/
+ # tag "sortable"
+ d, m, y = $4, $3, $1
+ when /(?<day>\d{1,2})(?<sep>\W)(?<month>\p{Alpha}{3,})\k<sep>(?<year>\d\d(\d\d)?)/
+ # tag "continental, monthname"
+ d, m, y = $1, calcmonth($3), $4
+ when /(?<month>\p{Alpha}{3,})(?<sep>\W)(?<day>\d{1,2})\k<sep>(?<year>\d\d(\d\d)?)/
+ # tag "american, monthname"
+ d, m, y = $3, calcmonth($1), $4
+ when /(?<year>\d\d(\d\d)?)(?<sep>\W)(?<month>\p{Alpha}{3,})\k<sep>(?<day>\d{1,2})/
+ # tag "standard, monthname, Match=#{$~.inspect}"
+ d, m, y = $~[:day], calcmonth($~[:month]), $~[:year]
+ else
+ raise ArgumentError, tr("invalid date") + " '#{date}'"
+ end
+ else # 3 integers then
+ y, m, d = arg
+ # tag "y,m,d=#{y},#{m},#{d}"
+ # unless...
+ if y.respond_to?(:to_str)
+ m, d, y = calcmonth(y.to_str), m, d
+ elsif m.respond_to?(:to_str)
+ if y > 31
+ m = calcmonth(m)
+ else
+ d, m, y = y, calcmonth(m), d
+ end
+ end
+ end
+ d, m, y = d.to_i, m.to_i, y.to_i
+ # tag "m = #{m}, d = #{d}, y = #{y}"
+ raise ArgumentError, tr("invalid month") + " '#{m}'" unless (1..12) === m
+ raise ArgumentError, tr("invalid day") + " '#{d}'" unless (1..31) === d
+ # these should be shifted as the years pass, but I'm a bit lazy
+ y = y < 60 ? 2000 + y : 1900 + y if y < 100
+ # Time.local(y, m, d)
+ Qt::Date.new(y, m, d).tap do |dat|
+ unless dat.valid?
+ raise ArgumentError, tr("invalid date") + (" '%02d-%02d-%04d'" % [d,m,y])
+ end
+ end
+ end # def to_date
+
+ # translated days of the week where 0 is Sunday
+ WeekDaysFromSun2Sat = {
+ Qt::Sunday=>tr('Sunday'), Qt::Monday=>tr('Monday'),
+ Qt::Tuesday=>tr('Tuesday'), Qt::Wednesday=>tr('Wednesday'),
+ Qt::Thursday=>tr('Thursday'), Qt::Friday=>tr('Friday'),
+ Qt::Saturday=>tr('Saturday') }
+
+ PossibleSelections = { Qt::CalendarWidget::SingleSelection=>tr("Single selection"), # DEFAULT
+ Qt::CalendarWidget::NoSelection=>tr("None") }
+
+ PossibleHorizontalHeaderOptions = {
+ Qt::CalendarWidget::SingleLetterDayNames=>tr('Single letter day names'),
+ Qt::CalendarWidget::ShortDayNames=>tr('Short day names'), # DEFAULT
+ Qt::CalendarWidget::NoHorizontalHeader=>tr('None')
+ }
+
+ PossibleVerticalHeaderOptions = {
+ Qt::CalendarWidget::ISOWeekNumbers=>tr('ISO week numbers'), # DEFAULT
+ Qt::CalendarWidget::NoVerticalHeader=>tr('None')
+ }
+
+ def weekdaysFromSun2Sat
+ require_relative 'structure'
+ @weekdays ||= Structure.new WeekDaysFromSun2Sat
+ end
- dynamic_bool :navigationBarVisible, :gridVisible
+ alias :weekdays :weekdaysFromSun2Sat
-=begin rdoc
- convert arguments to a Qt::Date (not a ruby Time)
- Possibly understood arguments:
- dd-mm-yy(yy)? or yyyy.mm.dd or mm[^-]dd[^-]yy(yy)?
- dd.MMM.yy(yy)? or MMM.dd.yy(yy)?
- yy(yy)?.MMM.dd
- split in three triple integers y m d
- int/string triples dMy yMd Mdy as long y > 31
-
- This method raises ArgumentError on any bad arguments or invalid date
- results.
-
- Any month string must match the Qt shortname for that month, in the active
- locale. I assume they are always 3 long.
- However if the string does not match any shortname then it will be matched with the longname
- automatically. This match is case insensitive.
- So 1-1-10 is understood, so is, '2010 Februari 2'
-=end
- def self.to_date *arg
-# tag "to_date #{arg.inspect}"
- l = arg.length
- raise ArgumentError, tr("invalid date") + " '#{arg.inspect}'" if l != 1 && l != 3
- if l == 1
- case date = arg[0].to_str
- when /(\d{1,2})-(\d{1,2})-(\d\d(\d\d)?)/
-# tag "continental, $1=#$1, $2=#$2,$3=#$3"
- d, m, y = $1, $2, $3
-# tag "dmy= #{d}, #{m}, #{y}"
- when /(?<month>\d{1,2})(?<sep>\W)(?<day>\d{1,2})\k<sep>(?<year>\d\d(\d\d)?)/
-# tag "american, '#{$1}' '#{$2}' '#{$3}' '#{$4}' '#{$5}'"
-# tag "MATCHDATA: #{$~.inspect}"
- d, m, y = $~[:day], $~[:month], $~[:year]
- when /(?<year>\d{4})(?<sep>\W)(?<month>\d{1,2})\k<sep>(?<day>\d{1,2})/
-# tag "sortable"
- d, m, y = $4, $3, $1
- when /(?<day>\d{1,2})(?<sep>\W)(?<month>\p{Alpha}{3,})\k<sep>(?<year>\d\d(\d\d)?)/
-# tag "continental, monthname"
- d, m, y = $1, calcmonth($3), $4
- when /(?<month>\p{Alpha}{3,})(?<sep>\W)(?<day>\d{1,2})\k<sep>(?<year>\d\d(\d\d)?)/
-# tag "american, monthname"
- d, m, y = $3, calcmonth($1), $4
- when /(?<year>\d\d(\d\d)?)(?<sep>\W)(?<month>\p{Alpha}{3,})\k<sep>(?<day>\d{1,2})/
-# tag "standard, monthname, Match=#{$~.inspect}"
- d, m, y = $~[:day], calcmonth($~[:month]), $~[:year]
- else
- raise ArgumentError, tr("invalid date") + " '#{date}'"
- end
- else # 3 integers then
- y, m, d = arg
-# tag "y,m,d=#{y},#{m},#{d}"
- # unless...
- if y.respond_to?(:to_str)
- m, d, y = calcmonth(y.to_str), m, d
- elsif m.respond_to?(:to_str)
- if y > 31
- m = calcmonth(m)
- else
- d, m, y = y, calcmonth(m), d
- end
- end
- end
- d, m, y = d.to_i, m.to_i, y.to_i
-# tag "m = #{m}, d = #{d}, y = #{y}"
- raise ArgumentError, tr("invalid month") + " '#{m}'" unless (1..12) === m
- raise ArgumentError, tr("invalid day") + " '#{d}'" unless (1..31) === d
- # these should be shifted as the years pass, but I'm a bit lazy
- y = y < 60 ? 2000 + y : 1900 + y if y < 100
-# Time.local(y, m, d)
- Qt::Date.new(y, m, d).tap do |dat|
- unless dat.valid?
- raise ArgumentError, tr("invalid date") + (" '%02d-%02d-%04d'" % [d,m,y])
- end
- end
- end # def to_date
+ # Returns a model with the possible selections
+ def possibleSelections
+ require_relative 'structure'
+ @possibleSelections ||= Structure.new PossibleSelections
+ end
- # translated days of the week where 0 is Sunday
- WeekDaysFromSun2Sat = {
- Qt::Sunday=>tr('Sunday'), Qt::Monday=>tr('Monday'),
- Qt::Tuesday=>tr('Tuesday'), Qt::Wednesday=>tr('Wednesday'),
- Qt::Thursday=>tr('Thursday'), Qt::Friday=>tr('Friday'),
- Qt::Saturday=>tr('Saturday') }
+ def possibleHorHeaders
+ require_relative 'structure'
+ @possibleHorHeaders ||= Structure.new PossibleHorHeaders
+ end
+ def possibleVerHeaders
+ require_relative 'structure'
+ @possibleVerHeaders ||= Structure.new PossibleVerHeaders
+ end
end # class CalendarModel
createInstantiator File.basename(__FILE__, '.rb'), nil, CalendarModel
-end
+end # module Reform
View
97 lib/reform/models/locale_model.rb
@@ -1,7 +1,7 @@
-# Copyright (c) 2010 Eugene Brazwick
+# Copyright (c) 2010-2011 Eugene Brazwick
-require_relative '../model'
+require 'reform/model'
module Reform
@@ -9,46 +9,71 @@ class LocaleModel < AbstractModel # < Qt::Object # QObject required for 'tr'
include Enumerable
private
- def initialize
- super
- @locales = nil
- end
+ def initialize parent, qtc
+ super
+ @locales = nil
+ end
+
+ def locales
+ unless @locales
+ @locales = []
+ idx = {}
+ l = Qt::Locale::C
+ while l <= Qt::Locale::LastLanguage
+ name = Qt::Locale.new(l).name
+ unless idx[name]
+ idx[name] = true
+ @locales << name
+ end
+ l += 1
+ end
+ @locales.sort!
+ end
+ @locales
+ end
public
- # obj=>string hash, string is displayed in lists (by default at least)
- def each_pair_BROKEN
- l = Qt::Locale::C
- while l <= Qt::Locale::LastLanguage
- desc = Qt::Locale::languageToString(l) # + '/'
-# countries = Qt::Locale::countriesForLanguage(l) BROKEN in kdebindings_4.4.2
-# for country in countries
- label = desc # + Qt::Locale::countryToString(l.country)
- locale = Qt::Locale.new(l) # , l.country)
+ # obj=>string hash, string is displayed in lists (by default at least)
+ def each_pair_BROKEN
+ l = Qt::Locale::C
+ while l <= Qt::Locale::LastLanguage
+ desc = Qt::Locale::languageToString(l) # + '/'
+ # countries = Qt::Locale::countriesForLanguage(l) BROKEN in kdebindings_4.4.2
+ # for country in countries
+ label = desc # + Qt::Locale::countryToString(l.country)
+ locale = Qt::Locale.new(l) # , l.country)
=begin problems
1) Walamo and English (and many more) have locale 'en_US'.
=end
- yield locale.name, label
-# end
- l += 1
- end
- end
-
- def each &block
- unless @locales
- @locales = {}
- l = Qt::Locale::C
- while l <= Qt::Locale::LastLanguage
- @locales[Qt::Locale.new(l).name] = true
- l += 1
- end
-# @locales.sort!
- end
- # delegate!
- @locales.keys.each(&block)
-# each_pair { |locale, text| yield [locale, text] }
- end
+ yield locale.name, label
+ # end
+ l += 1
+ end
+ end
+
+ def each &block
+ locales.each(&block)
+ end
+
+ def model_row i
+ locs = locales
+ #tag "locs = #{locs.inspect}" BEWARE
+ locs[i] #.tap{|t| tag"model_row(#{i}) -> #{t}"}
+ end
+
+ def length
+ locales.length
+ end
+
+ def model_value2index value, view
+ locales.find_index(value)
+ end
+
+ def model_index2value numeric_idx, view
+ locales[numeric_idx]
+ end
end # class LocaleModel
createInstantiator File.basename(__FILE__, '.rb'), nil, LocaleModel
-end # module Reform
+end # module Reform
View
155 lib/reform/models/rstore.rb
@@ -3,7 +3,7 @@
require 'pp'
-# TODO: fully persistent version of structure.rb
+# fully persistent version of structure.rb
# And automatically persistent.
=begin
@@ -13,9 +13,9 @@
'new' will connect to the rstore and hence a completely filled instance
is always immediately at your service.
- rstore will use yaml files on disk and some clever cutting algo to keep
- things fast.
- rstore v1 will not be transaction save. The data may get corrupted if
+ rstore will use a configurable backend, default gdbm
+ rstore v1 is transaction save, provided the backend is. gdbm is NOT!!!
+ The data may get corrupted if
the application crashes or in all other cases where a transaction is
partly executed.
@@ -24,7 +24,7 @@
==================
the database has no idea about which nodes can be reached from the root!
Therefor it must be periodically scanned and cleaned using a true GC.
- NOT IMPLEMENTED YET: and hence it will grow and grow. FIXME
+ To do this use 'compact' now and then.
=============================
MAD SCIENTIST ALERT!!!!
@@ -96,6 +96,11 @@ def initialize oid
private # RStoreNode methods
+ # Basic model constructor
+ # +parent+ is the parent model and +parent+.+key+ should refer to this node again
+ # +value+ is the object or array or hash to wrap
+ # +oid+ is the oid in the rstore.
+ # This is an internal method, do not call directly
def initialize parent, key, value, oid
raise "BOGO key #{key.inspect}" if !(nil == key || Symbol === key || Integer === key && key < 10_000_000)
raise 'arg' if Class === parent
@@ -105,6 +110,7 @@ def initialize parent, key, value, oid
@rstore_oid = oid
end
+ # override, assign a key within the model
def model_assign key, value, method_symbol = nil
# tag "model_assign[#{key}] := #{value.inspect}"
# raise 'WTF' if value.nil? nothing wrong with a[2] = nil etc.
@@ -123,6 +129,8 @@ def model_assign key, value, method_symbol = nil
# tag "model_value is now #{@model_value.inspect}"
end
+ # returns true if the value is not a complex object.
+ # complex object within a node must become nodes themselves!
def self.rstore_atom?(value)
case value
# RStoreNode is not one of them!!! These classes are basicly stored 'raw'!
@@ -144,20 +152,12 @@ def self.rstore_atom?(value)
with 3 different nodes, but each has the same oid!
=end
# this is the place where rstore contents is gathered and stored
- def self.rstore_inter key, value, parent, rstore
+ def self.rstore_wrap key, value, parent, rstore
# tag "rstore_inter(#{key}, #{value}), id = #{value.object_id}"
- return value if rstore_atom?(value) || RStoreNode === value
- need_ospace_storing = false
- if oid = rstore.objectspace[id = value.object_id]
- rv = rstore.revspace[oid] and return rv
- else
- oid = rstore.rstore_gen_oid(value)
- need_ospace_storing = true
- end
case value
when Hash
value.each do |k, v|
- raise "bad key #{k.inspect}" unless Symbol === k || String === k
+ #raise "bad key #{k.inspect} within value to wrap: #{value.inspect}" unless Symbol === k || String === k
value[k] = rstore_inter(k, v, parent, rstore) unless rstore_atom?(v)
end
when Array
@@ -166,7 +166,7 @@ def self.rstore_inter key, value, parent, rstore
end
else
if value.respond_to?(:model_has_own_storage?) && value.model_has_own_storage?
- STDERR.print "kind of mounted model '#{value}' detected, not stored!!!"
+# tag "kind of mounted model '#{value}' detected, not stored!!!"
value.model_parent = parent
value.model_key = key
rstore.rstore_assign_oid(oid, value) if need_ospace_storing
@@ -183,7 +183,19 @@ def self.rstore_inter key, value, parent, rstore
end
end
end
+ end
+
+ def self.rstore_inter key, value, parent, rstore
# tag "returning from rstore_inter, got oid #{oid}"
+ return value if rstore_atom?(value) || RStoreNode === value
+ need_ospace_storing = false
+ if oid = rstore.objectspace[id = value.object_id]
+ rv = rstore.revspace[oid] and return rv
+ else
+ oid = rstore.rstore_gen_oid(value)
+ need_ospace_storing = true
+ end
+ rstore_wrap key, value, parent, rstore
rv = RStoreNode.new(parent, key, value, oid)
if need_ospace_storing
# tag "inter stores new oid #{oid}"
@@ -740,7 +752,7 @@ def model_apply_getter name
begin
@model_value[name]
rescue TypeError
- tag "TypeError, model_value is #@model_value"
+# tag "TypeError, for [#{name.inspect}].model_value is #{@model_value.inspect}"
raise Error, tr("Bad getter '#{name.inspect}' on #{@model_value.class} value, caller = #{caller.join("\n")}")
end
# nil
@@ -794,14 +806,65 @@ def respond_to? symbol
Hash === @model_value && @model_value[symbol] || super
end
+ # this method is used to set the proper row, if 'value' is connected to it.
+ # Now the problem is that Hashes and Arrays can connect to their index or
+ # their value.
+ #
+ # IMPORTANT saying 'key_connector:id' is not the same as leaving it
+ # the default (also :id)
+ # Because this switches on locating the value by key
+ #
+ def model_value2index value, view
+# tag "#{self}::model_value2index(#{value}, view:#{view})"
+ return 0 if value.nil?
+ key_connector = view.key_connector
+ key = model_value2key(value, view) or
+ key ||= value if key_connector # if key-lookup is enforced,
+# tag "model_value2index, key_connector=#{key_connector}, key = #{key.inspect}, value was #{(value.respond_to?(:value) ? value.value : value).inspect}"
+ if @model_value.respond_to?(:each_key)
+# tag "HASH case"
+ if key
+ @model_value.each_key.find_index(key)
+ elsif @model_value.respond_to?(:each_pair)
+# tag "Using each_pair"
+ @model_value.each_pair.find_index { |k, v| v == value }
+ end
+ @model_value.each_key.find_index(value)
+ elsif @model_value.respond_to?(:find_index)
+# tag "ARRAY case"
+ return nil if @model_4value.empty?
+ key = value if !key && model_value2key(@model_value[0], view) # force the use of a key if this seems to be how it should be done.
+ # but it is higher heuristics
+ if key
+ return key if key_connector == :numeric_index
+ @model_value.find_index do |value|
+# tag "Comparing value2key #{value2key(value, view).inspect}, with key #{key.inspect}"
+ model_value2key(value, view) == key
+ end #.tap{|r|tag "find_index -> #{r.inspect}"}
+ else
+ @model_value.find_index(value)
+ end
+ else
+ 0
+ end
+ end
+
end # class RStoreNode
+ # RStore is the toplevel node. It is simply an extended RStoreNode and
+ # hence can wrap around any object or hash or array.
+ # RStore has extended caching tables so consume quite a lot of memory
class RStore < RStoreNode
ROOT_OID = '0'
# RStore::Node == RStoreNode, for some reason
Node = RStoreNode
- private # RStore methods
- def initialize dbname
+ private # RStore method
+ # Create a new rstore.
+ # The extension of dbname is important.
+ # If +dbname+ is nil, a nil-store (non persistent) is created
+ # If +init_value+ is set, it is used as initial value, provided
+ # +dbname+ was nil. Otherwise ignored
+ def initialize dbname, init_value = nil
super(nil, nil, nil, ROOT_OID)
# hash from object_id to oid
@objectspace = {}
@@ -828,18 +891,21 @@ def initialize dbname
raise 'blech' if @rstore_db.closed?
if rstore_root = @rstore_db[ROOT_OID]
# tag "rstore_db[ROOT_OID] = #{rstore_root.inspect}"
- t = Marshal::load(rstore_root)
- if t.nil?
- STDERR.print "OK, attempt to fix CORRUPTED database!!! CLEANED\n"
- clear
- else
-# tag "Loaded marshal-ed raw value #{t.pretty_inspect}, calling rstore_hash2value"
- @model_value = RStoreNode::rstore_hash2value(t, self)
-# tag "Loaded marshal-ed value #{@model_value.pretty_inspect}"
- end
+ if !dbname && init_value
+ clear init_value
+ else
+ t = Marshal::load(rstore_root)
+ if t.nil?
+ STDERR.print "OK, attempt to fix CORRUPTED database!!! CLEANED\n"
+ clear
+ else
+ # tag "Loaded marshal-ed raw value #{t.pretty_inspect}, calling rstore_hash2value"
+ @model_value = RStoreNode::rstore_hash2value(t, self)
+ # tag "Loaded marshal-ed value #{@model_value.pretty_inspect}"
+ end
+ end
else
-# @model_value = {}
- clear
+ clear(dbname ? nil : init_value)
end
if block_given?
begin
@@ -880,22 +946,22 @@ def rstore_mark val
public # RStore methods
- def clear
- @model_value = {}
+ def clear init_value = nil
@rstore_db.clear
@in_tran = false
@objectspace = {}
@revspace = {}
- # it is rather obvious that rstore_value2hash({}) == {} itself.
+ if init_value
+ model_pickup_tran do |tran|
+ @model_value = init_value
+ RStoreNode::rstore_wrap(nil, @model_value, self, self)
+ end
+ else
+ @model_value = {}
+ end
@rstore_db[ROOT_OID] = Marshal::dump(RStoreNode::rstore_value2hash(@model_value, self))
end
- # an RStore behaves like a hash, so the method to use would be 'delete'
-# def remove *keys
-# keys.each do |key|
-# end
-# end
-
# it must be public
def rstore_rstore
# tag "RStore::rstore_rstore"
@@ -904,6 +970,9 @@ def rstore_rstore
attr :objectspace, :revspace
+ # this is important since it connects us to the controltree
+ attr_accessor :parent
+
def tran?
@in_tran
end
@@ -936,7 +1005,7 @@ def model_begin_work
def model_commit_work altered_owners
raise ProtocolError, 'no transaction to commit' unless @in_tran
-# tag ">>> model_commit_work, altered_owners = #{altered_owners.inspect}"
+# tag ">>> model_commit_work, altered_owners = #{altered_owners.inspect}"
altered_owners.each do |object_id, node|
raise 'aaargh' unless RStoreNode === node
raise 'aargh' unless oid = node.rstore_oid
@@ -961,7 +1030,7 @@ def rstore_assign_i oid, value
end
def rstore_assign_oid oid, value
- raise 'BOGO call' if RStoreNode === value
+ raise 'BOGO call: trying to store a wrapper??' if RStoreNode === value
raise 'Attempt to update outside transaction' unless @in_tran
raise 'wtf' if oid =~ /^rstore/
# tag "Storing node in rstore DB: oid=#{oid} => #{value.inspect}"
@@ -983,7 +1052,8 @@ def model_has_own_storage?
def rstore_db_length
@rstore_db.length
end
-
+
+ # for debugging purposes
def rstore_db_inspect
@rstore_db.each_pair.to_a.pretty_inspect
end
@@ -1006,6 +1076,7 @@ def garbage_collect
# @model_value.compact! no such method exists
# garbage_collect
# end
+
end # class RStore
end # module Reform
View
58 lib/reform/models/structure.rb
@@ -27,15 +27,15 @@ class Structure < RStore
private # methods of Structure
- # [value] the hash
+ # [value] the hash, or array, or any object actually
def initialize value = nil
- super(nil)
- if value
- model_pickup_tran(sender) do
- # I think this is the most honoust way of setting up @model_value
- value.each { |k, v| self[k] = v }
- end
- end
+ super(nil, value)
+# if value
+# model_pickup_tran(sender) do
+# # I think this is the most honoust way of setting up @model_value
+# value.each { |k, v| self[k] = v }
+# end
+# end
end
public # methods of Structure
@@ -66,48 +66,6 @@ def each_with_index &block
end
=end
- # this method is used to set the proper row, if 'value' is connected to it.
- # Now the problem is that Hashes and Arrays can connect to their index or
- # their value.
- #
- # IMPORTANT saying 'key_connector:id' is not the same as leaving it
- # the default (also :id)
- # Because this switches on locating the value by key
- #
- def model_value2index value, view
- return 0 if value.nil?
- key_connector = view.key_connector
- key = model_value2key(value, view) or
- key ||= value if key_connector # if key-lookup is enforced,
-# tag "value2index, key_connector=#{key_connector}, key = #{key.inspect}, value was #{(value.respond_to?(:value) ? value.value : value).inspect}"
- if @model_value.respond_to?(:each_key)
-# tag "HASH case"
- if key
- @model_value.each_key.find_index(key)
- elsif @model_value.respond_to?(:each_pair)
-# tag "Using each_pair"
- @model_value.each_pair.find_index { |k, v| v == value }
- end
- @model_value.each_key.find_index(value)
- elsif @model_value.respond_to?(:find_index)
-# tag "ARRAY case"
- return nil if @model_4value.empty?
- key = value if !key && model_value2key(@model_value[0], view) # force the use of a key if this seems to be how it should be done.
- # but it is higher heuristics
- if key
- return key if key_connector == :numeric_index
- @model_value.find_index do |value|
-# tag "Comparing value2key #{value2key(value, view).inspect}, with key #{key.inspect}"
- model_value2key(value, view) == key
- end #.tap{|r|tag "find_index -> #{r.inspect}"}
- else
- @model_value.find_index(value)
- end
- else
- 0
- end
- end
-
# Qt::Base overrides this, so we must overoverride it
def << value
self.method_missing(:<<, value)
View
176 lib/reform/widgets/calendarwidget.rb 100755 → 100644
@@ -1,124 +1,122 @@
#!/usr/bin/ruby -w
-# Copyright (c) 2010 Eugene Brazwick
+# Copyright (c) 2010-2011 Eugene Brazwick
require 'Qt'
require_relative '../app'
+require_relative '../widget'
+require_relative '../models/calendar_model'
module Reform
- require_relative '../widget'
- require_relative '../models/calendar_model'
-
+ # our wrapper for QCalendarWidget
class CalendarWidget < Widget
private
- def initialize parent, qtc
- super
- connect(@qtc, SIGNAL('selectionChanged()'), self) do
-# tag "SELCHANGE, date #{@qtc.selectedDate.inspect}"
- # BEWARE FOR LOOP/STACKOVERFLOW. this will call updateModel
- # which calls @qtc.selectedDate := X
- # which MAY trigger selectionChanged(). However, it doesn't seem to do that
- # to be safe I use options[:property]
- rfRescue { model = effectiveModel and model.selectedDate = @qtc.selectedDate }
+ def initialize parent, qtc
+ super
+ connect(@qtc, SIGNAL('selectionChanged()'), self) do
+ # tag "SELCHANGE, date #{@qtc.selectedDate.inspect}"
+ # BEWARE FOR LOOP/STACKOVERFLOW. this will call updateModel
+ # which calls @qtc.selectedDate := X
+ # which MAY trigger selectionChanged(). However, it doesn't seem to do that
+ # to be safe I use options[:property]
+ rfRescue { mod = model and mod.selectedDate = @qtc.selectedDate }
+ end
end
- end
- def minimumDate *value
-# tag "#{self}::minimumDate, qtc=#@qtc"
- return @qtc.minimumDate if value.empty?
- @qtc.minimumDate = CalendarModel::to_date(*value)
- end
+ # minimumDate accepts the same as CalendarModel::to_date
+ # without arguments it returns the current value
+ def minimumDate *value
+ # tag "#{self}::minimumDate, qtc=#@qtc"
+ return @qtc.minimumDate if value.empty?
+ @qtc.minimumDate = CalendarModel::to_date(*value)
+ end
- def maximumDate *value
- return @qtc.maximumDate if value.empty?
- @qtc.maximumDate = CalendarModel::to_date(*value)
- end
+ # maximumDate accepts the same as CalendarModel::to_date
+ # without arguments it returns the current value
+ def maximumDate *value
+ return @qtc.maximumDate if value.empty?
+ @qtc.maximumDate = CalendarModel::to_date(*value)
+ end
- define_simple_setter :gridVisible
+ define_simple_setter :gridVisible
- def whenCurrentPageChanged &block
- if block
- connect(@qtc, SIGNAL('currentPageChanged(int, int)'), self) do
+ def whenCurrentPageChanged &block
+ if block
+ connect(@qtc, SIGNAL('currentPageChanged(int, int)'), self) do
- rfCallBlockBack(&block)
- end
- else
- @qtc.currentPageChanged(@qtc.yearShown, @qtc.monthShown)
+ rfCallBlockBack(&block)
+ end
+ else
+ @qtc.currentPageChanged(@qtc.yearShown, @qtc.monthShown)
+ end
end
- end
- alias :whenMonthChanged :whenCurrentPageChanged
+ alias :whenMonthChanged :whenCurrentPageChanged
- PossibleSelections = { Qt::CalendarWidget::SingleSelection=>tr("Single selection"), # DEFAULT
- Qt::CalendarWidget::NoSelection=>tr("None") }
-
- PossibleHorizontalHeaderOptions = {
- Qt::CalendarWidget::SingleLetterDayNames=>tr('Single letter day names'),
- Qt::CalendarWidget::ShortDayNames=>tr('Short day names'), # DEFAULT
- Qt::CalendarWidget::NoHorizontalHeader=>tr('None')
- }
-
- PossibleVerticalHeaderOptions = {
- Qt::CalendarWidget::ISOWeekNumbers=>tr('ISO week numbers'), # DEFAULT
- Qt::CalendarWidget::NoVerticalHeader=>tr('None') }
public
- #override
- @@connectingModelSem = false
-
- def updateModel model, options = nil
- return if @@connectingModelSem
- @@connectingModelSem = true
-# tag "#{self}::updateModel, qtc=#@qtc, caller=#{caller.join("\n")}, options=#{options.inspect}"
-# with model do
- # this is crude code. It simply assumes that model is the right one.
- #it also assumes model is not nil
- # RESSETTING all dateformatting first, to erase specific hacks in the
- # calendar example.
- @qtc.setDateTextFormat(Qt::Date.new, Qt::TextCharFormat.new)
- @qtc.minimumDate = model.minimumDate
- @qtc.maximumDate = model.maximumDate
- @qtc.selectionMode = model.selectionMode
- @qtc.horizontalHeaderFormat = model.horizontalHeaderFormat
- @qtc.verticalHeaderFormat = model.verticalHeaderFormat
- @qtc.navigationBarVisible = model.navigationBarVisible?
- @qtc.gridVisible = model.gridVisible?
- @qtc.firstDayOfWeek = model.firstDayOfWeek
- unless options && options[:property] == :selectedDate
- @qtc.selectedDate = model.selectedDate || Qt::Date.new
- end
- lang = model.locale || 'C'
-# tag "lang := #{lang}"
- @qtc.locale = Qt::Locale.new(lang)
- super
- ensure
+ #override
@@connectingModelSem = false
- end
- def setWeekdayTextFormat *args
- @qtc.setWeekdayTextFormat(*args)
- end
+ # override
+ def updateModel model, propa
+ return if @@connectingModelSem
+ @@connectingModelSem = true
+ # tag "#{self}::updateModel, qtc=#@qtc, caller=#{caller.join("\n")}, options=#{options.inspect}"
+ # with model do
+ # this is crude code. It simply assumes that model is the right one.
+ #it also assumes model is not nil
+ # RESSETTING all dateformatting first, to erase specific hacks in the
+ # calendar example.
+ @qtc.setDateTextFormat(Qt::Date.new, Qt::TextCharFormat.new)
+ @qtc.minimumDate = model.minimumDate
+ @qtc.maximumDate = model.maximumDate
+ @qtc.selectionMode = model.selectionMode
+ @qtc.horizontalHeaderFormat = model.horizontalHeaderFormat
+ @qtc.verticalHeaderFormat = model.verticalHeaderFormat
+ @qtc.navigationBarVisible = model.navigationBarVisible?
+ @qtc.gridVisible = model.gridVisible?
+ @qtc.firstDayOfWeek = model.firstDayOfWeek
+ #tag "assigning #{model.selectedDate.inspect} to #@qtc#selectedDate"
+ if date = model.selectedDate
+ @qtc.selectedDate = Qt::Date === date ? date : CalendarModel::to_date(date)
+ else
+ @qtc.selectedDate = Qt::Date.new
+ end
+ lang = model.locale || 'C'
+ # tag "lang := #{lang}"
+ @qtc.locale = Qt::Locale.new(lang)
+ super
+ ensure
+ @@connectingModelSem = false
+ end
+
+ def setWeekdayTextFormat *args
+ @qtc.setWeekdayTextFormat(*args)
+ end
- def setDateTextFormat *args
- @qtc.setDateTextFormat(*args)
- end
+ def setDateTextFormat *args
+ @qtc.setDateTextFormat(*args)
+ end
- define_simple_setter :headerTextFormat
+ define_simple_setter :headerTextFormat
- def yearShown
- @qtc.yearShown
- end
+ def yearShown
+ @qtc.yearShown
+ end
- def monthShown
- @qtc.monthShown
- end
+ def monthShown
+ @qtc.monthShown
+ end
end # CalendarWidget
- QCalendarWidget = Qt::CalendarWidget
+ class QCalendarWidget < Qt::CalendarWidget
+ include QWidgetHackContext
+ end
createInstantiator File.basename(__FILE__, '.rb'), QCalendarWidget, CalendarWidget
View
9 lib/reform/widgets/checkbox.rb
@@ -18,6 +18,13 @@ def initialize parent, qtc, connectit = true
end
end
end
+ connect(@qtc, SIGNAL('toggled(bool)'), self) do |checked|
+ rfRescue do
+ if (cid = connector) && (mod = model)
+ mod.model_apply_setter(cid, checked)
+ end
+ end
+ end
end
end # initialize
@@ -90,4 +97,4 @@ def updateModel model, options = nil
end # class CheckBox
createInstantiator File.basename(__FILE__, '.rb'), Qt::CheckBox, CheckBox
-end # Reform
+end # Reform
View
16 lib/reform/widgets/combobox.rb
@@ -42,7 +42,7 @@ def initialize parent, qtc
# @model_connector = nil
connect(@qtc, SIGNAL('activated(int)'), self) do |idx|
rfRescue do
-# tag "Activated(#{idx})"
+# tag "Activated(#{idx})"
if model && (cid = connector) && model.model_setter?(cid)
activated(model, cid, idx)
end
@@ -50,13 +50,6 @@ def initialize parent, qtc
end
end # initialize
-# def currentKey k
- # tag "currentKey := #{k.class}#{k}, index=#{@index.inspect}, index[k]=#{@index[k]}"
- # k = k.to_i if k.respond_to?(:to_i) # this fixes Qt::Enum identity crises (I hope) AARGH
-# @qtc.currentIndex = @index[enum2i(k)] || -1
- # tag "currentIndex is now #{@qtc.currentIndex}"
-# end
-
define_simple_setter :currentIndex
# can be overriden. Called when combobox index, value has been decided
@@ -67,11 +60,14 @@ def setCurrentIndex index
public
# use this instead of connecting 'activated'
+ # arg1: data, arg2: the key
def whenActivated &block
if block
connect(@qtc, SIGNAL('activated(int)'), self) do |idx|
# tag "idx = #{idx}, data_to_transmit[idx] = #{data_at(idx).inspect}"
- rfCallBlockBack(data_at(idx), idx, &block)
+ data = @localmodel.model_row(idx)
+ #tag "data = #{data.inspect}"
+ rfCallBlockBack(data, @localmodel.model_value2key(data, self), &block)
end
else
@qtc.activated(@qtc.currentIndex)
</