420 likes | 522 Views
Smallworld 2007 Americas Users Conference. Overview. We’ll start by accessing web services using HTTP …and build up an example with KML support Then discuss plugin’s, engines, and models …and create a gui to use the KML data This is a workshop,
E N D
Overview We’ll start by accessing web services using HTTP …and build up an example with KML support Then discuss plugin’s, engines, and models …and create a gui to use the KML data This is a workshop, so we’ll try to get to the exercises quickly …and, this is interactive, so questions, comments, and ideas are welcome and encouraged throughout!
Mclib_* module Notes Several of the modules we’ll use today: • action_property_mixin • dialog_designer • embedding_plugin_mixin • http_interface • http_server • kml_import • kml_export • plugin_threading_mixin can be located on sourceforge.net: • In the latest file release or in the CVS repository • See http://www.sourceforge.net/projects/magikcmpnts • All are released under the GNU Public License or Lesser GNU Public License Please contribute bugs, fixes, enhancements or additional modules back to the community!
Interacting with the world: Access web services http_interface kml_import kml_export Read “Google Earth” KML data Create Google Earth KML data
http_interface http_request • Models a connection via some URL • Built using native TCP socket support in Magik • No ACP or other external tools required • Includes Limited support for HTTP basic authentication • A connect() request returns an http_response object • Example: hreq<< http_request.new_for_url(“ http://code.google.com/apis/kml/documentation/KML_Samples.kml") hres << hreq.connect()
http_interface http_response • The result of executing some request • Includes the response code, content type, etc. • Resulting data is also captured in this object • Example: hres << hreq.connect() some_xml << hres.smart_result() some_raster << hres.smart_result() some_string << hres.smart_result() raw_text << hres.result_string smart_result() decides what to return based on content type.
Exercise 0 – Setup Steps: • Copy the code to your local environment • Go to z:\sw2007 • Copy everything there to c:\sw2007\adv_magik • Add the mclib product to your image • sw_module_dialog.open() • add product… • Add the workshop product to your image • sw_module_dialog.open() • add product…
Exercise 1 – Use a web service In this exercise, we will: • Learn to open a connection with the http_interface classes • Use the results of that connection from within Magik We will use:
Exercise 1 – Use a web service Steps: • Load the mclib_http_interface module • sw_module_dialog.open()…etc…. • Create an http_request to get some XML • hreq << mclib:http_request.new_for_url(_unset,_unset,“http://192.168.123.5/sample.xml”) • hr << hreq.connect() • some_xml << hr.smart_result() • Create an http_request to get some text • hreq << mclib:http_request.new_for_url(_unset,_unset,“http://192.168.123.5/sample.txt”) • hr << hreq.connect() • a_string << hr.smart_result() • Create an http_request to get an image • hreq << mclib:http_request.new_for_url(_unset,_unset,“http://192.168.123.5/sample.dib”) • hr << hreq.connect() • a_raster << hr.smart_result() • You can also skip the connect step: • some_xml << http_request.new_for_url(_unset,_unset,“http://localhost/sample.xml”).smart_result()
kml_export • Provides support for generating KML from RWOs and sets of RWOs • Supports: • URIs in the output for reference back to original records • Physical / Logical Fields • Geometriy fields • Styles • Crude interpretation of line/area styles • Creation of bitmaps for point styles ( see mclib_style_images ) • File or string or stream results • Implemented throughout the system: • some_rwo.set.as_kml() • some_map_trail.as_kml() • some_rwo_set.as_kml() • something.kml_style() [rwos, style objects, trails ] • Some_geom.as_kml_entity() • some_rwo_set.write_kml_on() some_rwo_set.write_kml_file() • Subclass behavior on specific objects to improve the KML output • Examples: • v.collections[:pub_rest].as_kml() • v.collections[:pub_rest].write_kml_file(“c:\temp\pubs.kml”)
kml_export Sample Results:
kml_import • Provides classes for reading KML into a kml_document object • Kml_document is a subclass of xml_doicument for representing these • Provides kml_document.rwo_set() to get back “records” and geometry • Many subclasses provided to work with the elements in a KML document • Still lots of work to be done to make this better • Supports: • Basic KML items – placemarks, points, lines, area • Folders – Create collections • Opening a document and using it as a dataset (see example) • Creation of description and snippet “fiields” • Basic KML style interpretation into Magik styles • Does NOT support: • Network links in KML • Image overlays • Lots of other KML capabilities!! • Create new classes to extend kml_import capabilities: • kml_point_element entries in a KML file like <Point> … </Point> • kml_element automatically selects the class to use for each element if it exists This also provides a nice example for modeling other XML schemas in Magik…
kml_import • Examples: kml_doc << kml_document.new(_unset,_unset) Base instance kml_doc << simple_xml.read_document_file( “c:\temp\sample.kml”,_unset,a_kml_doc) Read file / populate elements kml_doc.rwo_set() Gets records in all “collections” kml_doc.open() Process objects and creates transisent_dataset kml_doc.dataset_manager get the dataset_manager for it gis_program_manager.spatial_object_controller(:gis). add_dataset_manager(kml_doc.dataset_manager)) Add this dataset to the SOC…don’t forget ACE settings!
Exercise 2 – Work with KML data In this exercise, we will: • Retrieve a KML file via HTTP and turn it into a kml_document • Look at the records created from the file We will use:
Exercise 2 – Work with a KML Document Steps: • Load the mclib_kml_import module • Get a kml_document via HTTP • hreq << http_request.new_for_url(“http://192.168.123.5/cambridge.kml”) • hr << hreq.connect() • kml_doc << hr.smart_result() • kml_doc.open() • See the records in it: • kml_doc.rwo_set() • kml_doc.dataset
Float and embed on tabs Smarter Plugins: embedding_plugin_mixin plugin_threading_mixin action_property_mixin Background processing Manage properties and actions
embedding_plugin_mixin • Provides support for tear-off / re-embedding tabs • Allows a plugin to display itself in a separate frame without a gui_framework and application plugin How to use it: • Have your plugin inherit from the mixin • add the launched_panel property to your plugin • Call init_embedding_actions() from init_actions() • Create an appropriate role for the embedding location in the gui.xml • Use place_embedded_close_action() in build_gui() to add the embed/tear-off actions
plugin_threading_mixin • Provides support for managing threads from a plugin • Support one or multiple threads within a plugin • Delivers behavior like “engine_model” for any plugin • Is implemented as a mixin so you can include it with any new or existing class • Consists of: • plugin_threading_mixin • Provides standard behavior for your plugin • Includes actions to start/stop/suspend/resume threads • Includes capability for different threads in a plugin, identified by a TAG • threading_plugin • the class which manages a single thread • Does the actual forking and killing of a thread • Reports status to its framework, such as an instance of plugin_threading_mixin
plugin_threading_mixin How to use it: • Have your plugin inherit from the mixin • Add the slot :thread_engines and ensure it is readable and initialized to a property_list • Call build_threading_actions() from init_actions() • Implement the method run_engine_standard() to carry the background thread operations. • Include the actions in build_gui() to start, stop the threaded operations • Optional: • Support multiple threads running at the same time: • Define additional engine types in the :thread_engine_types shared constant. • Implement run_engine_<TYPE> for each of them • Use actions such as :run_engine<TYPE> to create a GUI with each type • Disable actions when the engine starts: • Add calls to add_run_disabled_action(a_action) • Create additional actions to start the engine • Subclass extra_threading_run_actions() to return appropriate sw_action_defs • The mixin and threading_plugins handle all the visibility updates, etc. for these actions
action_property_mixin • Supports the creation of actions for a plugins properties • Allows the action to get its value form the property • And, changing the action updates the property • The details of the action are defined form the property • Handles only basic settings on the action: • Type of control – menu and dialog • Value manager – limited se of choices • Action class – e.g. uses mclib_directory_action
action_property_mixin How to use it: • Have your plugin inherit from the mixin • Create the properties you want to use as usual. • Call add_property_action() from your init_actions(). Pass any any additional properties you want to set on it. • An appropriate action is created an returned • Optional: • Subclass menu_control_for_property() and toolbar_control_for_property() • Subclass value_manager_for()
Plugins, Engines, or Both? • Should a plugin include a separate “engine” class? • Conventional teaching in Magik is to split operation and GUI classes • When working with the Model class this provided: • separation of action from gui • the ability to reuse the action in a new context • a way to control the dependencies on instantiated GUI elements, and the dreaded graphics_system • lots of clever code could do the same, but hooking up two classes makes for a nice neat abstraction • The benefits come • at the expense of the effort to hook the classes together • with the need to keep code aligned between the classes • with many approaches to connecting them – dependencies, .owner slots, conditions
Plugins, Engines, or Both? • With the component framework and SWAF architectures: • The separation of operation from GUI is automatic • actions provide this • Plugins can be configured with XML or through direct creation • Any well written plugin can be used without ever calling build_gui() • But… • Code can get messy if it needs to deal with actions and properties • Thus action_property_mixin to manage actions based on properties • Heavy gui elements are not actions e.g. tree_item • Perhaps we approach it from the opposite perspective…. • Almost every class should be a plugin even if you can’t imagine a gui at first • Its easy to add actions later to manage the properties • but much harder to take a raw engine and make it into a plugin later
Exercise 3 – Export KML data In this exercise, we will: • Use a plugin with several of the mixins mentioned included • Use the kml_export module to output selected records to Google Earth We will use:
Exercise 3 – Export KML data Steps: • Load the mclib_kml_export module • Load the required mixins – mclib_plugin_threading_mixin, mclib_embedding_plugin_mixin, and mclib_action_property_mixin • Open the kml_dumper.magik file in Emacs • Compile the file into the session • kd << kml_dumper.new(:test,app) • kd.activate_embedded_or_standalone() • Select some objects on the map • Use the displayed GUI to run a sample dump and see the results in Google Earth • Enable embedding • kd << kml_dumper.new(:test,app) • kd.embedded_role_name << :viewport_mapping • kd.activate_embedded_or_standalone() • Try out peeling and embedding the panel • Review the code • Check the init_actions() method for • details on getting the embedding the threading actions • Use of the add_property_action() method • Look at build_gui() to see the support for embedding / peeling buttons
GUI elements Menubar / Statusbar Databus / Docks Save / Restore Designs The Challenge - SW4 GUI Layouts Manage Generate Magik / XML Module / Messages Test Activate / re-activate a GUI
Starting the Dialog Designer Target Layout Step-by-step design Embedding in the Main GUI Adding behavior to the GUI class SW-2007 Workshop
MagikSF> sw_module_dialog.open() Select ‘dialog_designer’ in the mclib_core_swaf Press ‘Load Module’ MagikSF> dialog_designer.open() Starting Dialog Designer
Buttons Load File Delete Style Choices Point Line Area Tabular List ‘post_render_sets’ Producer Target Layout
L-Mouse to enter ‘tabular list’ insert-mode Mouse into rendered dialog (not dragging) L-Mouse when red ‘drop-area’ visible Press space-bar to change to ‘select’ mode Select the inserted list and modify attributes: aspect = kml_list column_headings = Type,File dialog_element_id = kml_list File List
L-Mouse to enter ‘rowcol’ insert-mode Move mouse into rendered dialog L-Mouse when red ‘drop-area’ visible to the right of the tabular list RowCol
L-Mouse to enter ‘style-choice’ insert-mode L-Mouse 3 times when red ‘drop-area’ visible inside the last RowCol to place 3 style widgets Select the top style widget set style_type = point_style middle widget style_type = line_fg_colour Style Choices
L-Mouse to enter ‘rowcol’ insert-mode Move mouse into rendered dialog L-Mouse when red ‘drop-area’ visible above the style widgets RowCol
Click to enter ‘file/directory’ insert-mode L-Mouse into red ‘drop-area’ visible inside the last RowCol Select inserted widget has_border = No File/Directory Selector
Click to enter ‘Image Button’ insert-mode L-Mouse into red ‘drop-area’ visible inside the last RowCol Select inserted widget R-Mouse in editor Set Image Source Find and select ‘delete’ in ‘ui_resources’ module Delete button
Press to access ‘Databus’ tab If no applications running then … start the ‘Workshop Application’ Press to refresh the Databus GUI Select ‘post_render_sets’ in the lower left list App CONSUMED Data Types R-mouse and ‘Add to list ’ Producing ‘post_render_sets’
Select the TitleBar in the rendered GUI Title = KML Loader Set the class name Start Module properties… Set the base class to “kml_file_loader” Select the outermost RowCol col_resize_values = 100,0 Detoggle to hide guidelines Try it out…Click the Build/Activate button Final GUI touches …
Dialog | Save as … Save it to: c:\sw2007\adv_workshop\kml_loader.xml Generates an XML file Full description of the dialog design Dialog Designer can reload from this file You could use it to create a GUI standard Base more complex GUIs on simpler ones Copy/Paste elements from one design to another by loading both into the Dialog Designer Save the GUI …
In the workshop application directory ..\resources\base\data Edit: config.xml <plugin name=“kml_loader" class_name=“kml_file_loader"/> gui.xml <tab_box role="viewport_mapping"> <plugin plugin_name=“kml_loader"/> … </tab_box> Restart the application to see you new plugin! Embedding in Main GUI
We need to create code for: Open File and Delete Create the code to handle these actions List ‘On Selection’ code modify style choice visibility Code to modify style for KML Layer Luckily, we started this for you… Copy c:\sw2007\adv_workshop\kml_loader_2.magik to c:\temp\kml_file_loader\kml_loader_2.magik Reload the kml_file_module in the default_product Restart the application to see the new behavior Adding behavior to the GUI class
Click the Open button and locate a KML file C:\sw2007\advmagik\cambridge.kml Try changing the styles, colors, etc…. And refresh to display the new KML results Try it out