Revision
24
Author
emsmith
Date
2006-10-17 17:58:34 -0700 (Tue, 17 Oct 2006)

Log Message

Character window is shaping up - need to finish the todo list yet

Modified Paths

Added Paths

Removed Paths

Diff

Modified: desktop/trunk/Writer/lib/action.class.php (23 => 24)


--- desktop/trunk/Writer/lib/action.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/action.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -1,10 +1,9 @@
 <?php
 /**
- * action.class.php - Collection of actions for project
+ * action.class.php - Extends gtkaction
  *
- * doesn't use GtkAction at this point, but performs basically the
- * same type of operations - actions linked with a tooltip, callback, mnuemonic,
- * optional accel and image that you can call getMenu or getToolbar on
+ * gets the tooltips set right when fetching a toolbar/menu item and adds additional
+ * properties (set by constructor) for quick creation
  *
  * This is released under the GPL, see license.txt for details
  *
@@ -21,737 +20,56 @@
  */
 
 /**
- * Action - holds all menu/toolbar actions for the project
+ * Action - subclasses GtkAction
  *
- * use getMenu(id) or getToolbar(id), also has a complete menu
- * building function
+ * fixes the menu and toolbar item fetching to have working tooltips and
+ * automatically registers callbacks
  */
-class Action
+class Action extends GtkAction
 {
-
 	/**
-	 * singleton instance for this class
-	 * @var $singleton instanceof Action
-	 */
-	static public $singleton;
-
-	/**
-	 * current gtkacceleratorgroup
-	 * @var $acc object instanceof GtkAccelGroup
-	 */
-	protected $acc;
-
-	/**
-	 * tooltips object to use
-	 * @var $tooltips object instanceof Tooltips
-	 */
-	protected $tooltips;
-
-	/**
-	 * Multi-dim array of information for all actions
-	 * @var $actions array
-	 */
-	protected $actions = array(
-	'file' => array(
-		'new' => array(
-			'label' => '_New',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_N,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-new',
-			'class' => 'Project',
-			'method' => 'newProject',
-			'tooltip' => 'Create blank writer project',
-			'sensitive' => TRUE,
-			),
-		'wizard' => array(
-			'label' => '_Wizard',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'wizard',
-			'class' => 'Project',
-			'method' => 'wizardProject',
-			'tooltip' => 'Create a writer project using the wizard',
-			'sensitive' => TRUE,
-			),
-		'open' => array(
-			'label' => '_Open',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_O,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-open',
-			'class' => 'Project',
-			'method' => 'openProject',
-			'tooltip' => 'Open writer project',
-			'sensitive' => TRUE,
-			),
-		'close' => array(
-			'label' => '_Close',
-			'ellipse' => NULL,
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'gtk-close',
-			'class' => 'Project',
-			'method' => 'closeProject',
-			'tooltip' => 'Close currently open project',
-			'sensitive' => FALSE,
-			),
-		'delete' => array(
-			'label' => '_Delete',
-			'ellipse' => NULL,
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'gtk-delete',
-			'class' => 'Project',
-			'method' => 'deleteProject',
-			'tooltip' => 'Delete currently open project',
-			'sensitive' => FALSE,
-			),
-		'save' => array(
-			'label' => '_Save',
-			'ellipse' => NULL,
-			'accel_key' => Gdk::KEY_S,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-save',
-			'class' => 'Project',
-			'method' => 'saveProject',
-			'tooltip' => 'Save current writer project',
-			'sensitive' => FALSE,
-			),
-		'save-as' => array(
-			'label' => 'Save _As',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'gtk-save-as',
-			'class' => 'Project',
-			'method' => 'saveAsProject',
-			'tooltip' => 'Save current project with a new name',
-			'sensitive' => FALSE,
-			),
-		'revert-to-saved' => array(
-			'label' => 'Rever_t to Saved',
-			'ellipse' => NULL,
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'gtk-revert-to-saved',
-			'class' => 'Project',
-			'method' => 'revertProject',
-			'tooltip' => 'Revert project to the last saved state',
-			'sensitive' => FALSE,
-			),
-		'page-setup' => array(
-			'label' => 'Page _Setup',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'configure',
-			'class' => 'Printer',
-			'method' => 'pageSetup',
-			'tooltip' => 'Change printing preferences and options',
-			'sensitive' => TRUE,
-			),
-		'print-preview' => array(
-			'label' => 'P_rint Preview',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'gtk-print-preview',
-			'class' => 'Printer',
-			'method' => 'printPreview',
-			'tooltip' => 'View selected chapters before printing',
-			'sensitive' => FALSE,
-			),
-		'print' => array(
-			'label' => '_Print',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_P,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-print',
-			'class' => 'Printer',
-			'method' => 'quickPrint',
-			'tooltip' => 'Print selected chapters',
-			'sensitive' => FALSE,
-			),
-		'quit' => array(
-			'label' => '_Quit',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_Q,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-quit',
-			'class' => 'ProjectView',
-			'method' => 'quit',
-			'tooltip' => 'Exit writer application',
-			'sensitive' => TRUE,
-			),
-		),
-	'edit' => array(
-		'undo' => array(
-			'label' => '_Undo',
-			'ellipse' => NULL,
-			'accel_key' => Gdk::KEY_Z,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-undo',
-			'class' => 'Edit',
-			'method' => 'undo',
-			'tooltip' => 'Undo last action',
-			'sensitive' => FALSE,
-			),
-		'redo' => array(
-			'label' => '_Redo',
-			'ellipse' => NULL,
-			'accel_key' => Gdk::KEY_Y,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-redo',
-			'class' => 'Edit',
-			'method' => 'redo',
-			'tooltip' => 'Redo last action',
-			'sensitive' => FALSE,
-			),
-		'cut' => array(
-			'label' => 'Cu_t',
-			'ellipse' => NULL,
-			'accel_key' => Gdk::KEY_X,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-cut',
-			'class' => 'Edit',
-			'method' => 'cut',
-			'tooltip' => 'Remove selected item and place on clipboard',
-			'sensitive' => FALSE,
-			),
-		'copy' => array(
-			'label' => '_Copy',
-			'ellipse' => NULL,
-			'accel_key' => Gdk::KEY_C,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-copy',
-			'class' => 'Edit',
-			'method' => 'copy',
-			'tooltip' => 'Copy selected item and place on clipboard',
-			'sensitive' => FALSE,
-			),
-		'paste' => array(
-			'label' => '_Paste',
-			'ellipse' => NULL,
-			'accel_key' => Gdk::KEY_V,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-paste',
-			'class' => 'Edit',
-			'method' => 'paste',
-			'tooltip' => 'Paste item from the clipboard',
-			'sensitive' => FALSE,
-			),
-		'clear' => array(
-			'label' => 'Cle_ar',
-			'ellipse' => NULL,
-			'accel_key' => Gdk::KEY_BackSpace,
-			'accel_mask' => 0,
-			'image' => 'gtk-clear',
-			'class' => 'Edit',
-			'method' => 'clear',
-			'tooltip' => 'Clear selected item',
-			'sensitive' => FALSE,
-			),
-		'select-all' => array(
-			'label' => '_Select All',
-			'ellipse' => NULL,
-			'accel_key' => Gdk::KEY_A,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-file',
-			'class' => 'Edit',
-			'method' => 'selectAll',
-			'tooltip' => 'Select all items',
-			'sensitive' => FALSE,
-			),
-		'find' => array(
-			'label' => '_Find',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_F,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-find',
-			'class' => 'Edit',
-			'method' => 'find',
-			'tooltip' => 'Searches for text',
-			'sensitive' => TRUE,
-			),
-		'replace' => array(
-			'label' => 'R_eplace',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_H,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-find-and-replace',
-			'class' => 'Edit',
-			'method' => 'replace',
-			'tooltip' => 'Searches and replace text',
-			'sensitive' => TRUE,
-			),
-		'goto' => array(
-			'label' => '_Goto',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_G,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'gtk-jump-to',
-			'class' => 'Edit',
-			'method' => 'goto',
-			'tooltip' => 'Jump to a specified item',
-			'sensitive' => TRUE,
-			),
-		),
-	'project' => array(
-		'import' => array(
-			'label' => '_Import',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'gtk-convert',
-			'class' => 'Project',
-			'method' => 'importProject',
-			'tooltip' => 'Import files to project',
-			'sensitive' => FALSE,
-			),
-		'export' => array(
-			'label' => '_Export',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_E,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'save-all',
-			'class' => 'Project',
-			'method' => 'exportProject',
-			'tooltip' => 'Export project to different formats',
-			'sensitive' => FALSE,
-			),
-		'version' => array(
-			'label' => '_Version',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'file-get',
-			'class' => 'Project',
-			'method' => 'versionProject',
-			'tooltip' => 'Create new version for project',
-			'sensitive' => FALSE,
-			),
-		'history' => array(
-			'label' => '_History',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'history',
-			'class' => 'Project',
-			'method' => 'historyProject',
-			'tooltip' => 'View project history and optionally change current version',
-			'sensitive' => FALSE,
-			),
-		'properties' => array(
-			'label' => 'P_roperties',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'gtk-properties',
-			'class' => 'Project',
-			'method' => 'propertiesProject',
-			'tooltip' => 'View and edit project information',
-			'sensitive' => FALSE,
-			),
-		),
-	'view' => array(
-		'characters' => array(
-			'label' => '_Characters',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_F3,
-			'accel_mask' => 0,
-			'image' => 'users',
-			'class' => 'Characters',
-			'method' => 'list',
-			'tooltip' => 'Character organization system',
-			'sensitive' => TRUE,
-			),
-		'places' => array(
-			'label' => '_Places',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_F4,
-			'accel_mask' => 0,
-			'image' => 'folder-home',
-			'class' => 'Places',
-			'method' => 'list',
-			'tooltip' => 'Place setting organization system',
-			'sensitive' => TRUE,
-			),
-		'editor' => array(
-			'label' => '_Editor',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_F5,
-			'accel_mask' => 0,
-			'image' => 'editor',
-			'class' => 'Editor',
-			'method' => 'list',
-			'tooltip' => 'Online story feedback system',
-			'sensitive' => TRUE,
-			),
-		'columns' => array(
-			'label' => 'Co_lumns',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'view-text',
-			'class' => 'ProjectView',
-			'method' => 'columns',
-			'tooltip' => 'Choose columns to view',
-			'sensitive' => TRUE,
-			),
-		'customize' => array(
-			'label' => 'Custo_mize',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'settings',
-			'class' => 'ProjectView',
-			'method' => 'customize',
-			'tooltip' => 'Customize your toolbars',
-			'sensitive' => TRUE,
-			),
-		),
-	'chapter' => array(
-		'new' => array(
-			'label' => '_New Chapter',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'bookmark-add',
-			'class' => 'Project',
-			'method' => 'newChapter',
-			'tooltip' => 'Create a new blank chapter in the current project',
-			'sensitive' => FALSE,
-			),
-		'edit' => array(
-			'label' => '_Edit Chapter',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'bookmark-edit',
-			'class' => 'Project',
-			'method' => 'editChapter',
-			'tooltip' => 'Edit currently selected chapter',
-			'sensitive' => FALSE,
-			),
-		'import' => array(
-			'label' => '_Import Chapter',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'bookmark-list',
-			'class' => 'Project',
-			'method' => 'importChapter',
-			'tooltip' => 'Create or overwrite a chapter by importing a file',
-			'sensitive' => FALSE,
-			),
-		'export' => array(
-			'label' => '_Export Chapter',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'bookmark-folder',
-			'class' => 'Project',
-			'method' => 'exportChapter',
-			'tooltip' => 'Export chapter to a file',
-			'sensitive' => FALSE,
-			),
-		'delete' => array(
-			'label' => '_Delete Chapter',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'bookmark',
-			'class' => 'Project',
-			'method' => 'deleteChapter',
-			'tooltip' => 'Delete selected chapter',
-			'sensitive' => FALSE,
-			),
-		'renumber' => array(
-			'label' => '_Renumber Chapters',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'gtk-sort-descending',
-			'class' => 'Project',
-			'method' => 'renumberChapters',
-			'tooltip' => 'Renumber selected chapters',
-			'sensitive' => FALSE,
-			),
-		'properties' => array(
-			'label' => '_Chapter Properties',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'bookmark-toolbar',
-			'class' => 'Project',
-			'method' => 'propertiesChapter',
-			'tooltip' => 'Edit chapter properties',
-			'sensitive' => FALSE,
-			),
-		),
-	'tools' => array(
-		'spelling' => array(
-			'label' => '_Spelling and Grammar',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_F7,
-			'accel_mask' => 0,
-			'image' => 'gtk-spell-check',
-			'class' => 'Project',
-			'method' => 'spellingGrammar',
-			'tooltip' => 'Spelling and grammar related tools',
-			'sensitive' => FALSE,
-			),
-		'reports' => array(
-			'label' => '_Reports',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'reports',
-			'class' => 'Project',
-			'method' => 'reports',
-			'tooltip' => 'Generate reports and charts about the projects',
-			'sensitive' => FALSE,
-			),
-		'storyboard' => array(
-			'label' => '_Storyboard',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_F2,
-			'accel_mask' => 0,
-			'image' => 'action',
-			'class' => 'Project',
-			'method' => 'storyboard',
-			'tooltip' => 'View scene storyboards',
-			'sensitive' => FALSE,
-			),
-		'notes' => array(
-			'label' => '_Notes',
-			'ellipse' => '...',
-			'accel_key' => Gdk::KEY_T,
-			'accel_mask' => Gdk::CONTROL_MASK,
-			'image' => 'notes',
-			'class' => 'Project',
-			'method' => 'reports',
-			'tooltip' => 'Open story notes',
-			'sensitive' => FALSE,
-			),
-		'preferences' => array(
-			'label' => '_Preferences',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'gtk-preferences',
-			'class' => 'ProjectView',
-			'method' => 'preferences',
-			'tooltip' => 'Set application wide preferences',
-			'sensitive' => TRUE,
-			),
-		),
-	'help' => array(
-		'help' => array(
-			'label' => '_Help',
-			'ellipse' => NULL,
-			'accel_key' => Gdk::KEY_F1,
-			'accel_mask' => 0,
-			'image' => 'help',
-			'class' => 'ProjectView',
-			'method' => 'help',
-			'tooltip' => 'View help files',
-			'sensitive' => TRUE,
-			),
-		'tutorials' => array(
-			'label' => '_Tutorials',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'contact',
-			'class' => 'ProjectView',
-			'method' => 'tutorials',
-			'tooltip' => 'View online tutorials',
-			'sensitive' => TRUE,
-			),
-		'articles' => array(
-			'label' => '_Articles',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'bookcase',
-			'class' => 'ProjectView',
-			'method' => 'articles',
-			'tooltip' => 'View online articles on writing',
-			'sensitive' => TRUE,
-			),
-		'website' => array(
-			'label' => '_Website',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'browser',
-			'class' => 'ProjectView',
-			'method' => 'website',
-			'tooltip' => 'Visit writer website',
-			'sensitive' => TRUE,
-			),
-		'support' => array(
-			'label' => '_Support',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'gtk-help',
-			'class' => 'ProjectView',
-			'method' => 'support',
-			'tooltip' => 'Writer support resources',
-			'sensitive' => TRUE,
-			),
-		'register' => array(
-			'label' => '_Register',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'user',
-			'class' => 'ProjectView',
-			'method' => 'register',
-			'tooltip' => 'Register for a writer account at callicore',
-			'sensitive' => TRUE,
-			),
-		'bugs' => array(
-			'label' => '_Bugs',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'bug',
-			'class' => 'ProjectView',
-			'method' => 'bugs',
-			'tooltip' => 'Report a bug',
-			'sensitive' => TRUE,
-			),
-		'updates' => array(
-			'label' => '_Software Updates',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'download',
-			'class' => 'ProjectView',
-			'method' => 'update',
-			'tooltip' => 'Check for writer software updates',
-			'sensitive' => TRUE,
-			),
-		'about' => array(
-			'label' => '_About',
-			'ellipse' => '...',
-			'accel_key' => NULL,
-			'accel_mask' => NULL,
-			'image' => 'gtk-about',
-			'class' => 'ProjectView',
-			'method' => 'about',
-			'tooltip' => 'Information about writer',
-			'sensitive' => TRUE,
-			),
-		),
-	);
-
-	/**
 	 * public function __construct
 	 *
 	 * creates tooltips, accelerator group, and assigns the singleton variable
 	 *
 	 * @return void
 	 */
-	public function __construct()
+	public function __construct($name, $label, $shortlabel, $tooltip, $image, $callback)
 	{
-		if(!is_null(self::$singleton))
-		{
-			throw new Exception('Action is a singleton class - use Action::singleton() to retrieve the current instance');
-		}
-
-		self::$singleton = $this;
-
-		$this->acc = new GtkAccelGroup();
-		$this->tooltips = Tooltips::singleton();
+		parent::__construct($name, Writer::i18n($label), Writer::i18n($tooltip), $image);
+		$this->set_property('short-label', Writer::i18n($shortlabel));
+		$this->connect('activate', $callback);
+		unset($name, $label, $shortlabel, $tooltip, $image, $callback);
 		return;
 	}
 
 	/**
-	 * public function getMenuItem
+	 * public function create_tool_item
 	 *
-	 * description
+	 * override so we can do the tooltip properly
 	 *
-	 * @param type $name about
-	 * @return type about
+	 * @return instanceof GtkToolItem
 	 */
-	public function getMenuItem($area, $id)
+	public function create_tool_item()
 	{
-		if(!isset($this->actions[$area]) || !isset($this->actions[$area][$id]))
-		{
-			return;
-		}
-		$action = $this->actions[$area][$id];
-		$item = new GtkImageMenuItem(_($action['label']) . $action['ellipse']);
-		if(!is_null($action['accel_key']))
-		{
-			$item->add_accelerator('activate', $this->acc, $action['accel_key'], $action['accel_mask'], Gtk::ACCEL_VISIBLE);
-			$label = new GtkAccelLabel($action['label']);
-			$label->set_accel_widget($item);
-		}
-		$item->set_image(GtkImage::new_from_stock($action['image'], THEME::$MENU));
-		$object = call_user_func(array($action['class'], 'singleton'));
-		$item->connect_simple('activate', array($object, $action['method']));
-		$item->set_sensitive($action['sensitive']);
-		$this->tooltips->set_tip($item, $action['tooltip']);
-		unset($object, $action);
-		return $item;
+		$widget = parent::create_tool_item();
+		$widget->set_tooltip(Tooltips::instance(), $this->get_property('tooltip'));
+		return $widget;
 	}
 
 	/**
-	 * public function getToolbarItem
+	 * public function create_menu_item
 	 *
 	 * description
 	 *
 	 * @param type $name about
 	 * @return type about
 	 */
-	public function getToolbarItem($area, $id)
+	public function create_menu_item()
 	{
-		if(!isset($this->actions[$area]) || !isset($this->actions[$area][$id]))
-		{
-			return;
-		}
-		$action = $this->actions[$area][$id];
-		$item = GtkToolButton::new_from_stock($action['image']);
-		$item->set_use_underline(TRUE);
-		$item->set_label(_($action['label']));
-		$this->tooltips->set_tip($item, $action['tooltip']);
-		$object = call_user_func(array($action['class'], 'singleton'));
-		$item->connect_simple('clicked', array($object, $action['method']));
-		$item->set_sensitive($action['sensitive']);
-		unset($object, $action);
-		return $item;
+		$widget = parent::create_menu_item();
+		Tooltips::instance()->set_tip($widget, $this->get_property('tooltip'));
+		return $widget;
 	}
-
-	/**
-	 * public function getAccel
-	 *
-	 * description
-	 *
-	 * @param type $name about
-	 * @return type about
-	 */
-	public function getAccel()
-	{
-		return $this->acc;
-	}
-
-	/**
-	 * public function singleton
-	 *
-	 * grab and return the instance
-	 *
-	 * @return object instanceof Theme
-	 */
-	static public function singleton()
-	{
-		return self::$singleton;
-	}
 }
 ?>
\ No newline at end of file

Added: desktop/trunk/Writer/lib/character/action.class.php (23 => 24)


--- desktop/trunk/Writer/lib/character/action.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/character/action.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -0,0 +1,156 @@
+<?php
+/**
+ * action.class.php - Collection of actions for character window
+ *
+ * because of broken tooltips, we have to subclass GtkAction
+ *
+ * This is released under the GPL, see license.txt for details
+ *
+ * @author       Elizabeth Smith <emsmith@callicore.net>
+ * @copyright    Elizabeth Smith (c)2006
+ * @link         http://callicore.net/writer
+ * @license      http://www.opensource.org/licenses/gpl-license.php GPL
+ * @version      $Id$
+ * @since        Php 5.2.0
+ * @package      callicore
+ * @subpackage   writer
+ * @category     lib
+ * @filesource
+ */
+
+/**
+ * CharacterAction - holds all actions for the character area
+ *
+ * manages actions real pretty like
+ */
+class CharacterAction
+{
+
+	/**
+	 * singleton instance for this class
+	 * @var $singleton instanceof CharacterWindow
+	 */
+	static protected $singleton;
+
+	/**
+	 * switches on to allow construct to occur
+	 * @var $check bool
+	 */
+	static protected $check = FALSE;
+
+	/**
+	 * Multi-dim array of information for all actions
+	 * @var $actions array
+	 */
+	protected $groups = array();
+
+	/**
+	 * public function __construct
+	 *
+	 * creates tooltips, accelerator group, and assigns the singleton variable
+	 *
+	 * @return void
+	 */
+	public function __construct()
+	{
+		if(self::$check == FALSE)
+		{
+			throw new Exception(Writer::i18n(
+			'%1$s is a singleton class - use %1$s::instance() to retrieve the current object',
+			'CharacterAction'));
+		}
+		self::$singleton = $this;
+
+		$acc = new GtkAccelGroup();
+		CharacterWindow::instance()->add_accel_group($acc);
+
+		$callback = CharacterWindow::instance();
+
+		// character actions
+		$group = new GtkActionGroup('character');
+		$action = new Action('add', '_Add', '_Add', 'Add new character',
+			'gtk-add', array($callback->treeview->get_model(), 'onNew'));
+		$action->set_accel_group($acc);
+		$group->add_action_with_accel($action, '<Control>n');
+
+		$action = new Action('edit', '_Edit', '_Edit', 'Edit selected character',
+			'gtk-edit', array($callback->treeview->get_model(), 'onEdit'));
+		$group->add_action($action);
+
+		$action = new Action('delete', '_Delete', '_Delete', 'Delete selected character',
+			'gtk-delete', array($callback->treeview->get_model(), 'onDelete'));
+		$action->set_accel_group($acc);
+		$group->add_action_with_accel($action, 'del');
+
+		$action = new Action('undelete', '_Undelete', '_Undelete', 'Undelete selected character',
+			'gtk-undelete', array($callback->treeview->get_model(), 'onUndelete'));
+		$action->set_accel_group($acc);
+		$group->add_action_with_accel($action, '<shift>del');
+
+		$action = new Action('save', '_Save', '_Save', 'Save all changes',
+			'gtk-save', array($callback->treeview->get_model(), 'onSave'));
+		$action->set_accel_group($acc);
+		$action->set_sensitive(FALSE);
+		$group->add_action_with_accel($action, '<ctrl>s');
+
+		$action = new Action('revert', '_Revert to Saved', '_Revert', 'Revert to saved state',
+			'gtk-revert-to-saved', array($callback->treeview->get_model(), 'onRevert'));
+		$action->set_accel_group($acc);
+		$action->set_sensitive(FALSE);
+		$group->add_action_with_accel($action, '<ctrl>r');
+
+		$this->groups['character'] = $group;
+
+		unset($group, $action, $acc, $callback);
+		return;
+	}
+
+	/**
+	 * public function getGroup
+	 *
+	 * get a specific action group
+	 *
+	 * @param string $name group label to search for
+	 * @return instanceof GtkActionGroup
+	 */
+	public function getGroup($name)
+	{
+		if(isset($this->groups[$name]))
+		{
+			return $this->groups[$name];
+		}
+		return;
+	}
+
+	/**
+	 * static public function instance
+	 *
+	 * this is how you "construct" a CharacterAction object
+	 *
+	 * @return object instanceof CharacterAction
+	 */
+	static public function instance()
+	{
+		if(is_null(self::$singleton))
+		{
+			self::$check = TRUE;
+			self::$singleton = new CharacterAction();
+			self::$check = FALSE;
+		}
+		return self::$singleton;
+	}
+
+	/**
+	 * public function __clone()
+	 *
+	 * disable cloning of a singleton
+	 *
+	 * @return void
+	 */
+	public function __clone()
+	{
+		throw new Exception(Writer::i18n('Cannot clone singleton object %s', 'CharacterAction'));
+		return;
+	}
+}
+?>
\ No newline at end of file
Property changes on: desktop/trunk/Writer/lib/character/action.class.php
___________________________________________________________________
Name: tsvn:logminsize
   + 15
Name: svn:keywords
   + Id
Name: svn:eol-style
   + LF

Added: desktop/trunk/Writer/lib/character/dao.class.php (23 => 24)


--- desktop/trunk/Writer/lib/character/dao.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/character/dao.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -0,0 +1,767 @@
+<?php
+/**
+ * dao.class.php - data access object for characters
+ *
+ * characters have basic information but can also have meta information
+ *
+ * This is released under the GPL, see license.txt for details
+ *
+ * @author       Elizabeth Smith <emsmith@callicore.net>
+ * @copyright    Elizabeth Smith (c)2006
+ * @link         http://callicore.net/writer
+ * @license      http://www.opensource.org/licenses/gpl-license.php GPL
+ * @version      $Id$
+ * @since        Php 5.2.0
+ * @package      callicore
+ * @subpackage   writer
+ * @category     lib
+ * @filesource
+ */
+
+/**
+ * CharacterDao - character data access object
+ *
+ * This can get a little messy because of the meta mapping
+ */
+class CharacterDao implements Iterator
+{
+	/**
+	 * stores character meta data
+	 * @var $meta array
+	 */
+	protected $meta = array();
+
+	/**
+	 * name => id map for metadata
+	 * @var $metamap array
+	 */
+	protected $metamap = array();
+
+	/**
+	 * id => name map for liststore
+	 * @var $listmap array
+	 */
+	protected $listmap = array();
+
+	/**
+	 * stores basic data
+	 * @var $data array
+	 */
+	protected $data = array();
+
+	/**
+	 * public function __construct
+	 *
+	 * creates empty object or finds object by id or name
+	 *
+	 * @param string|int $id id or name to find
+	 * @return void
+	 */
+	public function __construct($id = NULL)
+	{
+		$db = Db::instance();
+
+		try
+		{
+			$statement = $db->query('PRAGMA table_info("character")');
+			foreach($statement->fetchAll(PDO::FETCH_ASSOC) as $data)
+			{
+				$this->data[$data['name']] = $data['dflt_value'];
+				$this->listmap[] = $data['name'];
+			}
+			$this->listmap[] = 'color';
+			$this->listmap[] = 'saved';
+			$this->listmap[] = 'deleted';
+			// select all available metas and their default
+			$statement = $db->query('SELECT "id", "name", "default" from "character_meta"');
+			foreach($statement->fetchAll(PDO::FETCH_ASSOC) as $data)
+			{
+				$this->meta[$data['name']] = $data['default'];
+				$this->metamap[$data['name']] = $data['id'];
+				$this->listmap[] = $data['name'];
+			}
+			if(!is_null($id))
+			{
+				$sql = 'SELECT ' . implode(', ', array_map(array($db, 'identify'), array_keys($this->data))) . ' from "character" ';
+				$statement = $db->prepare($sql . 'WHERE id= :id');
+				$statement->execute(array(':id' => $id));
+				$data = $statement->fetch(PDO::FETCH_ASSOC);
+				if($data == FALSE)
+				{
+					$statement = $db->prepare($sql . 'WHERE name= :name');
+					$statement->execute(array(':name' => $id));
+					$data = $statement->fetch(PDO::FETCH_ASSOC);
+				}
+				if($data !== FALSE)
+				{
+					foreach($data as $key => $value)
+					{
+						$this->data[$key] = $value;
+					}
+					$statement = $db->prepare('SELECT "t1"."value", "t2"."name" FROM "character_has_character_meta" AS "t1" LEFT JOIN "character_meta" AS "t2" ON "t1"."character_meta_id_fk" = "t2"."id" WHERE "t1"."character_id_fk" = :id');
+					$statement->execute(array(':id' => $this->data['id']));
+					foreach($statement->fetchAll(PDO::FETCH_ASSOC) as $data)
+					{
+						$this->meta[$data['name']] = $data['value'];
+					}
+				}
+			}
+		}
+		catch(PDOException $e)
+		{
+			$info = $db->errorInfo();
+			unset($db, $statement, $e);
+			throw new Exception(Writer::i18n('Cannot save character: %s', $info[2]));
+		}
+
+		unset($statement, $db, $data, $sql, $id, $key, $value);
+		return;
+	}
+
+	/**
+	 * public function delete
+	 *
+	 * saves the changed information to the database
+	 *
+	 * @return void
+	 */
+	public function delete()
+	{
+		$db = Db::instance();
+
+		$db->beginTransaction();
+		try
+		{
+			if(!is_null($this->data['id']) && $this->data['id'] != FALSE)
+			{
+				// if id is int, see if it exists
+				$statement = $db->prepare('SELECT COUNT("id") FROM "character" WHERE "id" = :id');
+				$statement->execute(array(':id' => $this->data['id']));
+				$check = $statement->fetch(PDO::FETCH_COLUMN);
+			}
+			if(!isset($check) || $check == FALSE)
+			{
+				// otherwise lookup via name
+				$statement = $db->prepare('SELECT "id" FROM "character" WHERE "name" = :name');
+				$statement->execute(array(':name' => $this->data['name']));
+				$check = $statement->fetch(PDO::FETCH_COLUMN);
+			}
+			if($check !== FALSE)
+			{
+				// delete all meta data
+				$statement = $db->prepare('DELETE FROM "character_has_character_meta" WHERE "character_id_fk" = :id');
+				$statement->execute(array(':id' => $this->data['id']));
+				// grab order
+				$statement = $db->prepare('SELECT "order" FROM "character" WHERE "id" = :id');
+				$statement->execute(array(':id' => $this->data['id']));
+				$order = $statement->fetch(PDO::FETCH_COLUMN);
+				// delete main
+				$statement = $db->prepare('DELETE FROM "character" WHERE "id" = :id');
+				$statement->execute(array(':id' => $this->data['id']));
+				// all larger orders get decremented
+				$statement = $db->prepare('UPDATE "character" SET "order" = "order" - 1 WHERE "order" > :order');
+				$statement->execute(array(':order' => $order));
+			}
+		}
+		catch(PDOException $e)
+		{
+			unset($statement);
+			$db->rollback();
+			$info = $db->errorInfo();
+			unset($db, $e);
+			throw new Exception(Writer::i18n('Cannot save character: %s', $info[2]));
+		}
+		unset($statement);
+		$db->commit();
+		$this->__construct();
+		unset($db, $check, $order);
+		return;
+	}
+
+	/**
+	 * public function save
+	 *
+	 * removes a character record
+	 *
+	 * @return void
+	 */
+	public function save()
+	{
+		$db = Db::instance();
+
+		$db->beginTransaction();
+		try
+		{
+			// see if it's in the db to delete
+			if(!is_null($this->data['id']) && $this->data['id'] != FALSE)
+			{
+				// if id is int, see if it exists
+				$statement = $db->prepare('SELECT COUNT("id") FROM "character" WHERE "id" = :id');
+				$statement->execute(array(':id' => $this->data['id']));
+				$check = $statement->fetch(PDO::FETCH_COLUMN);
+			}
+			else
+			{
+				// otherwise lookup via name
+				$statement = $db->prepare('SELECT "id" FROM "character" WHERE "name" = :name');
+				$statement->execute(array(':name' => $this->data['name']));
+				$check = $statement->fetch(PDO::FETCH_COLUMN);
+			}
+			if($check === FALSE)
+			{
+				$statement = $db->query('SELECT MAX("order") FROM "character"');
+				$order = (int) $statement->fetch(PDO::FETCH_COLUMN) + 1;
+				// insert main and grab id
+				$statement = $db->prepare('INSERT INTO "character"("name", "order", "date_created", "date_edited") VALUES (:name, :order, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)');
+				$statement->execute(array(':name' => $this->data['name'], ':order' => $order));
+				$this->data['id'] = $db->lastInsertId();
+				// prepare and insert meta data in loop
+				$statement = $db->prepare('INSERT INTO "character_has_character_meta"("value","character_meta_id_fk", "character_id_fk") VALUES (:value, :metaid, :id)');
+				$statement->bindValue(':id', $this->data['id']);
+				$statement->bindParam(':metaid', $metaid);
+				$statement->bindParam(':value', $value);
+				foreach($this->meta as $key => $value)
+				{
+					$metaid = $this->metamap[$key];
+					$statement->execute();
+				}
+				if(!is_null($this->data['order']))
+				{
+					self::reorder($this->data['id'], $this->data['order']);
+				}
+				// refill non-tamperable, id, order, dates
+				$statement = $db->prepare('SELECT "order", "date_created", "date_edited" FROM "character" WHERE "id" = :id');
+				$statement->execute(array(':id' => $this->data['id']));
+				$data = $statement->fetch(PDO::FETCH_ASSOC);
+				foreach($data as $id => $value)
+				{
+					$this->data[$id] = $value;
+				}
+			}
+			else
+			{
+				$this->data['id'] = $check;
+				// main data update
+				$statement = $db->prepare('UPDATE "character" SET "name" = :name, "date_edited" = CURRENT_TIMESTAMP WHERE "id" = :id');
+				$statement->execute(array(':name' => $this->data['name'], ':id' => $this->data['id']));
+				// check and insert/update meta data
+				foreach($this->meta as $id => $value)
+				{
+					$check = $db->prepare('SELECT COUNT("id") FROM "character_has_character_meta" WHERE "character_meta_id_fk" = :metaid AND "character_id_fk" = :id');
+					$check->execute(array(':id' => $this->data['id'], ':metaid' => $this->metamap[$id]));
+					$check = (int) $check->fetch(PDO::FETCH_COLUMN);
+					if($check > 0)
+					{
+						$statement = $db->prepare('UPDATE "character_has_character_meta" SET "value" = :value WHERE "character_meta_id_fk" = :metaid AND "character_id_fk" = :id');
+						$statement->execute(array(':id' => $id, ':metaid' => $this->metamap[$id], ':value' => $value));
+					}
+					else
+					{
+						$statement = $db->prepare('INSERT INTO "character_has_character_meta"("value","character_meta_id_fk", "character_id_fk") VALUES (:value, :metaid, :id)');
+						$statement->execute(array(':id' => $id, ':metaid' => $this->metamap[$id], ':value' => $value));
+					}
+				}
+				// reorder
+				self::reorder($this->data['id'], $this->data['order']);
+				// refill non-tamperable, id, order, dates
+				$statement = $db->prepare('SELECT "order", "date_edited" FROM "character" WHERE "id" = :id');
+				$statement->execute(array(':id' => $this->data['id']));
+				$data = $statement->fetch(PDO::FETCH_ASSOC);
+				foreach($data as $id => $value)
+				{
+					$this->data[$id] = $value;
+				}
+			}
+		}
+		catch(PDOException $e)
+		{
+			unset($statement);
+			$db->rollback();
+			$info = $db->errorInfo();
+			unset($db, $e);
+			throw new Exception(Writer::i18n('Cannot save character: %s', $info[2]));
+		}
+		unset($statement);
+		$db->commit();
+		unset($db, $data, $id, $value, $metaid, $check, $key);
+		return;
+	}
+
+	/**
+	 * public function storeArray
+	 *
+	 * returns the object as a simple array
+	 * plus color and saved for datastore
+	 *
+	 * @return array
+	 */
+	public function storeArray()
+	{
+		return array_merge(array_values($this->data), array('#000000', TRUE, FALSE), array_values($this->meta));
+	}
+
+	/**
+	 * static public function find
+	 *
+	 * return an array of character objects, can add sql clause
+	 *
+	 * @param string|int pass list of ids or names to select
+	 * @return array of objects instanceof CharacterDao
+	 */
+	static public function find($sql = NULL)
+	{
+		$db = Db::instance();
+
+		$statement = $db->query('SELECT "id" FROM "character"' . $sql);
+		$ids = $statement->fetchAll(PDO::FETCH_COLUMN);
+		unset($statement);
+		$list = array();
+		foreach($ids as $id)
+		{
+			$list[] = new CharacterDao($id);
+		}
+		unset($db, $ids, $id);
+		return $list;
+	}
+
+	/**
+	 * static public function reorder
+	 *
+	 * because order is a PITA we have a function just for it
+	 * is smart enough to reorder
+	 *
+	 * @param int $id primary key of row we're reordering
+	 * @param int $new new position for row
+	 * @return void
+	 */
+	static public function reorder($id, $new = NULL)
+	{
+		if(is_null($new))
+		{
+			return;
+		}
+
+		$db = Db::instance();
+
+		try
+		{
+			// grab max
+			$statement = $db->query('SELECT MAX("order") FROM "character"');
+			$max = $statement->fetch(PDO::FETCH_COLUMN);
+
+			if($new > $max)
+			{
+				$statement = $db->prepare('UPDATE "character" SET "order" = :order WHERE "id" = :id');
+				$statement->execute(array(':id' => $id, ':order' => (int)++$max));
+				unset($id, $new, $max, $statement, $db);
+				return;
+			}
+			if($new < 0)
+			{
+				$new = 0;
+			}
+	
+			$statement = $db->prepare('SELECT "order" FROM "character" WHERE "id" = :id');
+			$statement->execute(array(':id' => $id));
+			$old = $statement->fetch(PDO::FETCH_COLUMN);
+
+			if($new == $old)
+			{
+				unset($id, $new, $max, $statement, $db, $old);
+				return;
+			}
+			elseif($new > $old)
+			{
+				$statement = $db->prepare('UPDATE "character" SET "order" = order - 1 WHERE "order" <= :new AND "order" >= :old');
+				$statement->execute(array(':old' => $old, ':new' => $new));
+			}
+			elseif($new < $old)
+			{
+				$statement = $db->prepare('UPDATE "character" SET "order" = order + 1 WHERE "order" >= :new AND "order <= :old');
+				$statement->execute(array(':old' => $old, ':new' => $new));
+			}
+	
+			$statement = $db->prepare('UPDATE "character" SET "order" = :order WHERE "id" = :id');
+			$statement->execute(array(':id' => $id, ':order' => $new));
+		}
+		catch(PDOException $e)
+		{
+			unset($statement);
+			$info = $db->errorInfo();
+			unset($db, $data, $check, $order, $id, $e, $metaid);
+			throw new Exception(Writer::i18n('Cannot reorder character: %s', $info[2]));
+		}
+
+		unset($old, $id, $new, $max, $statement, $db);
+		return ;
+	}
+
+	//----------------------------------------------------------------
+	//             Overloading
+	//----------------------------------------------------------------
+
+	/**
+	 * public function __set
+	 *
+	 * sets a value for the data store
+	 *
+	 * @param string $name item to set
+	 * @param scalar $value value for item
+	 * @return void
+	 */
+	public function __set($name, $value)
+	{
+		if(is_numeric($name) && isset($this->listmap[$name]))
+		{
+			$name = $this->listmap[$name];
+		}
+		if(array_key_exists($name, $this->data))
+		{
+			$this->data[$name] = $value;
+		}
+		if(array_key_exists($name, $this->meta))
+		{
+			$this->meta[$name] = $value;
+		}
+		return;
+	}
+
+	/**
+	 * public function __get
+	 *
+	 * gets a value from the data store
+	 *
+	 * @param string $name item to grab
+	 * @return mixed
+	 */
+	public function __get($name)
+	{
+		if(is_int($name) && isset($this->listmap[$name]))
+		{
+			$name = $this->listmap[$name];
+		}
+		if(isset($this->data[$name]))
+		{
+			return $this->data[$name];
+		}
+		elseif(isset($this->meta[$name]))
+		{
+			return $this->meta[$name];
+		}
+		return;
+	}
+
+	//----------------------------------------------------------------
+	//             Iterate the data properly
+	//----------------------------------------------------------------
+
+	/**
+	 * public function rewind
+	 *
+	 * uses array iteration funcs on data
+	 *
+	 * @return void
+	 */
+	public function rewind()
+	{
+		reset($this->data);
+		reset($this->meta);
+		return;
+	}
+
+	/**
+	 * public function current
+	 *
+	 * returns current data value
+	 *
+	 * @return mixed
+	 */
+	public function current()
+	{
+		$current = current($this->data);
+		if($current === FALSE)
+		{
+			return current($this->meta);
+		}
+		else
+		{
+			return $current;
+		}
+	}
+
+	/**
+	 * public function key
+	 *
+	 * uses array key function on internal current data array
+	 *
+	 * @return mixed
+	 */
+	public function key()
+	{
+		$current = current($this->data);
+		if($current === FALSE)
+		{
+			return key($this->meta);
+		}
+		else
+		{
+			return key($this->data);
+		}
+	}
+
+	/**
+	 * public function next
+	 *
+	 * advances the pointer on internal array
+	 *
+	 * @return void
+	 */
+	public function next()
+	{
+		$current = current($this->data);
+		if($current === FALSE)
+		{
+			next($this->meta);
+		}
+		else
+		{
+			next($this->data);
+		}
+		unset($current);
+	}
+
+	/**
+	 * public function valid
+	 *
+	 * checks to see if we get false from current
+	 *
+	 * @return bool
+	 */
+	public function valid()
+	{
+		return $this->current() !== FALSE;
+	}
+
+	//----------------------------------------------------------------
+	//             Meta Data Options
+	//----------------------------------------------------------------
+
+	/**
+	 * static public function addMeta
+	 *
+	 * add a new meta data option and return id of it
+	 *
+	 * @param string $name name for the data
+	 * @param string $display display name for the data
+	 * @param string $default default value for the data
+	 * @param string $type type of meta data (from type table)
+	 * @param array $options list of options to add to 
+	 * @return int
+	 */
+	static public function addMeta($name, $display, $default, $type, $options = NULL)
+	{
+		$db = Db::instance();
+		$db->beginTransaction();
+		try
+		{
+			if($name === 'id' || $name === 'name')
+			{
+				$name = 'meta' . $name;
+			}
+			// make sure it doesn't exist
+			$statement = $db->prepare('SELECT COUNT("id") FROM "character_meta" WHERE "name" = :name');
+			$statement->execute(array(':name' => $name));
+			$check = $statement->fetch(PDO::FETCH_COLUMN);
+			if($check > 0)
+			{
+				unset($statement, $db, $display, $default, $type, $options, $check);
+				throw new Exception(Writer::i18n('Meta item "%s" already exists', $name));
+			}
+			// get type
+			$statement = $db->prepare('SELECT "id" FROM "character_meta_type" WHERE "name" = :type');
+			$statement->execute(array(':type' => $type));
+			$type = $statement->fetch(PDO::FETCH_COLUMN);
+			// do insert
+			$statement = $db->prepare('INSERT INTO "character_meta"("name", "display", "default", "character_meta_type_id_fk") VALUES(:name, :display, :default, :type)');
+			$statement->execute(array(':name' => $name, ':display' => $display, ':default' => $default, ':type' => $type));
+			$id = $db->lastInsertId();
+			// options if any
+			if(!is_null($options) && is_array($options))
+			{
+				$statement = $db->prepare('INSERT INTO "character_meta_option"("name", "display", "value", "character_meta_id_fk") VALUES(:name, :display, :value, :id)');
+				$statement->bindValue(':id', $id);
+				$statement->bindParam(':name', $name);
+				$statement->bindParam(':display', $display);
+				$statement->bindParam(':value', $value);
+				foreach($options as $data)
+				{
+					$name = isset($data['name']) ? $data['name'] : (isset($data[0]) ? $data[0] : NULL);
+					$display = isset($data['display']) ? $data['display'] : (isset($data[0]) ? $data[0] : NULL);
+					$value = isset($data['value']) ? $data['value'] : (isset($data[0]) ? $data[0] : NULL);
+					$statement->execute();
+				}
+			}
+		}
+		catch(PDOException $e)
+		{
+			unset($statement);
+			$db->rollback();
+			$info = $db->errorInfo();
+			unset($db, $name, $display, $default, $type, $options, $type, $id, $data, $value, $check);
+			throw new Exception(Writer::i18n('Cannot create meta item: %s', $info[2]));
+		}
+		unset($statement, $name, $display, $default, $type, $options, $type, $id, $data, $value);
+		$db->commit();
+		return $db->lastInsertId();
+	}
+
+	/**
+	 * static public function changeMeta
+	 *
+	 * alter meta data information
+	 *
+	 * @param int $id id of meta to change
+	 * @param string $name name for the data
+	 * @param string $display display name for the data
+	 * @param string $default default value for the data
+	 * @param string $type type of meta data (from type table)
+	 * @param array $options list of options to add to 
+	 * @return void
+	 */
+	static public function changeMeta($id, $name = NULL, $display = NULL, $default = NULL, $type = NULL, $options = NULL)
+	{
+		$db = Db::instance();
+		$db->beginTransaction();
+		try
+		{
+			// make sure it exists
+			$statement = $db->prepare('SELECT COUNT("id") FROM "character_meta" WHERE "id" = :id');
+			$statement->execute(array(':id' => $id));
+			$check = $statement->fetch(PDO::FETCH_COLUMN);
+			if($check < 1)
+			{
+				unset($statement, $db, $display, $default, $type, $options, $check);
+				throw new Exception(Writer::i18n('Meta item "%s" does not exist', $name));
+			}
+			$updates = array();
+			$bind = array(':id' => $id);
+			if(!is_null($name))
+			{
+				if($name === 'id' || $name === 'name')
+				{
+					$name = 'meta' . $name;
+				}
+				$updates[] = '"name" = :name';
+				$bind[':name'] = $name;
+			}
+			if(!is_null($display))
+			{
+				$updates[] = '"display" = :display';
+				$bind[':display'] = $display;
+			}
+			if(!is_null($default))
+			{
+				$updates[] = '"default" = :default';
+				$bind[':default'] = $default;
+			}
+			if(!is_null($display))
+			{
+				// get type
+				$statement = $db->prepare('SELECT "id" FROM "character_meta_type" WHERE "name" = :type');
+				$statement->execute(array(':type' => $type));
+				$type = $statement->fetch(PDO::FETCH_COLUMN);
+				$updates[] = '"character_meta_type_id_fk" = :type';
+				$bind[':type'] = $type;
+			}
+			// do update (if needed
+			if(count($updates) < 1)
+			{
+				// do update
+				$statement = $db->prepare('UPDATE "character_meta" SET ' . implode(', ', $updates) . ' WHERE id = :id');
+				$statement->execute($bind);
+			}
+			// options if any
+			if(!is_null($options) && is_array($options))
+			{
+				$statement->prepare('DELETE FROM "character_meta_option" WHERE "character_meta_id_fk" = :id');
+				$statement->execute(array(':id' => $id));
+				$statement = $db->prepare('INSERT INTO "character_meta_option"("name", "display", "value", "character_meta_id_fk") VALUES(:name, :display, :value, :id)');
+				$statement->bindValue(':id', $id);
+				$statement->bindParam(':name', $name);
+				$statement->bindParam(':display', $display);
+				$statement->bindParam(':value', $value);
+				foreach($options as $data)
+				{
+					$name = isset($data['name']) ? $data['name'] : (isset($data[0]) ? $data[0] : NULL);
+					$display = isset($data['display']) ? $data['display'] : (isset($data[0]) ? $data[0] : NULL);
+					$value = isset($data['value']) ? $data['value'] : (isset($data[0]) ? $data[0] : NULL);
+					$statement->execute();
+				}
+			}
+		}
+		catch(PDOException $e)
+		{
+			unset($statement);
+			$db->rollback();
+			$info = $db->errorInfo();
+			unset($db, $name, $display, $default, $type, $options, $type, $id, $data, $value, $check);
+			throw new Exception(Writer::i18n('Cannot create meta item: %s', $info[2]));
+		}
+		unset($check, $updates, $bind, $statement, $name, $display, $default, $type, $options, $type, $id, $data, $value);
+		$db->commit();
+		unset($db);
+		return;
+	}
+
+	/**
+	 * static public function removeMeta
+	 *
+	 * remove a meta data item
+	 *
+	 * @param int $id id of meta to remove
+	 * @return void
+	 */
+	static public function removeMeta($id)
+	{
+		$db = Db::instance();
+		$db->beginTransaction();
+		try
+		{
+			// try delete
+			$statement = $db->prepare('DELETE FROM "character_meta" WHERE "id" = :id');
+			$statement->execute(array(':id' => $id));
+			$statement = $db->prepare('DELETE FROM "character_meta_option" WHERE "character_meta_id_fk" = :id');
+			$statement->execute(array(':id' => $id));
+			$statement = $db->prepare('DELETE FROM "character_has_character_meta" WHERE "character_meta_id_fk" = :id');
+			$statement->execute(array(':id' => $id));
+		}
+		catch(PDOException $e)
+		{
+			unset($statement);
+			$db->rollback();
+			$info = $db->errorInfo();
+			unset($db, $id);
+			throw new Exception(Writer::i18n('Cannot delete meta item: %s', $info[2]));
+		}
+		$db->commit();
+		unset($db, $statement, $id);
+		return;
+	}
+
+	/**
+	 * static public function countMeta
+	 *
+	 * counts number of rows in meta column
+	 *
+	 * @return type about
+	 */
+	static public function countMeta()
+	{
+		$db = Db::instance();
+		$statement = $db->query('SELECT COUNT("id") FROM "character_meta"');
+		$count = $statement->fetch(PDO::FETCH_COLUMN);
+		unset($db, $statement);
+		return $count;
+	}
+}
+?>
\ No newline at end of file
Property changes on: desktop/trunk/Writer/lib/character/dao.class.php
___________________________________________________________________
Name: tsvn:logminsize
   + 15
Name: svn:keywords
   + Id
Name: svn:eol-style
   + LF

Added: desktop/trunk/Writer/lib/character/edit.class.php (23 => 24)


--- desktop/trunk/Writer/lib/character/edit.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/character/edit.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -0,0 +1,131 @@
+<?php
+/**
+ * edit.class.php - character window edit class
+ *
+ * Edit a single character - both meta and regular data
+ *
+ * This is released under the GPL, see license.txt for details
+ *
+ * @author       Elizabeth Smith <emsmith@callicore.net>
+ * @copyright    Elizabeth Smith (c)2006
+ * @link         http://callicore.net/writer
+ * @license      http://www.opensource.org/licenses/gpl-license.php GPL
+ * @version      $Id$
+ * @since        Php 5.2.0
+ * @package      callicore
+ * @subpackage   writer
+ * @category     lib
+ * @filesource
+ */
+
+/**
+ * CharacterEdit - character edit window
+ *
+ * Simple form with save and cancel options
+ */
+class CharacterEdit extends GtkDialog
+{
+
+	/**
+	 * set character information
+	 * @var $character type
+	 */
+	protected $character;
+
+	/**
+	 * public function __construct
+	 *
+	 * Create a new CharacterEdit instance and build internal gui items
+	 *
+	 * @return void
+	 */
+	public function __construct($model, $iter)
+	{
+		// dao object to tamper with
+		$this->character = new CharacterDao();
+		$cols = $model->get_n_columns();
+		while($cols > 0)
+		{
+			$this->character->{$cols - 1} = $model->get_value($iter, $cols -1);
+			$cols--;
+		}
+		unset($data, $cols, $iter, $model);
+
+		// create window
+		parent::__construct(Writer::i18n('Writer :: Characters :: Edit "')
+			. $this->character->name . '"', CharacterWindow::instance(),
+			Gtk::DIALOG_MODAL & Gtk::DIALOG_DESTROY_WITH_PARENT,
+			array(
+				Gtk::STOCK_APPLY, Gtk::RESPONSE_APPLY,
+				Gtk::STOCK_CANCEL, Gtk::RESPONSE_CANCEL
+			));
+
+		// window defaults
+		$config = Config::instance();
+		$width = isset($config->character_edit_width) ? (int) $config->character_edit_width : 800;
+		$height = isset($config->character_edit_height) ? (int) $config->character_edit_height : 600;
+		$this->set_default_size($height, $width);
+		$x = isset($config->character_window_x) ? (int) $config->character_window_x : NULL;
+		$y = isset($config->character_window_y) ? (int) $config->character_window_y : NULL;
+		if(!is_null($x) && !is_null($y))
+		{
+			$this->move($x, $y);
+		}
+
+		// fill vbox with form in table
+		$table = new GtkTable();
+
+		// id (no change)
+		// name (change - check for unique)
+		// order (ignore)
+		// create date (no change)
+		// edit date (no change)
+
+		// meta data - switch on type for textentry, textbuffer, image (drag -n drop) or browse, drop down list, toggle
+
+		$this->connect_simple('delete-event', array($this, 'onDeleteEvent'));
+		return;
+
+		//create statusbar
+		$vbox = new GtkVBox();
+
+		$vbox->pack_start($this->toolbar, FALSE, FALSE);
+
+		$scroll = new GtkScrolledWindow();
+		$scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+		$scroll->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
+		$scroll->add($this->treeview);
+		$vbox->pack_start($scroll);
+
+		$this->add($vbox);
+		$this->treeview->grab_focus();
+
+		$this->show_all();
+		unset($vbox, $config, $height, $width);
+		return;
+	}
+
+	/**
+	 * public function onDeleteEvent
+	 *
+	 * callback when window is destroyed
+	 *
+	 * @param type $name about
+	 * @return type about
+	 */
+	public function onDeleteEvent()
+	{
+		// write configuration settings for window
+		$config = Config::instance();
+		list($height, $width) = $this->get_size();
+		$config->character_edit_height = $height;
+		$config->character_edit_width = $width;
+		list($x, $y) = $this->get_position();
+		$config->character_edit_x = $x;
+		$config->character_edit_y = $y;
+		unset($config, $height, $width, $x, $y);
+		$this->destroy();
+		return;
+	}
+}
+?>
\ No newline at end of file
Property changes on: desktop/trunk/Writer/lib/character/edit.class.php
___________________________________________________________________
Name: tsvn:logminsize
   + 15
Name: svn:keywords
   + Id
Name: svn:eol-style
   + LF

Added: desktop/trunk/Writer/lib/character/model.class.php (23 => 24)


--- desktop/trunk/Writer/lib/character/model.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/character/model.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -0,0 +1,274 @@
+<?php
+/**
+ * model.class.php - uses the dao and implements interfaces
+ *
+ * custom data store for a gtktreeview
+ *
+ * This is released under the GPL, see license.txt for details
+ *
+ * @author       Elizabeth Smith <emsmith@callicore.net>
+ * @copyright    Elizabeth Smith (c)2006
+ * @link         http://callicore.net/writer
+ * @license      http://www.opensource.org/licenses/gpl-license.php GPL
+ * @version      $Id$
+ * @since        Php 5.2.0
+ * @package      callicore
+ * @subpackage   writer
+ * @category     lib
+ * @filesource
+ */
+
+/**
+ * CharacterModel - would probably be smarter to implement this as a custom datastore
+ *
+ * I need a new release for a customdatastore though...sigh
+ */
+class CharacterModel extends GtkListStore
+{
+
+	/**
+	 * store timeouts to remove
+	 * @var $timeouts array
+	 */
+	protected $timeout = array();
+
+	/**
+	 * public function __construct
+	 *
+	 * description
+	 *
+	 * @param type $name about
+	 * @return type about
+	 */
+	public function __construct()
+	{
+		$list = CharacterDao::find();
+		$count = CharacterDao::countMeta();
+
+		// yuck, we have to use eval because the number of columns for the store can change
+		$eval = 'parent::__construct(Gtk::TYPE_LONG, Gtk::TYPE_STRING, '
+			. 'Gtk::TYPE_LONG, Gtk::TYPE_STRING, Gtk::TYPE_STRING, Gtk::TYPE_STRING, '
+			. 'Gtk::TYPE_BOOLEAN, GTK::TYPE_BOOLEAN, ';
+		while($count > 0)
+		{
+			$eval .= 'Gtk::TYPE_PHP_VALUE, ';
+			$count--;
+		}
+		$eval = substr($eval, 0, -2) . ');';
+		eval($eval);
+		foreach($list as $object)
+		{
+			$this->append($object->storeArray());
+		}
+		unset($list, $count, $eval, $object);
+	}
+
+	/**
+	 * public function onNew
+	 *
+	 * inserts a new blank row for a character
+	 *
+	 * @return void
+	 */
+	public function onNew()
+	{
+		$date = date('Y-m-d H:i:s');
+		$iter = $this->append();
+		$this->set($iter, 1, 'New Character ' . $this->iter_n_children(NULL), 2,
+			$this->iter_n_children(NULL), 3, $date, 4, $date, 5, '#009900', 6, FALSE);
+		$this->timeout[$this->get_string_from_iter($iter)] = Gtk::timeout_add(60000, array($this, 'onStale'), $iter);
+		CharacterWindow::instance()->treeview->get_selection()->select_iter($iter);
+		CharacterWindow::instance()->treeview->scroll_to_cell($this->get_path($iter));
+		$this->isChanged();
+		unset($date, $iter);
+		return;
+	}
+
+	/**
+	* public function onStale
+	*
+	* changes font color for a row from green to blue as new data
+	* becomes stale
+	*
+	* @param object $iter instanceof GtkTreeIter
+	* @return void
+	*/
+	public function onStale($iter)
+	{
+		$this->set($iter, 5, '#000099');
+		unset($iter);
+		return;
+	}
+
+	/**
+	 * public function onDelete
+	 *
+	 * tags item for deletion (is not deleted until save!)
+	 *
+	 * @todo an "are you sure" dialog
+	 * @return void
+	 */
+	public function onDelete()
+	{
+		$selection = CharacterWindow::instance()->treeview->get_selection();
+		list($model, $iter) = $selection->get_selected();
+		$next = $this->iter_next($iter);
+		if(!is_null($next))
+		{
+			$selection->select_iter($next);
+			CharacterWindow::instance()->treeview->scroll_to_cell($this->get_path($next));
+		}
+		$this->set($iter, 5, '#990000', 7, TRUE);
+		$id = $this->get_string_from_iter($iter);
+		if(isset($this->timeout[$id]))
+		{
+			Gtk::timeout_remove($this->timeout[$id]);
+		}
+		$this->isChanged();
+		unset($this->timeout[$id], $selection, $model, $iter, $id);
+		return;
+	}
+
+	/**
+	 * public function unDelete
+	 *
+	 * untags item for deletion (is not deleted until save!)
+	 *
+	 * @todo an "are you sure" dialog
+	 * @return void
+	 */
+	public function onUndelete()
+	{
+		$selection = CharacterWindow::instance()->treeview->get_selection();
+		list($model, $iter) = $selection->get_selected();
+		$next = $this->iter_next($iter);
+		if(!is_null($next))
+		{
+			$selection->select_iter($next);
+			CharacterWindow::instance()->treeview->scroll_to_cell($this->get_path($next));
+		}
+		// if saved flag is toggled go black
+		$data = $this->get($iter, 6);
+		if($data[0] == TRUE)
+		{
+			$this->set($iter, 5, '#000000');
+		}
+		// otherwise we go blue
+		else
+		{
+			$this->set($iter, 5, '#000099');
+		}
+		$this->set($iter, 7, FALSE);
+		$this->isChanged();
+		unset($data, $selection, $model, $iter);
+		return;
+	}
+
+	/**
+	 * public function onRevert
+	 *
+	 * clear rows and reload from db
+	 *
+	 * @return void
+	 */
+	public function onRevert()
+	{
+		$this->clear();
+		$list = CharacterDao::find();
+		foreach($list as $object)
+		{
+			$this->append($object->storeArray());
+		}
+		CharacterWindow::instance()->treeview->get_selection()->select_iter($this->get_iter_first());
+		foreach($this->timeout as $id)
+		{
+			Gtk::timeout_remove($id);
+		}
+		$this->timeout = array();
+		$this->isChanged(FALSE);
+		unset($list, $object);
+		return;
+	}
+
+	/**
+	 * public function onSave
+	 *
+	 * write changes to db
+	 *
+	 * @param type $name about
+	 * @return type about
+	 */
+	public function onSave()
+	{
+		
+	}
+
+	/**
+	 * public function onEdit
+	 *
+	 * open the edit window with selected character displayed
+	 *
+	 * @return void
+	 */
+	public function onEdit()
+	{
+		$selection = CharacterWindow::instance()->treeview->get_selection();
+		list($model, $iter) = $selection->get_selected();
+		// load in character
+		$dialog =  new CharacterEdit($model, $iter);
+		// run and get response
+		$response = $dialog->run();
+		$dialog->destroy();
+	}
+
+	/**
+	 * public function onSelectionChanged
+	 *
+	 * decides what actions can be taken
+	 *
+	 * @return void
+	 */
+	public function onSelectionChanged($selection)
+	{
+		list($model, $iter) = $selection->get_selected();
+		if(is_null($iter))
+		{
+			unset($model, $iter, $selection);
+			return;
+		}
+		$group = CharacterAction::instance();
+		// manipulate delete/undelete
+		$deleted = $this->get_value($iter, 7);
+		if($deleted == TRUE)
+		{
+			$group->getGroup('character')->get_action('edit')->set_sensitive(FALSE);
+			$group->getGroup('character')->get_action('delete')->set_sensitive(FALSE);
+			$group->getGroup('character')->get_action('undelete')->set_sensitive(TRUE);
+		}
+		else
+		{
+			$group->getGroup('character')->get_action('edit')->set_sensitive(TRUE);
+			$group->getGroup('character')->get_action('delete')->set_sensitive(TRUE);
+			$group->getGroup('character')->get_action('undelete')->set_sensitive(FALSE);
+		}
+		unset($model, $iter, $selection, $group, $deleted);
+		return;
+	}
+
+	/**
+	 * public function isChanged
+	 *
+	 * call this if we change a character at all
+	 *
+	 * @return void
+	 */
+	public function isChanged($toggle = TRUE)
+	{
+		$group = CharacterAction::instance();
+		$group->getGroup('character')->get_action('save')->set_sensitive($toggle);
+		$group->getGroup('character')->get_action('revert')->set_sensitive($toggle);
+		unset($group, $toggle);
+		return;
+	}
+}
+?>
\ No newline at end of file
Property changes on: desktop/trunk/Writer/lib/character/model.class.php
___________________________________________________________________
Name: tsvn:logminsize
   + 15
Name: svn:keywords
   + Id
Name: svn:eol-style
   + LF

Added: desktop/trunk/Writer/lib/character/toolbar.class.php (23 => 24)


--- desktop/trunk/Writer/lib/character/toolbar.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/character/toolbar.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -0,0 +1,55 @@
+<?php
+/**
+ * toolbar.class.php - character window toolbar widget
+ *
+ * creates a toolbar using character actions stored in GtkActionGroups
+ *
+ * This is released under the GPL, see license.txt for details
+ *
+ * @author       Elizabeth Smith <emsmith@callicore.net>
+ * @copyright    Elizabeth Smith (c)2006
+ * @link         http://callicore.net/writer
+ * @license      http://www.opensource.org/licenses/gpl-license.php GPL
+ * @version      $Id$
+ * @since        Php 5.2.0
+ * @package      callicore
+ * @subpackage   writer
+ * @category     lib
+ * @filesource
+ */
+
+/**
+ * CharacterToolbar - toolbar widget
+ *
+ * @todo show/hide toolbar, pick icon size for toolbar, toolbar type choices
+ */
+class CharacterToolbar extends GtkToolbar
+{
+	/**
+	 * public function __construct
+	 *
+	 * registers callbacks and sets up model
+	 *
+	 * @return void
+	 */
+	public function __construct()
+	{
+		parent::__construct();
+		$this->set_style(Gtk::TOOLBAR_BOTH);
+		$this->set_icon_size(Writer::$BUTTON);
+		$group = CharacterAction::instance();
+
+		$this->insert($group->getGroup('character')->get_action('add')->create_tool_item(), -1);
+		$this->insert($group->getGroup('character')->get_action('edit')->create_tool_item(), -1);
+		$this->insert($group->getGroup('character')->get_action('delete')->create_tool_item(), -1);
+		$this->insert($group->getGroup('character')->get_action('undelete')->create_tool_item(), -1);
+
+		$this->insert(new GtkSeparatorToolItem(), -1);
+
+		$this->insert($group->getGroup('character')->get_action('save')->create_tool_item(), -1);
+		$this->insert($group->getGroup('character')->get_action('revert')->create_tool_item(), -1);
+
+		$this->show_all();
+	}
+}
+?>
\ No newline at end of file
Property changes on: desktop/trunk/Writer/lib/character/toolbar.class.php
___________________________________________________________________
Name: tsvn:logminsize
   + 15
Name: svn:keywords
   + Id
Name: svn:eol-style
   + LF

Added: desktop/trunk/Writer/lib/character/treeview.class.php (23 => 24)


--- desktop/trunk/Writer/lib/character/treeview.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/character/treeview.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -0,0 +1,88 @@
+<?php
+/**
+ * treeview.class.php - character window treeview widget
+ *
+ * creates and fills the treeview widget and handles all the tree view
+ * manipulation stuff
+ *
+ * This is released under the GPL, see license.txt for details
+ *
+ * @author       Elizabeth Smith <emsmith@callicore.net>
+ * @copyright    Elizabeth Smith (c)2006
+ * @link         http://callicore.net/writer
+ * @license      http://www.opensource.org/licenses/gpl-license.php GPL
+ * @version      $Id$
+ * @since        Php 5.2.0
+ * @package      callicore
+ * @subpackage   writer
+ * @category     lib
+ * @filesource
+ */
+
+/**
+ * CharacterTreeview - character treeview widget - shows a list of all characters
+ */
+class CharacterTreeview extends GtkTreeView
+{
+
+	/**
+	 * format for displaying dates
+	 * @var $date string
+	 */
+	protected $date;
+
+	/**
+	 * public function __construct
+	 *
+	 * registers callbacks and sets up model
+	 *
+	 * @return void
+	 */
+	public function __construct()
+	{
+		parent::__construct();
+
+		$config = Config::instance();
+		$this->date = isset($config->character_date_format) ? $config->character_date_format : 'Y-m-d H:i:s';
+
+		$this->set_rules_hint(TRUE);
+		$cols = array('#' => 2, 'Name' => 1, 'Created' => 3, 'Edited' => 4);
+		foreach($cols as $name => $id)
+		{
+			$render = new GtkCellRendererText();
+			$col = new GtkTreeViewColumn($name, $render, 'text', $id, 'foreground', 5);
+			$col->focus_cell($render);
+			if($id == 1)
+			{
+				$col->set_expand(TRUE);
+			}
+			elseif($id == 3 || $id == 4)
+			{
+				$col->set_cell_data_func($render, array($this, 'dateFormat'));
+			}
+			$col->set_resizable(TRUE);
+			$col->set_sort_column_id($id);
+			$this->append_column($col);
+		}
+		$this->set_model(new CharacterModel());
+		$selection = $this->get_selection();
+		$selection->set_mode(Gtk::SELECTION_BROWSE);
+		$selection->select_iter($this->get_model()->get_iter_first());
+		$selection->connect('changed', array($this->get_model(), 'onSelectionChanged'));
+		unset($config, $cols, $name, $id, $render, $col, $selection);
+	}
+
+	/**
+	 * public function dateFormat
+	 *
+	 * callback to format the date in a cell
+	 *
+	 * @return void
+	 */
+	public function dateFormat($render, $cell)
+	{
+		$cell->set_property('text', date($this->date, strtotime($cell->get_property('text'))));
+		return;
+	}
+}
+?>
\ No newline at end of file
Property changes on: desktop/trunk/Writer/lib/character/treeview.class.php
___________________________________________________________________
Name: tsvn:logminsize
   + 15
Name: svn:keywords
   + Id
Name: svn:eol-style
   + LF

Added: desktop/trunk/Writer/lib/character/window.class.php (23 => 24)


--- desktop/trunk/Writer/lib/character/window.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/character/window.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -0,0 +1,160 @@
+<?php
+/**
+ * window.class.php - character window main class
+ *
+ * parent window for all character related adminitration tasks such as listing,
+ * creating, deleting, editing characters and manipulating meta-data for
+ * characters as well as importing, exporting, printing and saving characters
+ *
+ * This is released under the GPL, see license.txt for details
+ *
+ * @author       Elizabeth Smith <emsmith@callicore.net>
+ * @copyright    Elizabeth Smith (c)2006
+ * @link         http://callicore.net/writer
+ * @license      http://www.opensource.org/licenses/gpl-license.php GPL
+ * @version      $Id$
+ * @since        Php 5.2.0
+ * @package      callicore
+ * @subpackage   writer
+ * @category     lib
+ * @filesource
+ */
+
+/**
+ * CharacterWindow - character window - list view looks a lot like main window
+ *
+ * Has menu bar and tool bar specific to characters and character listing
+ */
+class CharacterWindow extends GtkWindow
+{
+
+	/**
+	 * singleton instance for this class
+	 * @var $singleton instanceof CharacterWindow
+	 */
+	static protected $singleton;
+
+	/**
+	 * switches on to allow construct to occur
+	 * @var $check bool
+	 */
+	static protected $check = FALSE;
+
+	/**
+	 * Treeview widget packed into window
+	 * @var $treeview object instanceof CharacterTreeview
+	 */
+	public $treeview;
+
+	/**
+	 * public function __construct
+	 *
+	 * Create a new CharacterWindow instance and build internal gui items
+	 *
+	 * @return void
+	 */
+	public function __construct()
+	{
+		if(self::$check == FALSE)
+		{
+			throw new Exception(Writer::i18n(
+			'%1$s is a singleton class - use %1$s::instance() to retrieve the current object',
+			'CharacterWindow'));
+		}
+		self::$singleton = $this;
+
+		parent::__construct();
+
+		$config = Config::instance();
+		$this->set_transient_for(ProjectWindow::instance());
+		$this->set_destroy_with_parent(TRUE);
+		$width = isset($config->character_window_width) ? (int) $config->character_window_width : 800;
+		$height = isset($config->character_window_height) ? (int) $config->character_window_height : 600;
+		$this->set_default_size($height, $width);
+		$x = isset($config->character_window_x) ? (int) $config->character_window_x : NULL;
+		$y = isset($config->character_window_y) ? (int) $config->character_window_y : NULL;
+		if(!is_null($x) && !is_null($y))
+		{
+			$this->move($x, $y);
+		}
+		$this->set_title(Writer::i18n(('Writer :: Characters')));
+
+		$this->treeview = new CharacterTreeview();
+		$this->toolbar = new CharacterToolbar();
+
+		//create statusbar
+		$vbox = new GtkVBox();
+
+		$vbox->pack_start($this->toolbar, FALSE, FALSE);
+
+		$scroll = new GtkScrolledWindow();
+		$scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
+		$scroll->set_shadow_type(Gtk::SHADOW_ETCHED_IN);
+		$scroll->add($this->treeview);
+		$vbox->pack_start($scroll);
+
+		$this->add($vbox);
+		$this->treeview->grab_focus();
+
+		$this->connect_simple('delete-event', array($this, 'onDeleteEvent'));
+
+		$this->show_all();
+		unset($vbox, $config, $height, $width, $x, $y);
+		return;
+	}
+
+	/**
+	 * static public function instance
+	 *
+	 * this is how you "construct" a CharacterWindow object
+	 *
+	 * @return object instanceof CharacterWindow
+	 */
+	static public function instance()
+	{
+		if(is_null(self::$singleton))
+		{
+			self::$check = TRUE;
+			self::$singleton = new CharacterWindow();
+			self::$check = FALSE;
+		}
+		return self::$singleton;
+	}
+
+	/**
+	 * public function __clone()
+	 *
+	 * disable cloning of a singleton
+	 *
+	 * @return void
+	 */
+	public function __clone()
+	{
+		throw new Exception(Writer::i18n('Cannot clone singleton object %s', 'CharacterWindow'));
+		return;
+	}
+
+	/**
+	 * public function onDeleteEvent
+	 *
+	 * callback when window is destroyed
+	 *
+	 * @param type $name about
+	 * @return type about
+	 */
+	public function onDeleteEvent()
+	{
+		// write configuration settings for window
+		$config = Config::instance();
+		list($height, $width) = $this->get_size();
+		$config->character_window_height = $height;
+		$config->character_window_width = $width;
+		list($x, $y) = $this->get_position();
+		$config->character_window_x = $x;
+		$config->character_window_y = $y;
+		unset($config, $height, $width, $x, $y);
+		$this->destroy();
+		return;
+	}
+}
+?>
\ No newline at end of file
Property changes on: desktop/trunk/Writer/lib/character/window.class.php
___________________________________________________________________
Name: tsvn:logminsize
   + 15
Name: svn:keywords
   + Id
Name: svn:eol-style
   + LF

Modified: desktop/trunk/Writer/lib/config.class.php (23 => 24)


--- desktop/trunk/Writer/lib/config.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/config.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -28,11 +28,17 @@
 {
 	/**
 	 * singleton instance for this class
-	 * @var $singleton instanceof Config
+	 * @var $singleton instanceof Characters
 	 */
-	static public $singleton;
+	static protected $singleton;
 
 	/**
+	 * switches on to allow construct to occur
+	 * @var $check bool
+	 */
+	static protected $check = FALSE;
+
+	/**
 	 * multi-dim array of current configuration information
 	 * @var $data array
 	 */
@@ -47,12 +53,14 @@
 	 */
 	public function __construct()
 	{
-		if(!is_null(self::$singleton))
+		if(self::$check == FALSE)
 		{
-			throw new Exception('Config is a singleton class - use Config::singleton() to retrieve the current instance');
+			throw new Exception(Writer::i18n(
+			'%1$s is a singleton class - use %1$s::instance() to retrieve the current object',
+			'Config'));
 		}
+		self::$singleton = $this;
 
-		self::$singleton = $this;
 		if(file_exists(Writer::$appdata . 'config.ini'))
 		{
 			$this->data = parse_ini_file(Writer::$appdata . 'config.ini');
@@ -167,14 +175,33 @@
 	}
 
 	/**
-	 * public function singleton
+	 * public function __clone()
 	 *
-	 * grab and return the instance
+	 * disable cloning of a singleton
 	 *
-	 * @return object instanceof Theme
+	 * @return void
 	 */
-	static public function singleton()
+	public function __clone()
 	{
+		throw new Exception(Writer::i18n('Cannot clone singleton object %s', 'Config'));
+		return;
+	}
+
+	/**
+	 * static public function instance
+	 *
+	 * this is how you "construct" a Config object
+	 *
+	 * @return object instanceof Config
+	 */
+	static public function instance()
+	{
+		if(is_null(self::$singleton))
+		{
+			self::$check = TRUE;
+			self::$singleton = new Config();
+			self::$check = FALSE;
+		}
 		return self::$singleton;
 	}
 }

Added: desktop/trunk/Writer/lib/db.class.php (23 => 24)


--- desktop/trunk/Writer/lib/db.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/db.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -0,0 +1,182 @@
+<?php
+/**
+ * db.class.php - wrapper for pdo and sqlite to manage open project
+ *
+ * extends pdo class, forces singleton instance
+ *
+ * This is released under the GPL, see license.txt for details
+ *
+ * @author       Elizabeth Smith <emsmith@callicore.net>
+ * @copyright    Elizabeth Smith (c)2006
+ * @link         http://callicore.net/writer
+ * @license      http://www.opensource.org/licenses/gpl-license.php GPL
+ * @version      $Id$
+ * @since        Php 5.2.0
+ * @package      callicore
+ * @subpackage   writer
+ * @category     lib
+ * @filesource
+ */
+
+/**
+ * Db - pdo wrapper class for easy pdo management
+ *
+ * forces pdo as a singleton
+ */
+class Db extends PDO
+{
+	/**
+	 * singleton instance for this class
+	 * @var $singleton instanceof Db
+	 */
+	static protected $singleton;
+
+	/**
+	 * switches on to allow construct to occur
+	 * @var $check bool
+	 */
+	static protected $check = FALSE;
+
+	/**
+	 * sql definition
+	 * @var $sql string
+	 */
+	protected $sql =
+'CREATE TABLE "character" (
+  "id" INTEGER PRIMARY KEY,
+  "name" TEXT UNIQUE,
+  "order" INTEGER UNIQUE,
+  "date_created" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
+  "date_edited" DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP
+);
+
+CREATE TABLE "character_meta" (
+  "id" INTEGER PRIMARY KEY,
+  "name" TEXT UNIQUE,
+  "display" TEXT,
+  "default" TEXT,
+  "character_meta_type_id_fk" INTEGER NOT NULL DEFAULT 0
+);
+
+CREATE TABLE "character_meta_type" (
+  "id" INTEGER PRIMARY KEY,
+  "name" TEXT UNIQUE,
+  "list" TEXT
+);
+
+INSERT INTO "character_meta_type"("name", "list") VALUES (\'entry\', \'TEXT\');
+INSERT INTO "character_meta_type"("name", "list") VALUES (\'text\', NULL);
+INSERT INTO "character_meta_type"("name", "list") VALUES (\'toggle\', \'TOGGLE\');
+INSERT INTO "character_meta_type"("name", "list") VALUES (\'choice\', NULL);
+INSERT INTO "character_meta_type"("name", "list") VALUES (\'image\', \'PIXBUF\');
+
+CREATE TABLE "character_meta_option" (
+  "id" INTEGER PRIMARY KEY,
+  "name" TEXT UNIQUE,
+  "display" TEXT,
+  "value" TEXT,
+  "character_meta_id_fk" INTEGER NOT NULL DEFAULT 0
+);
+
+CREATE TABLE "character_has_character_meta" (
+  "id" INTEGER PRIMARY KEY,
+  "value" TEXT,
+  "character_id_fk" INTEGER NOT NULL DEFAULT 0,
+  "character_meta_id_fk" INTEGER NOT NULL DEFAULT 0,
+  "character_meta_option_id_fk" INTEGER
+);
+
+INSERT INTO "character"("name", "order") VALUES (\'NONE\', 1);
+';
+
+	/**
+	 * public function __construct
+	 *
+	 * constructor will throw an exception if a class already exists - use
+	 * instance to create the class
+	 *
+	 * @param string $file file to open
+	 * @return void
+	 */
+	public function __construct($file)
+	{
+		if(self::$check == FALSE)
+		{
+			throw new Exception(Writer::i18n(
+			'%1$s is a singleton class - use %1$s::instance() to retrieve the current object',
+			'Db'));
+		}
+		self::$singleton = $this;
+
+		$new = file_exists($file) ? FALSE : TRUE;
+		parent::__construct('sqlite:' . $file);
+		$this->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
+		if($new == TRUE)
+		{
+			$this->beginTransaction();
+			try
+			{
+				$create = $this->exec($this->sql);
+			}
+			catch(PDOException $e)
+			{
+				$this->rollback();
+				$info = $this->errorInfo();
+				unset($file, $new, $e);
+				throw new Exception(Writer::i18n('Creating character storage failed: "%s"', $info[2]));
+			}
+			$this->commit();
+		}
+		unset($file, $new);
+		return;
+	}
+
+	/**
+	 * public function identify
+	 *
+	 * quote identifier
+	 *
+	 * @param string $string string to quote
+	 * @return string
+	 */
+	public function identify($string)
+	{
+		return '"' . $string . '"';
+	}
+
+	/**
+	 * public function __clone()
+	 *
+	 * disable cloning of a singleton
+	 *
+	 * @return void
+	 */
+	public function __clone()
+	{
+		throw new Exception(Writer::i18n('Cannot clone singleton object %s', 'Db'));
+		return;
+	}
+
+	/**
+	 * static public function instance
+	 *
+	 * this is how you "construct" a Db object
+	 *
+	 * @return object instanceof Db
+	 */
+	static public function instance($file = NULL)
+	{
+		if(is_null(self::$singleton) && !is_null($file))
+		{
+			self::$check = TRUE;
+			self::$singleton = new Db($file);
+			self::$check = FALSE;
+		}
+		elseif(is_null(self::$singleton))
+		{
+			throw new Exception(Writer::i18n('There is no currently open project'));
+		}
+		return self::$singleton;
+	}
+}
+?>
\ No newline at end of file
Property changes on: desktop/trunk/Writer/lib/db.class.php
___________________________________________________________________
Name: tsvn:logminsize
   + 15
Name: svn:keywords
   + Id
Name: svn:eol-style
   + LF

Added: desktop/trunk/Writer/lib/project/window.class.php (23 => 24)


--- desktop/trunk/Writer/lib/project/window.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/project/window.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -0,0 +1,97 @@
+<?php
+/**
+ * window.class.php - character window main class
+ *
+ * parent window for all character related adminitration tasks such as listing,
+ * creating, deleting, editing characters and manipulating meta-data for
+ * characters as well as importing, exporting, printing and saving characters
+ *
+ * This is released under the GPL, see license.txt for details
+ *
+ * @author       Elizabeth Smith <emsmith@callicore.net>
+ * @copyright    Elizabeth Smith (c)2006
+ * @link         http://callicore.net/writer
+ * @license      http://www.opensource.org/licenses/gpl-license.php GPL
+ * @version      $Id$
+ * @since        Php 5.2.0
+ * @package      callicore
+ * @subpackage   writer
+ * @category     lib
+ * @filesource
+ */
+
+/**
+ * ProjectWindow - character window - list view looks a lot like main window
+ *
+ * Has menu bar and tool bar specific to characters and character listing with
+ * drag and drop and reorderable functionality
+ */
+class ProjectWindow extends GtkWindow
+{
+
+	/**
+	 * singleton instance for this class
+	 * @var $singleton instanceof Characters
+	 */
+	static protected $singleton;
+
+	/**
+	 * switches on to allow construct to occur
+	 * @var $check bool
+	 */
+	static protected $check = FALSE;
+
+	/**
+	 * public function __construct
+	 *
+	 * Create a new ProjectWindow instance and build internal gui items
+	 *
+	 * @return void
+	 */
+	public function __construct()
+	{
+		if(self::$check == FALSE)
+		{
+			throw new Exception(Writer::i18n(
+			'%1$s is a singleton class - use %1$s::instance() to retrieve the current object',
+			'ProjectWindow'));
+		}
+		self::$singleton = $this;
+
+		parent::__construct();
+
+		return;
+	}
+
+	/**
+	 * static public function instance
+	 *
+	 * this is how you "construct" a ProjectWindow object
+	 *
+	 * @return object instanceof ProjectWindow
+	 */
+	static public function instance()
+	{
+		if(is_null(self::$singleton))
+		{
+			self::$check = TRUE;
+			self::$singleton = new ProjectWindow();
+			self::$check = FALSE;
+		}
+		return self::$singleton;
+	}
+
+	/**
+	 * public function __clone()
+	 *
+	 * disable cloning of a singleton
+	 *
+	 * @return void
+	 */
+	public function __clone()
+	{
+		throw new Exception(Writer::i18n('Cannot clone singleton object %s', 'ProjectWindow'));
+		return;
+	}
+}
+?>
\ No newline at end of file
Property changes on: desktop/trunk/Writer/lib/project/window.class.php
___________________________________________________________________
Name: tsvn:logminsize
   + 15
Name: svn:keywords
   + Id
Name: svn:eol-style
   + LF

Deleted: desktop/trunk/Writer/lib/theme.class.php (23 => 24)


--- desktop/trunk/Writer/lib/theme.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/theme.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -1,138 +0,0 @@
-<?php
-/**
- * theme.class.php - default theme to override hicolor
- *
- * this loads in app specific icons and a matching FULL default
- * stock images theme to override hicolor (which is ugly as sin)
- * user gtk windowing/icon themes should override any of these
- * except the app specific stuff
- *
- * This is released under the GPL, see license.txt for details
- *
- * @author       Elizabeth Smith <emsmith@callicore.net>
- * @copyright    Elizabeth Smith (c)2006
- * @link         http://callicore.net/writer
- * @license      http://www.opensource.org/licenses/gpl-license.php GPL
- * @version      $Id$
- * @since        Php 5.2.0
- * @package      callicore
- * @subpackage   writer
- * @category     lib
- * @filesource
- */
-
-/**
- * Theme - basic icon theme management
- *
- * notice the singleton way to grab the class
- */
-class Theme
-{
-
-	/**
-	 * Icon sizes - these SHOULD be constants - but
-	 * you can't set class constants after the class is defined
-	 * so they're static vars instead - annoying
-	 *
-	 * sizes are 16, 18, 20, 14, 32, 48, 64 and 128 px square
-	 *
-	 * @var GtkEnum
-	 */
-	static public $MENU = Gtk::ICON_SIZE_MENU;
-	static public $SMALL_TOOLBAR = Gtk::ICON_SIZE_SMALL_TOOLBAR;
-	static public $BUTTON = Gtk::ICON_SIZE_BUTTON;
-	static public $LARGE_TOOLBAR = Gtk::ICON_SIZE_LARGE_TOOLBAR;
-	static public $DND = Gtk::ICON_SIZE_DND;
-	static public $DIALOG = Gtk::ICON_SIZE_DIALOG;
-	static public $LARGE;
-	static public $IMAGE;
-
-	/**
-	 * singleton instance for this class
-	 * @var $singleton instanceof Theme
-	 */
-	static public $singleton;
-
-	/**
-	 * default icon theme for current gdk screen
-	 * @var $theme instanceof GtkIconTheme
-	 */
-	protected $theme;
-
-	/**
-	 * public function __construct
-	 *
-	 * registers two new icon sizes, parses the hicolor override rc file and the
-	 * application specific rc file, also sets default window icon
-	 *
-	 * @return void
-	 */
-	public function __construct()
-	{
-		if(!is_null(self::$singleton))
-		{
-			throw new Exception('Theme is a singleton class - use Theme::singleton() to retrieve the current instance');
-		}
-
-		self::$singleton = $this;
-
-		self::$LARGE = Gtk::icon_size_register('gtk-large',64, 64);
-		self::$IMAGE = Gtk::icon_size_register('gtk-image',128, 128);
-
-		Gtk::rc_parse(DIR . 'images' . DS . 'stock' . DS . 'stock.rc');
-
-		Gtk::rc_parse(DIR . 'images' . DS . 'images.rc');
-
-		$this->theme = GtkIconTheme::get_for_screen(GdkScreen::get_default());
-		$this->addThemeIcon('writer-icon');
-
-		GtkWindow::set_default_icon_name('writer-icon');
-
-		return;
-	}
-
-	/**
-	 * public function addThemeIcon
-	 *
-	 * adds an icon to the current theme, really only needs to be
-	 * done with the writer-icon image
-	 *
-	 * @param string $stock stock name from rc file
-	 * @return void
-	 */
-	public function addThemeIcon($stock)
-	{
-		$window = new GtkWindow();
-		$this->theme->add_builtin_icon($stock, self::$MENU,
-			$window->render_icon($stock, self::$MENU));
-		$this->theme->add_builtin_icon($stock, self::$SMALL_TOOLBAR,
-			$window->render_icon($stock, self::$SMALL_TOOLBAR));
-		$this->theme->add_builtin_icon($stock, self::$BUTTON,
-			$window->render_icon($stock, self::$BUTTON));
-		$this->theme->add_builtin_icon($stock, self::$LARGE_TOOLBAR,
-			$window->render_icon($stock, self::$LARGE_TOOLBAR));
-		$this->theme->add_builtin_icon($stock, self::$DND,
-			$window->render_icon($stock, self::$DND));
-		$this->theme->add_builtin_icon($stock, self::$DIALOG,
-			$window->render_icon($stock, self::$DIALOG));
-		$this->theme->add_builtin_icon($stock, self::$LARGE,
-			$window->render_icon($stock, self::$LARGE));
-		$this->theme->add_builtin_icon($stock, self::$IMAGE,
-			$window->render_icon($stock, self::$IMAGE));
-		unset($window, $stock);
-		return;
-	}
-
-	/**
-	 * public function singleton
-	 *
-	 * grab and return the instance
-	 *
-	 * @return object instanceof Theme
-	 */
-	static public function singleton()
-	{
-		return self::$singleton;
-	}
-}
-?>
\ No newline at end of file

Modified: desktop/trunk/Writer/lib/tooltips.class.php (23 => 24)


--- desktop/trunk/Writer/lib/tooltips.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/tooltips.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -2,7 +2,7 @@
 /**
  * tooltips.class.php - wrapper for gtktooltips
  *
- * handles forcing a tooltip singleton and translating tip
+ * handles forcing a tooltip singleton
  *
  * This is released under the GPL, see license.txt for details
  *
@@ -21,8 +21,7 @@
 /**
  * Tooltips - tooltips wrapper
  *
- * does gettext on any tooltip sent, fixes the weirdness
- * of toolbar tooltips, and forces a tooltip singleton
+ * fixes the weirdness of toolbar tooltips, and forces a tooltip singleton
  */
 class Tooltips extends GtkTooltips
 {
@@ -31,9 +30,15 @@
 	 * singleton instance for this class
 	 * @var $singleton instanceof Tooltips
 	 */
-	static public $singleton;
+	static protected $singleton;
 
 	/**
+	 * switches on to allow construct to occur
+	 * @var $check bool
+	 */
+	static protected $check = FALSE;
+
+	/**
 	 * public function __construct
 	 *
 	 * registers two new icon sizes, parses the hicolor override rc file and the
@@ -43,10 +48,13 @@
 	 */
 	public function __construct()
 	{
-		if(!is_null(self::$singleton))
+		if(self::$check == FALSE)
 		{
-			throw new Exception('Tooltips is a singleton class - use Tooltips::singleton() to retrieve the current instance');
+			throw new Exception(Writer::i18n(
+			'%1$s is a singleton class - use %1$s::instance() to retrieve the current object',
+			'Tooltips'));
 		}
+		self::$singleton = $this;
 
 		parent::__construct();
 		self::$singleton = $this;
@@ -68,26 +76,45 @@
 	{
 		if($widget instanceof GtkToolItem)
 		{
-			$widget->set_tooltip($this, _($tooltip));
+			$widget->set_tooltip($this, $tooltip);
 		}
 		else
 		{
-			parent::set_tip($widget, _($tooltip));
+			parent::set_tip($widget, $tooltip);
 		}
 		unset($widget, $tooltip);
 		return;
 	}
 
 	/**
-	 * public function singleton
+	 * static public function instance
 	 *
-	 * grab and return the instance
+	 * this is how you "construct" a Tooltips object
 	 *
 	 * @return object instanceof Tooltips
 	 */
-	static public function singleton()
+	static public function instance()
 	{
+		if(is_null(self::$singleton))
+		{
+			self::$check = TRUE;
+			self::$singleton = new Tooltips();
+			self::$check = FALSE;
+		}
 		return self::$singleton;
 	}
+
+	/**
+	 * public function __clone()
+	 *
+	 * disable cloning of a singleton
+	 *
+	 * @return void
+	 */
+	public function __clone()
+	{
+		throw new Exception(Writer::i18n('Cannot clone singleton object %s', 'Tooltips'));
+		return;
+	}
 }
 ?>
\ No newline at end of file

Modified: desktop/trunk/Writer/lib/writer.class.php (23 => 24)


--- desktop/trunk/Writer/lib/writer.class.php	2006-10-13 16:59:41 UTC (rev 23)
+++ desktop/trunk/Writer/lib/writer.class.php	2006-10-18 00:58:34 UTC (rev 24)
@@ -38,6 +38,24 @@
 	static public $appdata;
 
 	/**
+	 * Icon sizes - these SHOULD be constants - but
+	 * you can't set class constants after the class is defined
+	 * so they're static vars instead - annoying
+	 *
+	 * sizes are 16, 18, 20, 14, 32, 48, 64 and 128 px square
+	 *
+	 * @var GtkEnum
+	 */
+	static public $MENU = Gtk::ICON_SIZE_MENU;
+	static public $SMALL_TOOLBAR = Gtk::ICON_SIZE_SMALL_TOOLBAR;
+	static public $BUTTON = Gtk::ICON_SIZE_BUTTON;
+	static public $LARGE_TOOLBAR = Gtk::ICON_SIZE_LARGE_TOOLBAR;
+	static public $DND = Gtk::ICON_SIZE_DND;
+	static public $DIALOG = Gtk::ICON_SIZE_DIALOG;
+	static public $LARGE;
+	static public $IMAGE;
+
+	/**
 	 * public function __construct
 	 *
 	 * checks for requirements, runs the splash screen,
@@ -49,11 +67,12 @@
 	public function __construct()
 	{
 		$this->checkRequirements();
+		$this->findFolders();
+		$this->theme();
 
-		// we use system locale
-		bindtextdomain('Writer', DIR . 'locale');
-		textdomain('Writer');
-
+Db::instance('test.cwp');
+CharacterWindow::instance();
+return;
 		$splash = new SplashScreen();
 
 		$splash->update('Initializing Messages');
@@ -108,73 +127,82 @@
 			{
 				$file = 'gnome-open "' . $file . '"';
 			}
+			return exec($file);
 		}
 		elseif(stristr(PHP_OS, 'win'))
 		{
-			$file = 'start "" "' . $file . '"';
+			return win_shell_execute($file, 'open');
 		}
 		elseif(stristr(PHP_OS, 'darwin') || stristr(PHP_OS, 'mac'))
 		{
 			$file = 'open "' . $file . '"';
+			return exec($file);
 		}
 		else
 		{
 			return FALSE;
 		}
-		self::exec($file);
-		unset($file);
 		return;
 	}
 
 	/**
-	 * public static function exec
+	 * public static function i18n
 	 *
-	 * overrides php exec for windows to avoid popping up dos windows (ugly)
+	 * wrapper for gettext + sprintf/vsprintf
 	 *
-	 * @param string $cmd command to execute
-	 * @return void
+	 * @param string $string string to translate
+	 * @return string translated string
 	 */
-	public static function exec($cmd)
+	public static function i18n($string)
 	{
-		if(stristr(PHP_OS, 'winnt'))
+		$args = func_get_args();
+		array_shift($args);
+		if(!empty($args) && count($args) == 1 && is_array($args[0]))
 		{
-			$shell = new COM('WScript.Shell');
-			$shell->Run('cmd /c ' . $cmd, 0, FALSE);
+			$args = $args[0];
 		}
-		elseif(stristr(PHP_OS, 'win32'))
-		{
-			$shell = new COM('WScript.Shell');
-			$shell->Run('command /c ' . $cmd, 0, FALSE);
-		}
-		else
-		{
-			$cmd = popen($cmd, 'r');
-			pclose($cmd);
-		}
-		unset($shell, $cmd);
-		return;
+		return gettext(vsprintf($string, $args));
 	}
 
 	/**
 	 * protected function checkRequirements
 	 *
-	 * checks that php version is 5.2 or greater and php extensions needed are loaded
+	 * checks that php version is 5.2 or greater and php extensions
+	 * needed are loaded
 	 *
 	 * @return void
 	 */
 	protected function checkRequirements()
 	{
+		if(extension_loaded('gettext'))
+		{
+			// we use system locale
+			bindtextdomain('Writer', DIR . 'locale');
+			textdomain('Writer');
+		}
+		else
+		{
+			function gettext($string)
+			{
+				return $string;
+			}
+		}
 		if(version_compare(PHP_VERSION, '5.1.0', '<'))
 		{
-			trigger_error('You must use php 5.1.0 or higher', E_USER_ERROR);
+			trigger_error(self::i18n('You must use php 5.1.0 or higher'), E_USER_ERROR);
 		}
 		$have = get_loaded_extensions();
-		$needed = array('standard', 'pcre', 'date', 'PDO', 'pdo_sqlite', 'gettext', 'php-gtk');
+		$needed = array('standard', 'pcre', 'date', 'PDO', 'pdo_sqlite',
+			'pspell', 'stem', 'php-gtk', 'gd', 'fileinfo');
+		if(stristr(PHP_OS, 'win'))
+		{
+			$needed[] = 'win32std';
+		}
 		$diff = array_diff($needed, $have);
 		if(!empty($diff))
 		{
-			trigger_error('The following extensions must be loaded in your php.ini for Writer to function :'
-				. implode($diff), E_USER_ERROR);
+			trigger_error(self::i18n('The following extensions must be loaded in your php.ini for Writer to function: %s',
+				implode(', ', $diff)), E_USER_ERROR);
 		}
 		unset($have, $needed, $diff);
 		return;
@@ -193,16 +221,16 @@
 		// check environment variables for appdir or use home/.projects
 		if(isset($_ENV['APPDATA']))
 		{
-			self::$appdata = $_ENV['APPDATA'] . DS . 'writer' . DS;
+			self::$appdata = $_ENV['APPDATA'] . DS . 'callicore' . DS;
 		}
 		elseif(stristr(PHP_OS, 'darwin'))
 		{
 			self::$appdata = self::$home . 'Library' . DS . 'Application Support'
-				. DS . 'writer' . DS;
+				. DS . 'callicore' . DS;
 		}
 		elseif(stristr(PHP_OS, 'linux') || stristr(PHP_OS, 'freebsd') || stristr(PHP_OS, 'unix'))
 		{
-			self::$appdata = self::$home . '.writer' . DS;
+			self::$appdata = self::$home . 'callicore' . DS;
 		}
 		else
 		{
@@ -214,7 +242,58 @@
 			mkdir(self::$appdata);
 		}
 
+		self::$appdata .= 'writer' . DS;
+
+		if(!file_exists(self::$appdata))
+		{
+			mkdir(self::$appdata);
+		}
+
 		return;
 	}
+
+	/**
+	 * public function theme
+	 *
+	 * registers two new icon sizes, parses the hicolor override rc file and the
+	 * application specific rc file, also sets default window icon
+	 *
+	 * @return void
+	 */
+	protected function theme()
+	{
+
+		self::$LARGE = Gtk::icon_size_register('gtk-large',64, 64);
+		self::$IMAGE = Gtk::icon_size_register('gtk-image',128, 128);
+
+		Gtk::rc_parse(DIR . 'images' . DS . 'stock' . DS . 'stock.rc');
+
+		Gtk::rc_parse(DIR . 'images' . DS . 'images.rc');
+
+		$theme = GtkIconTheme::get_for_screen(GdkScreen::get_default());
+
+		$window = new GtkWindow();
+		$theme->add_builtin_icon('writer-icon', self::$MENU,
+			$window->render_icon('writer-icon', self::$MENU));
+		$theme->add_builtin_icon('writer-icon', self::$SMALL_TOOLBAR,
+			$window->render_icon('writer-icon', self::$SMALL_TOOLBAR));
+		$theme->add_builtin_icon('writer-icon', self::$BUTTON,
+			$window->render_icon('writer-icon', self::$BUTTON));
+		$theme->add_builtin_icon('writer-icon', self::$LARGE_TOOLBAR,
+			$window->render_icon('writer-icon', self::$LARGE_TOOLBAR));
+		$theme->add_builtin_icon('writer-icon', self::$DND,
+			$window->render_icon('writer-icon', self::$DND));
+		$theme->add_builtin_icon('writer-icon', self::$DIALOG,
+			$window->render_icon('writer-icon', self::$DIALOG));
+		$theme->add_builtin_icon('writer-icon', self::$LARGE,
+			$window->render_icon('writer-icon', self::$LARGE));
+		$theme->add_builtin_icon('writer-icon', self::$IMAGE,
+			$window->render_icon('writer-icon', self::$IMAGE));
+		unset($window, $theme);
+
+		GtkWindow::set_default_icon_name('writer-icon');
+
+		return;
+	}
 }
 ?>
\ No newline at end of file