Class: Canis::App

Inherits:
Object show all
Includes:
WidgetShortcuts
Defined in:
lib/canis/core/util/app.rb

Overview

This is the Application class which does the job of setting up the environment, and closing it at the end.

Instance Attribute Summary collapse

methods to create widgets easily collapse

Instance Method Summary collapse

Methods included from WidgetShortcuts

#_configure, #_position, #app_header, #blank, #box, #button, #check, def_widget, #dock, #field, #flow, #label, #line, #link, #listbox, #menubar, #menulink, #radio, #stack, #status_line, #table, #textarea, #textpad, #tree, #widget_shortcuts_init

Constructor Details

#initialize(config = {}, &block) ⇒ App

TODO: i should be able to pass window coords here in config :title



85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/canis/core/util/app.rb', line 85

def initialize config={}, &block
  @config = config


  widget_shortcuts_init
  @variables = {}
  # if we are creating child objects then we will not use outer form. this object will manage
  #@current_object = []  # 2014-08-29 - 17:35 unused
  @_system_commands = %w{ bind_global bind_component field_help_text }

  init_vars
  $log.debug "XXX APP CONFIG: #{@config}  " if $log.debug? 
  run &block
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



78
79
80
# File 'lib/canis/core/util/app.rb', line 78

def config
  @config
end

#formObject (readonly)

Returns the value of attribute form.



79
80
81
# File 'lib/canis/core/util/app.rb', line 79

def form
  @form
end

#quit_key=(value) ⇒ Object (writeonly)

Sets the attribute quit_key

Parameters:

  • value

    the value to set the attribute quit_key to.



81
82
83
# File 'lib/canis/core/util/app.rb', line 81

def quit_key=(value)
  @quit_key = value
end

#windowObject (readonly)

Returns the value of attribute window.



80
81
82
# File 'lib/canis/core/util/app.rb', line 80

def window
  @window
end

Instance Method Details

#bind_globalObject

bind a key to a method at global (form) level Note that individual component may be overriding this.



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
# File 'lib/canis/core/util/app.rb', line 265

def bind_global
  opts = get_all_commands
  cmd = rb_gets("Select a command (<tab> for choices) : ", opts)
  if cmd.nil? || cmd == ""
    rb_puts "Aborted."
    return
  end
  key = []
  str = ""
  # the next is fine but does not allow user to enter a control or alt or function character
  # since it uses Field. It is fine if you want to force alphanum input
  ch = rb_getchar("Enter one or two keys. Finish with <ENTER>. Enter first key:")
  unless ch
    rb_puts "Aborted. <Press a key>"
    return
  end
  key << ch
  str << keycode_tos(ch)
  ch = rb_getchar  "Got #{str}. Enter second key or hit return:"
  unless ch
    rb_puts "Aborted. <Press a key>"
    return
  end
  if ch == KEY_ENTER || ch == 13
  else
    key << ch
    str << keycode_tos(ch)
  end
  if !key.empty?
    rb_puts "Binding #{cmd} to #{str}. "
    key = key[0] if key.size == 1
    #@form.bind_key(key, cmd.to_sym) # not finding it, getting called by that comp
    @form.bind_key(key){ send(cmd.to_sym) }
  end
end

#closeObject



113
114
115
116
117
118
119
120
121
122
# File 'lib/canis/core/util/app.rb', line 113

def close
  $log.debug " INSIDE CLOSE, #{@stop_ncurses_on_close} "
  @window.destroy if @window
  $log.debug " INSIDE CLOSE, #{@stop_ncurses_on_close} "
  if @stop_ncurses_on_close
    Canis::stop_ncurses
    $log.debug " CLOSING NCURSES"
  end
  $log.debug " CLOSING APP"
end

#field_help_textObject

displays help_text associated with field. 2011-10-15



301
302
303
304
305
306
307
308
309
310
# File 'lib/canis/core/util/app.rb', line 301

def field_help_text
  f = @form.get_current_field
  if f.respond_to?('help_text')
    h = f.help_text
    h = "No help text defined for this field.\nTry F1, or press '?' for key-bindings." unless h
    textdialog "#{h}", :title => "Widget Help Text"
  else
    alert "Could not get field #{f} or does not respond to helptext. Try F1 or '?'"
  end
end

#get_all_commandsObject



256
257
258
259
260
261
262
# File 'lib/canis/core/util/app.rb', line 256

def get_all_commands
  opts = @_system_commands.dup
  if respond_to? :get_commands
    opts.push(*get_commands())
  end
  opts
end

#get_bindingObject

used only by LiveConsole, if enables in an app, usually only during testing.



219
220
221
# File 'lib/canis/core/util/app.rb', line 219

def get_binding
  return binding()
end

#get_command_from_user(choices = ["quit","help", "suspend", "shell_output"]) ⇒ Object

prompts user for a command. we need to get this back to the calling app or have some block stuff TODO Actually, this is naive, you would want to pass some values in like current data value or lines ?? Also may want command completion, or help so all commands can be displayed NOTE: This is gonna change very soon - 2012-01-8



317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'lib/canis/core/util/app.rb', line 317

def get_command_from_user choices=["quit","help", "suspend", "shell_output"]
  @_command_history ||= Array.new
  str = rb_gets("Cmd: ", choices) { |q| q.default = @_previous_command; q.history = @_command_history }
          @_command_history << str unless @_command_history.include? str
  # shell the command
  if str =~ /^!/
    str = str[1..-1]
    suspend(false) { 
      #system(str); 
      $log.debug "XXX STR #{str}  " if $log.debug? 

      output=`#{str}`
      system("echo ' ' ");
      $log.debug "XXX output #{output} " if $log.debug? 
      system("echo '#{output}' ");
      system("echo Press Enter to continue.");
      system("read"); 
    }
    return nil # i think
  else
    # TODO
    # here's where we can take internal commands
    #alert "[#{str}] string did not match :!"
    str = str.to_s #= str[1..-1]
    cmdline = str.split
    cmd = cmdline.shift #.to_sym
    return unless cmd # added 2011-09-11 FFI
    f = @form.get_current_field
    if respond_to?(cmd, true)
      if cmd == "close"
        throw :close # other seg faults in del_panel window.destroy executes 2x
      else
        res = send cmd, *cmdline
      end
    elsif f.respond_to?(cmd, true)
      res = f.send(cmd, *cmdline)
    else
      alert "App: #{self.class} does not respond to #{cmd} "
      ret = false
      # what is this execute_this: some kind of general routine for all apps ?
      ret = execute_this(cmd, *cmdline) if respond_to?(:execute_this, true)
      rb_puts("#{self.class} does not respond to #{cmd} ", :color_pair => $promptcolor) unless ret
      # should be able to say in red as error
    end
  end
end

#hline(config = {}) ⇒ Object

displays a horizontal line takes col (column to start from) from current stack take row from app_row

requires width to be passed in config, else defaults to 20

Examples:

hline :width => 55  


384
385
386
387
388
389
390
391
392
393
394
395
396
# File 'lib/canis/core/util/app.rb', line 384

def hline config={}
  raise "I think this is unused. removed if this does not raise 2014-08-29 - 12:43 "
  row = config[:row] || @app_row
  width = config[:width] || 20
  _position config
  col = config[:col] || 1
  @color_pair = config[:color_pair] || $datacolor
  @attrib = config[:attrib] || Ncurses::A_NORMAL
  @window.attron(Ncurses.COLOR_PAIR(@color_pair) | @attrib)
  @window.mvwhline( row, col, FFI::NCurses::ACS_HLINE, width)
  @window.attron(Ncurses.COLOR_PAIR(@color_pair) | @attrib)
  @app_row += 1
end

#init_varsObject



99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/canis/core/util/app.rb', line 99

def init_vars
  @quit_key ||= FFI::NCurses::KEY_F10
  # actually this should be maintained inside ncurses pack, so not loaded 2 times.
  # this way if we call an app from existing program, App won't start ncurses.
  unless $ncurses_started
    init_ncurses
  end
  $lastline = Ncurses.LINES - 1
  unless $log
    logpath=ENV["CANIS_LOG_PATH"]
    $log = create_logger(logpath || "/dev/null")
  end
end

#keypress(&block) ⇒ Object

returns a symbol of the key pressed e.g. :C_c for Ctrl-C :Space, :bs, :M_d etc NOTE 2014-08-15 Trying with just string returned by keycode_tos This should allow for simpler apps that want to handle keys perhaps taken from a config file

rather than bind each key manually.


209
210
211
# File 'lib/canis/core/util/app.rb', line 209

def keypress &block
 @keyblock = block
end

#loggerObject



112
# File 'lib/canis/core/util/app.rb', line 112

def logger; return $log; end

#loop(&block) ⇒ Object

This method is called by run, and thus in most cases this is what is used. run calls this without a block not sure, but user shuld be able to trap keystrokes if he wants but do i still call handle_key if he does, or give him total control. But loop is already called by framework



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
# File 'lib/canis/core/util/app.rb', line 129

def loop &block
  @form.repaint
  @window.wrefresh
  Ncurses::Panel.update_panels
  @break_key = ?\C-q.getbyte(0)
  # added this extra loop since from some places we exit using throw :close
  # amd that was in a much higher place, and was getting us right out, with
  # no chance of user canceling quit. This extra loop allows us to remain
  # added on 2011-11-24 
  while true
    catch :close do
      while((ch = @window.getchar()) != 999 )
        if ch == @break_key || ch == @quit_key
          break
        end


        # 2014-08-19 - 22:51 commented next line, too much choice. keep it simple. delete in a month FIXME
        #yield ch if block # <<<----

        # this is what the user should have control ove. earlier we would put this in
        # a try catch block so user could do what he wanted with the error. Now we
        # need to get it to him somehow, perhaps through a block or on_error event
        begin
          # execute a code block so caller program can handle keys from a hash or whatever.
          # NOTE: these keys will not appear in help
          # FIXME : ideally if its just a hash, we should allow user to give it to form
          #  or widget which it will use, or merge, and be able to print help from
          if @keyblock
            str = keycode_tos ch
            # why did we ever want to convert to a symbol. why not just pass it as is.
            #@keyblock.call(str.gsub(/-/, "_").to_sym) # not used ever
            ret = @keyblock.call(str) 
            if ret
              @form.repaint 
              next
            end
          end
          @form.handle_key ch
        rescue => err
          $log.debug( "app.rb handle_key rescue reached ")
          $log.debug( err.to_s) 
          $log.debug(err.backtrace.join("\n")) 
          textdialog [err.to_s, *err.backtrace], :title => "Exception"
        end
        @window.wrefresh
      end
    end # catch
    stopping = @window.fire_close_handler
    @window.wrefresh
    break if stopping.nil? || stopping
  end # while
end

#message(text) ⇒ Object

updates a global var with text. Calling app has to set up a Variable with that name and attach to a label so it can be printed.



214
215
216
# File 'lib/canis/core/util/app.rb', line 214

def message text
  $status_message.value = text # trying out 2011-10-9 
end

#safe_loop(&block) ⇒ Object

if calling loop separately better to call this, since it will shut off ncurses and print error on screen. UNUSED



185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
# File 'lib/canis/core/util/app.rb', line 185

def safe_loop &block
  begin
    loop &block
  rescue => ex
    $log.debug( "APP.rb rescue reached ")
    $log.debug( ex) if ex
    $log.debug(ex.backtrace.join("\n")) if ex
  ensure
    close
    # putting it here allows it to be printed on screen, otherwise it was not showing at all.
    if ex
      puts "========== EXCEPTION =========="
      p ex 
      puts "==============================="
      puts(ex.backtrace.join("\n")) 
    end
  end
end

#suspend(clear = true) ⇒ Object

suspends curses so you can play around on the shell or in cooked mode like Vim does. Expects a block to be passed. Purpose: you can print some stuff without creating a window, or just run shell commands without coming out. NOTE: if you pass clear as true, then the screen will be cleared and you can use puts or print to print. You may have to flush. However, with clear as false, the screen will not be cleared. You will have to print using printw, and if you expect user input you must do a “system /bin/stty sane” If you print stuff, you will have to put a getch() or system(“read”) to pause the screen.



234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/canis/core/util/app.rb', line 234

def suspend clear=true
  return unless block_given?
  Ncurses.def_prog_mode
  if clear
    Ncurses.endwin 
    # NOTE: avoid false since screen remains half off
    # too many issues
  else
    system "/bin/stty sane"
  end
  yield if block_given?
  Ncurses.reset_prog_mode
  if !clear
    # Hope we don't screw your terminal up with this constantly.
    Canis::stop_ncurses
    Canis::start_ncurses  
    #@form.reset_all # not required
  end
  @form.repaint
  @window.wrefresh
  Ncurses::Panel.update_panels
end