From 57215e11912c84fade60e36637422ce30d9abc13 Mon Sep 17 00:00:00 2001 From: Correl Roush Date: Fri, 29 Feb 2008 15:39:44 +0000 Subject: [PATCH] A few bug fixes and a whole lot of documentation Mantis: 2691 git-svn-id: file:///srv/svn/scanner/trunk@16 a0501263-5b7a-4423-a8ba-1edf086583e7 --- ncurses/example.php | 16 ++ ncurses/ncurses.php | 392 +++++++++++++++++++++++++++++++++++++++----- scanner.php | 24 +-- 3 files changed, 383 insertions(+), 49 deletions(-) diff --git a/ncurses/example.php b/ncurses/example.php index 5da6385..c1b789e 100644 --- a/ncurses/example.php +++ b/ncurses/example.php @@ -1,6 +1,22 @@ +* @copyright Copyright (c) 2008, Correl J. Roush +* @version 0.1 +* +* @package Nc +*/ + +/** +* PHP ncurses application +* +* @package Nc +*/ +abstract class NcApp { var $screen; - function __construct( $echo = false, $cursor = false ) { + /** + * Constructor + * + * Initializes the ncurses environment, as well as the fullscreen window {@link $screen} + * + * @param boolean $echo Echo keyboard input to the screen + * @param boolean $cursor Display the cursor on the screen + */ + public function __construct( $echo = false, $cursor = false ) { ncurses_init(); $echo ? ncurses_echo() : ncurses_noecho(); ncurses_curs_set( (bool)$cursor ); @@ -10,31 +36,91 @@ class NcApp { ncurses_refresh(); $this->run(); } - function __destruct() { + /** + * Destructor + * + * Clears the screen and ends the ncurses session + */ + public function __destruct() { ncurses_clear(); ncurses_refresh(); ncurses_end(); } - function run() { - } + /** + * This is a placeholder function for application code + */ + abstract function run(); } +/** +* Ncurses window +* +* Provides a basic window object. A border can be optionally enabled if the window +* is large enough to accomodate it, and is enabled by default. If a title is set, +* it will be visible at the top of the border if one exists. +* +* If a parent window is provided, the window will be registered as a child of the +* parent, and will be relatively positioned to the parent. +* +* @package Nc +*/ class NcWindow { + /** + * @var resource nc_window resource for the border window, if one exists + */ var $frame; + /** + * @var resource nc_window resource for the container window + */ var $window; + /** + * @var array nc_panel resources for the window and its container + */ var $panels = array(); + /** + * @var array children array of child NcWindow references + */ var $children = array(); + /** + * @var NcWindow reference to this object's direct parent, if one exists + */ var $parent = false; + /** + * @var integer Absolute column position of the window + */ var $x; + /** + * @var integer Absolute row position of the window + */ var $y; + /** + * @var integer Width of contained window + */ var $width; + /** + * @var integer Height of contained window + */ var $height; + /** + * @var string Window title + */ var $title; - function __construct( &$parent, $height, $width, $y, $x, $framed = true ) { + /** + * Constructor + * + * Builds the requested ncurses window. + * + * @param NcWindow $parent Parent window + * @param integer $height Height + * @param integer $width Width + * @param integer $y Row + * @param integer $x Column + * @param boolean $framed Include a frame (border). Required for window titles. + */ + public function __construct( $parent, $height, $width, $y, $x, $framed = true ) { if( $parent instanceof NcWindow ) { $this->parent = $parent; - //TODO: Find out why this drives php nuts at script termination $this->parent->add_child( $this ); $x += $parent->x; $y += $parent->y; @@ -66,7 +152,10 @@ class NcWindow { $this->panels[] = ncurses_new_panel( $this->window ); ncurses_update_panels(); } - function __destruct() { + /** + * Destructor + */ + public function __destruct() { foreach( $this->panels as $id => $panel ) { ncurses_del_panel( $this->panels[$id] ); } @@ -75,7 +164,16 @@ class NcWindow { ncurses_delwin( $this->frame ); } } - function title( $value = false ) { + /** + * Set or retrieve a window title + * + * Sets window title to the value provided, returns the current window title + * if one is not. + * + * @param string $value New window title + * @return string Window title + */ + public function title( $value = false ) { if( $value === false ) { return $this->title; } elseif( $this->frame !== false ) { @@ -86,13 +184,37 @@ class NcWindow { ncurses_doupdate(); } } - function attribute_on( $attribute ) { + /** + * Activate an ncurses output attribute + * + * @param integer NCURSES_A_* constant + */ + public function attribute_on( $attribute ) { ncurses_wattron( $this->window, $attribute ); } - function attribute_off( $attribute ) { + /** + * Deactivate an ncurses output attribute + * + * @param integer NCURSES_A_* constant + */ + public function attribute_off( $attribute ) { ncurses_wattroff( $this->window, $attribute ); } - function write( $y, $x, $text, $update = true ) { + /** + * Write text to the window + * + * Writes text to the window at the specified coordinates. + * Text is truncated to prevent it overflowing off the side of the window. If + * the text contains newlines, it is split and each new line will continue from + * the same x position as the first, rather than wrapping back to the far left + * side of the window as ncurses normally would. + * + * @param integer $y Row + * @param integer $x Column + * @param string $text Text to write + * @param boolean $update Update the window upon completion + */ + public function write( $y, $x, $text, $update = true ) { $y = $y < 0 ? $this->height + $y : $y; $x = $x < 0 ? $this->width + $x : $x; $lines = preg_split( '/\r?(\n|\r)/', $text ); @@ -105,7 +227,16 @@ class NcWindow { ncurses_doupdate(); } } - function write_centered( $y, $text, $update = true ) { + /** + * Write centered text + * + * Writes text centered horizontally within the window on the specified line. + * + * @param integer $y Row + * @param string $text Text to write + * @param boolean $update Update the window upon completion + */ + public function write_centered( $y, $text, $update = true ) { $this->write( $y, floor( $this->width / 2 ) - floor( strlen( $text ) / 2 ), @@ -113,20 +244,55 @@ class NcWindow { $update ); } - function write_fixed( $y, $x, $text, $width = 0, $update = true ) { + /** + * Write fixed-width text + * + * Writes a string truncated or padded with spaces to fill the requested width. + * If the width is unspecified or zero, the width is defined as the length from + * the starting coordinate to the right edge of the window. + * + * @param integer $y Row + * @param integer $x Column + * @param string $text Text to write + * @param integer $width Field length + * @param boolean $update Update the window upon completion + */ + public function write_fixed( $y, $x, $text, $width = 0, $update = true ) { $width = $width > 0 ? $width : $this->width - $x; $this->write( $y, $x, $this->_string_fixed( $text, $width ), $update ); } - function _string_fixed( $text, $width = 0 ) { + /** + * Build a fixed-width string + * + * Truncates a string if it exceeds the specified width, pads it with spaces + * if it is too short. + * + * @param string $text Text to format + * @param integer $width Field length + * @return string Fixed-width string + */ + protected function _string_fixed( $text, $width = 0 ) { $width = $width < 0 ? 0 : $width; $text = substr( $text, 0, $width ); $text .= str_repeat( ' ', $width - strlen( $text ) ); return $text; } - function add_child( $child ) { + /** + * Assign a window as a child of this window + * + * Children of a window are hidden and shown along with their parent widget. + * + * @param NcWindow $child Child window + */ + public function add_child( $child ) { $this->children[] = $child; } - function hide( $update = true ) { + /** + * Hide the window + * + * @param boolean $update Update the window upon completion + */ + public function hide( $update = true ) { foreach( $this->panels as $panel ) { ncurses_hide_panel( $panel ); } @@ -138,22 +304,42 @@ class NcWindow { ncurses_doupdate(); } } - function show( $update = true ) { + /** + * Show the window + * + * @param boolean $update Update the window upon completion + */ + public function show( $update = true ) { foreach( $this->panels as $panel ) { ncurses_show_panel( $panel ); } foreach( $this->children as $child ) { $child->show( false ); } - ncurses_update_panels(); - ncurses_doupdate(); + if( $update ) { + ncurses_update_panels(); + ncurses_doupdate(); + } } - function erase() { + /** + * Clear the window's contents + * + * @param boolean $update Update the window upon completion + */ + public function erase( $update = true ) { ncurses_werase( $this->window ); - ncurses_wrefresh( $this->window ); - ncurses_doupdate(); + if( $update ) { + ncurses_wrefresh( $this->window ); + ncurses_doupdate(); + } } - function get_char( $flush = true ) { + /** + * Read a character from the keyboard and return it + * + * @param boolean $flush Flush the input buffer before requesting a key + * @return integer Keycode + */ + public function get_char( $flush = true ) { if( $flush ) { ncurses_flushinp(); } @@ -162,18 +348,50 @@ class NcWindow { } } +/** +* Progress Bar +* +* @package Nc +*/ class NcProgressBar extends NcWindow { + /** + * @var float Maximum value + */ var $max; + /** + * @var float Current value + */ var $value; + /** + * @var boolean Show percentage + */ var $show_pct; - function __construct( &$parent, $width, $y, $x, $max = 100, $show_pct = true ) { + /** + * Constructor + * + * Creates a new progress bar widget + * + * @param NcWindow $parent Parent window + * @param integer $width Width + * @param integer $y Row + * @param integer $x Column + * @param float $max Maximum value + * @param boolean $show_pct Display the percentage alongside the progress bar + */ + public function __construct( &$parent, $width, $y, $x, $max = 100, $show_pct = true ) { parent::__construct( $parent, 1, $width, $y, $x, false ); $this->max = $max; $this->show_pct = $show_pct; $this->pos( 0 ); } - function pos( $value = false ) { + /** + * Set or get the current value + * + * @param float $value New value + * @return float Current value + */ + public function pos( $value = false ) { if( $value === false ) { return $this->value; } else { @@ -193,7 +411,13 @@ class NcProgressBar extends NcWindow { ncurses_doupdate(); } } - function max( $value = false ) { + /** + * Get or set maximum value + * + * @param float $value New maximum + * @return float Current maximum + */ + public function max( $value = false ) { if( $value === false ) { return $this->max; } else { @@ -203,18 +427,49 @@ class NcProgressBar extends NcWindow { } } +/** +* Text Input +* +* @package Nc +*/ class NcTextInput extends NcWindow { + /** + * @var string Current value + */ var $value = ''; + /** + * @var boolean Active + */ var $active = false; + /** + * @var string Perl regular expression for filtering input + */ var $filter = false; - function __construct( &$parent, $width, $y, $x, $value = '', $filter = false ) { + /** + * Constructor + * + * Creates a new text input widget + * + * @param NcWindow $parent Parent window + * @param integer $width Width + * @param integer $y Row + * @param integer $x Column + * @param string $value Initial value + * @param string $filter Perl regular expression for filtering input + */ + public function __construct( &$parent, $width, $y, $x, $value = '', $filter = false ) { parent::__construct( $parent, 1, $width, $y, $x, false ); $this->value = $value; $this->filter = $filter !== false && @preg_match( $filter, '' ) !== false ? $filter : false; $this->update(); } - function update() { + /** + * Update the input control on the screen + * + * Widget is highlighted when active + */ + public function update() { $this->attribute_on( NCURSES_A_UNDERLINE ); if( $this->active ) { $this->attribute_on( NCURSES_A_REVERSE ); @@ -223,14 +478,26 @@ class NcTextInput extends NcWindow { $this->attribute_off( NCURSES_A_UNDERLINE ); $this->attribute_off( NCURSES_A_REVERSE ); } - function value( $value = false ) { + /** + * Get or set value + */ + public function value( $value = false ) { if( $value === false ) { return $this->value; } else { $this->value = $value; } } - function get() { + /** + * Activate input widget and accept input + * + * Input ends when the user presses the enter key. + * If a filter has been set and the input does not pass the filter, the value + * reverts to the previous value, and this function returns false. + * + * @return string|boolean Text entered, or false + */ + public function get() { $this->active = true; $this->update(); while( $this->active ) { @@ -254,18 +521,56 @@ class NcTextInput extends NcWindow { } } +/** +* Table View +* +* @package Nc +*/ class NcTableView extends NcWindow { + /** + * @var array Column headings + */ var $columns; + /** + * @var array Recordset + */ var $records; + /** + * @var integer Currently selected record index + */ var $selected; - function __construct( &$parent, $height, $width, $y, $x, $params = array() ) { + /** + * Constructor + * + * Creates a new table view + * + * @param NcWindow $parent Parent window + * @param integer $height Height + * @param integer $width Width + * @param integer $y Row + * @param integer $x Column + * @param array Array of optional parameters, as follows: + * array( + * 'columns' => array( 'key' => 'Column Name', ... ), + * 'records' => array( array( 'key' => 'value', ... ), ... ) + * ) + */ + public function __construct( $parent, $height, $width, $y, $x, $params = array() ) { parent::__construct( $parent, $height, $width, $y, $x ); $params = !is_array( $params ) ? array() : $params; $this->columns = isset( $params['columns'] ) && is_array( $params['columns'] ) ? $params['columns'] : array(); $this->records = isset( $params['records'] ) && is_array( $params['records'] ) ? array_values( $params['records'] ) : array(); } - function update( $selected = 0 ) { + /** + * Redraw the table and select a record + * + * Redraws the table with the specified record selected and the view scrolled + * accordingly. + * + * @param integer $selected Selected row + */ + public function update( $selected = 0 ) { $selected = $selected >= 0 ? $selected : 0; $selected = $selected < count( $this->records ) ? $selected : count( $this->records ) - 1; $this->selected = $selected; @@ -333,16 +638,27 @@ class NcTableView extends NcWindow { ncurses_wvline( $this->window, NCURSES_ACS_VLINE, 1 ); $this->attribute_off( NCURSES_A_UNDERLINE ); // Highlighted Row - ncurses_wmove( $this->window, $selected - $offset + 1, $x ); - $this->attribute_on( NCURSES_A_REVERSE ); - ncurses_wvline( $this->window, NCURSES_ACS_VLINE, 1 ); - $this->attribute_off( NCURSES_A_REVERSE ); + if( count( $this->records ) > 0 ) { + ncurses_wmove( $this->window, $selected - $offset + 1, $x ); + $this->attribute_on( NCURSES_A_REVERSE ); + ncurses_wvline( $this->window, NCURSES_ACS_VLINE, 1 ); + $this->attribute_off( NCURSES_A_REVERSE ); + } } // Finally, update ncurses_wrefresh( $this->window ); ncurses_doupdate(); } - function load( $records ) { + /** + * Load a recordset + * + * Recordset should be an array in the following format: + * array( array( 'key' => 'value', ... ), ... ) + * + * @param array $records Recordset + * @return boolean True if recordset loaded successfully, false otherwise + */ + public function load( $records ) { if( !is_array( $records ) ) { return false; } diff --git a/scanner.php b/scanner.php index dfc0b7e..c6e6def 100644 --- a/scanner.php +++ b/scanner.php @@ -368,17 +368,19 @@ if( $curses ) { break; case 10: case 13: - $nc_fault_info = new NcWindow( $nc_main, -10, -10, 5, 5 ); - $fault = &$faults[$nc_faults->selected]; - $nc_fault_info->attribute_on( NCURSES_A_BOLD ); - $nc_fault_info->write_centered( 0, 'Fault Information' ); - $nc_fault_info->write( 3, 0, "Module:\nLevel:\nFilename:\nLine Number:\nAuthor:\nRevision:\nReason:\n\nContext:" ); - $nc_fault_info->attribute_off( NCURSES_A_BOLD ); - $fault['object']['context'] = trim( $fault['object']['context'] ); - $nc_fault_info->write( 3, 20, "{$fault['module']}\n{$fault['level']}\n{$fault['file']}\n{$fault['line']}\n{$fault['author']}\n{$fault['revision']}\n{$fault['reason']}\n\n{$fault['object']['context']}" ); - $nc_fault_info->get_char(); - $nc_fault_info->hide(); - unset( $nc_fault_info ); + if( count( $nc_faults->records ) > 0 ) { + $nc_fault_info = new NcWindow( $nc_main, -10, -10, 5, 5 ); + $fault = &$faults[$nc_faults->selected]; + $nc_fault_info->attribute_on( NCURSES_A_BOLD ); + $nc_fault_info->write_centered( 0, 'Fault Information' ); + $nc_fault_info->write( 3, 0, "Module:\nLevel:\nFilename:\nLine Number:\nAuthor:\nRevision:\nReason:\n\nContext:" ); + $nc_fault_info->attribute_off( NCURSES_A_BOLD ); + $fault['object']['context'] = trim( $fault['object']['context'] ); + $nc_fault_info->write( 3, 20, "{$fault['module']}\n{$fault['level']}\n{$fault['file']}\n{$fault['line']}\n{$fault['author']}\n{$fault['revision']}\n{$fault['reason']}\n\n{$fault['object']['context']}" ); + $nc_fault_info->get_char(); + $nc_fault_info->hide(); + unset( $nc_fault_info ); + } break; case ord( 's' ): case ord( 'S' );