lib/clevic/browser.rb in clevic-0.7.0 vs lib/clevic/browser.rb in clevic-0.8.0
- old
+ new
@@ -1,24 +1,15 @@
require 'clevic/search_dialog.rb'
require 'clevic/ui/browser_ui.rb'
+require 'clevic/record.rb'
+require 'clevic.rb'
module Clevic
=begin rdoc
-The main application class. Each model for display should have a self.ui method
-which returns a Clevic::TableView instance, usually in conjunction with
-a ModelBuilder.
-
- Clevic::TableView.new( Entry, parent ).create_model.new( Entry, parent ).create_model
- .
- .
- .
- end
-
-Model instances may also implement <tt>self.key_press_event( event, current_index, view )</tt>
-and <tt>self.data_changed( top_left_index, bottom_right_index, view )</tt> methods so that
-they can respond to editing events and do Neat Stuff.
+The main application class. Display as many tabs as there are Clevic::Record or ActiveRecord::Base
+subclasses.
=end
class Browser < Qt::Widget
slots *%w{dump() refresh_table() filter_by_current(bool) next_tab() previous_tab() current_changed(int)}
def initialize( main_window )
@@ -36,30 +27,52 @@
# add the tables tab
@tables_tab = Qt::TabWidget.new( @layout.main_widget )
@layout.main_widget.layout.add_widget @tables_tab
@tables_tab.tab_bar.focus_policy = Qt::NoFocus
- # connect slots
- @layout.action_dump.connect SIGNAL( 'triggered()' ), &method( :dump )
- @layout.action_refresh.connect SIGNAL( 'triggered()' ), &method( :refresh_table )
- @layout.action_filter.connect SIGNAL( 'triggered(bool)' ), &method( :filter_by_current )
+ # hide the file menu, for now
+ @layout.menubar.remove_action( @layout.menu_file.menu_action )
+
+ # tab navigation
@layout.action_next.connect SIGNAL( 'triggered()' ), &method( :next_tab )
@layout.action_previous.connect SIGNAL( 'triggered()' ), &method( :previous_tab )
- @layout.action_find.connect SIGNAL( 'triggered()' ), &method( :find )
- @layout.action_find_next.connect SIGNAL( 'triggered()' ), &method( :find_next )
- @layout.action_new_row.connect SIGNAL( 'triggered()' ), &method( :new_row )
+
+ # dump model for current tab
+ @layout.action_dump.visible = $options[:debug]
+ @layout.action_dump.connect SIGNAL( 'triggered()' ), &method( :dump )
tables_tab.connect SIGNAL( 'currentChanged(int)' ), &method( :current_changed )
- # as an example
- #~ tables_tab.connect SIGNAL( 'currentChanged(int)' ) { |index| puts "other current_changed: #{index}" }
load_models
+ update_menus
end
- # activated by Ctrl-D for debugging
+ def update_menus
+ # update edit menu
+ @layout.menu_edit.clear
+
+ # do the model-specific menu items first
+ table_view.model_actions.each do |action|
+ @layout.menu_edit.add_action( action )
+ end
+
+ # now do the generic edit items
+ table_view.edit_actions.each do |action|
+ @layout.menu_edit.add_action( action )
+ end
+
+ # update search menu
+ @layout.menu_search.clear
+ table_view.search_actions.each do |action|
+ @layout.menu_search.add_action( action )
+ end
+ end
+
+ # activated by Ctrl-Shift-D for debugging
def dump
- puts "table_view.model: #{table_view.model.inspect}" if table_view.class == Clevic::TableView
+ puts "table_view.model: #{table_view.model.inspect}"
+ puts "table_view.model.model_class: #{table_view.model.model_class.inspect}"
end
# return the Clevic::TableView object in the currently displayed tab
def table_view
tables_tab.current_widget
@@ -67,61 +80,10 @@
def tables_tab
@tables_tab
end
- # display a search dialog, and find the entered text
- def find
- @search_dialog ||= SearchDialog.new
- result = @search_dialog.exec( table_view.current_index.gui_value )
-
- override_cursor( Qt::BusyCursor ) do
- case result
- when Qt::Dialog::Accepted
- search_for = @search_dialog.search_text
- table_view.search( @search_dialog )
- when Qt::Dialog::Rejected
- puts "Don't search"
- else
- puts "unknown dialog code #{result}"
- end
- end
- end
-
- def find_next
- if @search_dialog.nil?
- @layout.statusbar.show_message( 'No previous find' )
- else
- override_cursor( Qt::BusyCursor ) do
- save_from_start = @search_dialog.from_start?
- @search_dialog.from_start = false
- table_view.search( @search_dialog )
- @search_dialog.from_start = save_from_start
- end
- end
- end
-
- # force a complete reload of the current tab's data
- def refresh_table
- override_cursor( Qt::BusyCursor ) do
- table_view.model.reload_data
- end
- end
-
- # toggle the filter, based on current selection.
- def filter_by_current( bool_filter )
- # TODO if there's no selection, use the current index instead
- table_view.filter_by_indexes( table_view.selection_model.selected_indexes )
-
- # set the checkbox in the menu item
- @layout.action_filter.checked = table_view.filtered
-
- # update the tab, so there's a visual indication of filtering
- tab_title = table_view.filtered ? translate( '| ' + table_view.model_class.name.humanize ) : translate( table_view.model_class.name.humanize )
- tables_tab.set_tab_text( tables_tab.current_index, tab_title )
- end
-
# slot to handle Ctrl-Tab and move to next tab, or wrap around
def next_tab
tables_tab.current_index =
if tables_tab.current_index >= tables_tab.count - 1
0
@@ -138,75 +100,83 @@
else
tables_tab.current_index - 1
end
end
- def new_row
- table_view.model.add_new_item
- end
-
# slot to handle the currentChanged signal from tables_tab, and
# set focus on the grid
def current_changed( current_tab_index )
- tables_tab.current_widget.setFocus
- @layout.action_filter.checked = table_view.filtered
+ update_menus
+ tables_tab.current_widget.set_focus
end
# shortcut for the Qt translate call
def translate( st )
Qt::Application.translate("Browser", st, nil, Qt::Application::UnicodeUTF8)
end
- # return the list of descendants of ActiveRecord::Base
+ # return the list of descendants of ActiveRecord::Base, or
+ # of Clevic::Record
def find_models
models = []
- ObjectSpace.each_object( Class ) {|x| models << x if x.ancestors.include?( Clevic::Record ) }
- models
- end
-
- # define a default ui with plain fields for all
- # columns (except id) in the model. Could combine this with
- # DrySQL to automate the process.
- def define_default_ui( model )
- reflections = model.reflections.keys.map{|x| x.to_s}
- ui_columns = model.columns.reject{|x| x.name == 'id' }.map do |x|
- att = x.name.gsub( '_id', '' )
- if reflections.include?( att )
- att
- else
- x.name
- end
- end
-
- Clevic::TableView.new( model, tables_tab ).create_model do
- ui_columns.each do |column|
- if model.reflections.has_key?( column.to_sym )
- relational column.to_sym
- else
- plain column.to_sym
+ ObjectSpace.each_object( Class ) do |x|
+ if x.ancestors.include?( ActiveRecord::Base )
+ case
+ when x == ActiveRecord::Base; # don't include this
+ when x == Clevic::Record; # don't include this
+ else; models << x
end
end
- records :order => 'id'
end
+ models.sort{|a,b| a.name <=> b.name}
end
# Create the tabs, each with a collection for a particular model class.
#
# models parameter can be an array of Model objects, in order of display.
# if models is nil, find_models is called
def load_models
- models = Clevic::Record.models || find_models
+ models = Clevic::Record.models
+ models = find_models if models.empty?
# Add all existing model objects as tabs, one each
- models.each do |model|
- tab =
- if model.respond_to?( :ui )
- model.ui( tables_tab )
- else
- define_default_ui( model )
+ models.each do |model_class|
+ begin
+ next unless model_class.table_exists?
+
+ # create the the table_view and the table_model for the model_class
+ tab =
+ if model_class.respond_to?( :ui )
+ puts "Entity#ui deprecated. Use build_table_model instead."
+ model_class.ui( tables_tab )
+ else
+ Clevic::TableView.new( model_class, tables_tab )
+ end
+
+ # show status messages
+ tab.connect( SIGNAL( 'status_text(QString)' ) ) { |msg| @layout.statusbar.show_message( msg, 10000 ) }
+
+ # add a new tab
+ tables_tab.add_tab( tab, translate( model_class.name.demodulize.tableize.humanize ) )
+
+ # add the table to the Table menu
+ action = Qt::Action.new( @layout.menu_model )
+ action.text = translate( model_class.name.demodulize.tableize.humanize )
+ action.connect SIGNAL( 'triggered()' ) do
+ tables_tab.current_widget = tab
+ end
+ @layout.menu_model.add_action( action )
+
+ # handle filter status changed, so we can provide a visual indication
+ tab.connect SIGNAL( 'filter_status(bool)' ) do |status|
+ # update the tab, so there's a visual indication of filtering
+ tab_title = ( tab.filtered ? '| ' : '' ) + translate( model_class.name.humanize )
+ tables_tab.set_tab_text( tables_tab.current_index, tab_title )
+ end
+ rescue Exception => e
+ puts e.backtrace if $options[:debug]
+ puts "Model #{model_class} will not be available: #{e.message}"
end
- tab.connect( SIGNAL( 'status_text(QString)' ) ) { |msg| @layout.statusbar.show_message( msg, 20000 ) }
- tables_tab.add_tab( tab, translate( model.name.humanize ) )
end
end
# make sure all outstanding records are saved
def save_all