Inspired by Marc Quinton I made an application for on-line generating KML files with the GPS coordinates of developers here. It can be used as a simple example of using some Gtk widget, PHP DOM extension, XMLRPC and for flying over our heads - enjoy :)
A KML file is a simple XML file which can be opened by GoogleEarth.
<?php
/*
* KML file generator
* (c) june 2007, Jan Fosfor Pospisil
* jabber: fosfor@jabber.cz
* icq: 96560956
* email: fosfor.software@seznam.cz
* web: http://www.vpp-net.com/php-gtk/
* originaly posted at: http://www.php-gtk.eu/
*
* This application is able to generate KML file (XML structure) from selected
* user from the database of the developers registered at www.php-gtk.eu .
*
* It show usage of widgets:
* GtkAboutDialog, GtkMessageDialog
* GtkFileSelection
* GtkTreeView
* menu
* toolbar
* and algorithm for:
* DOM
* XMLRPC
*
* Original code of XMLRPC access to the server was adopted from Marc Quinton.
*
* Thanks to all on www.php-gtk.eu and irc #php-gtk :)
*
*/
error_reporting(E_ALL);
require_once 'XML/RPC.php';
if (!class_exists('gtk'))
die('Please load the php-gtk2 module.'.PHP_EOL);
/*
* handler for application end
*/
function hnd_quit() {
gtk::main_quit();
}
/*
* handler for About menu item
*/
function hnd_about() {
$dlg = new GtkAboutDialog();
$dlg->set_name('KML generator');
$dlg->set_version('0.1');
$dlg->set_comments(
'Generate KML file (XML) whitch can by opened by GoogleEarth.'.PHP_EOL.
'The KML file contains GPS coordinations of PHP-GTK developers registered'.
' at www.php-gtk.eu.'
);
$dlg->set_copyright('Copyright (C) 2007 Jan Pospisil');
$dlg->set_license('Free for non-comercial use.');
$dlg->set_logo(
$dlg->render_icon(Gtk::STOCK_DIALOG_INFO, Gtk::ICON_SIZE_DIALOG)
);
$dlg->set_website('http://www.vpp-net.com/php-gtk');
$dlg->run();
$dlg->destroy();
}
/*
* function to reload data from the internet to the treeview
*/
function reload_data() {
global $model;
// Prepare the request data
$host = 'www.php-gtk.eu';
$port = 80;
$backend = '/xmlrpc.php';
// XML-RPC API description here : http://www.php-gtk.eu/site/geo-nick
$params = array ();
$msg = new XML_RPC_Message('gtkphpnet.geo_nick', $params);
$cli = new XML_RPC_Client($backend, $host);
$resp = $cli->send($msg);
if (!$resp)
return false; // exception ?
if ($resp->faultCode())
return false; // exception ?
$val = $resp->value();
$data = XML_RPC_decode($val);
$model->clear();
foreach ($data as $user => $coords) {
if ($coords[0] && $coords[1]) {
$tmp = array();
$tmp[0] = true;
$tmp[1] = $user;
$tmp[2] = $coords[1]*1;
$tmp[3] = $coords[0]*1;
$model->append($tmp);
}
}
}
/*
* handler for select/deselect row
*/
function row_activated() {
global $tree, $model;
$selection = $tree->get_selection();
list($model, $iter) = $selection->get_selected();
$value = $model->get_value($iter, 0);
$model->set($iter, 0, !$value);
}
/*
* function to show Save dialog
*/
function save() {
$filePrompt = new GtkFileSelection('Save to...');
$filePrompt->cancel_button->connect_simple('clicked', array($filePrompt, 'destroy'));
$filePrompt->ok_button->connect('clicked', 'export');
$filePrompt->show();
}
function dialog_box($text, $inform = true) {
global $wnd;
$dialog = new GtkMessageDialog(
$wnd,
Gtk::DIALOG_DESTROY_WITH_PARENT,
(($inform)?Gtk::MESSAGE_INFO:Gtk::MESSAGE_QUESTION),
(($inform)?Gtk::BUTTONS_OK:Gtk::BUTTONS_YES_NO),
$text
);
$answer = $dialog->run();
$dialog->destroy();
if ($inform)
return true;
if ($answer == Gtk::RESPONSE_YES)
return true;
return false;
}
/*
* function to process one row into XML output
*/
function process_row($model, $path, $iter, $dom, $folder) {
$export = $model->get_value($iter, 0);
if (!$export)
return;
$user = $model->get_value($iter, 1);
$long = $model->get_value($iter, 2);
$lat = $model->get_value($iter, 3);
$placemark = $dom->createElement('Placemark');
$pm_name = $dom->createElement('name', $user);
$pm_vis = $dom->createElement('visibility', '1');
$pm_style = $dom->createElement(
'styleUrl',
'#default+icon=http://maps.google.com/mapfiles/kml/pal3/icon63.png'
);
$pm_point = $dom->createElement('Point');
$coords = $dom->createElement(
'coordinates',
str_replace(',', '.', $long) . ',' . str_replace(',', '.', $lat) . ',0'
);
$folder->appendChild($placemark);
$placemark->appendChild($pm_name);
$placemark->appendChild($pm_vis);
$placemark->appendChild($pm_style);
$placemark->appendChild($pm_point);
$pm_point->appendChild($coords);
}
/*
* function to process all selected rows into KML file (XML output)
*/
function export($okbutton) {
global $model;
$filePrompt = $okbutton->get_toplevel();
$fileName = $filePrompt->get_filename();
if (is_dir($fileName)) {
dialog_box('Please select file to write the data.');
return;
} else if (file_exists($fileName))
if (!dialog_box('File exitst. Overwrite?', false))
return;
$filePrompt->destroy();
$dom = new DOMDocument('1.0', 'utf-8');
$main_kml = $dom->createElement('kml');
{$main_kml->setAttribute('xmlns', 'http://earth.google.com/kml/2.1');}
$document = $dom->createElement('Document');
$name = $dom->createElement('name', 'PHP-GTK developers');
$folder = $dom->createElement('Folder');
$folder_name = $dom->createElement('name', 'php-gtk.eu');
$folder_vis = $dom->createElement('visibility', '1');
$dom->appendChild($main_kml);
$main_kml->appendChild($document);
$document->appendChild($name);
$document->appendChild($folder);
$folder->appendChild($folder_name);
$folder->appendChild($folder_vis);
$model->foreach('process_row', $dom, $folder);
if ((strpos($fileName, '.') === false) && (!file_exists($fileName)))
$fileName .= '.kml';
$fp = fopen($fileName, 'w');
fwrite($fp, $dom->saveXML());
fclose($fp);
}
/*
* function to process row by row when (de)selecting all
*/
function select_row($model, $path, $iter, $select = true) {
$model->set($iter, 0, $select);
}
/*
* main application - building GUI
*/
/*
* model for storing data
*/
$model = new GtkListStore(
Gtk::TYPE_BOOLEAN,
Gtk::TYPE_STRING,
Gtk::TYPE_DOUBLE,
Gtk::TYPE_DOUBLE
);
$model->set_sort_column_id(1, Gtk::SORT_ASCENDING);
/*
* building GUI element and setting properities
*/
$wnd = new GtkWindow();
{$wnd->connect_simple('destroy', 'hnd_quit');}
{$wnd->set_title('KML generator');}
{$wnd->set_default_size(600, 600);}
{$wnd->set_position(Gtk::WIN_POS_CENTER);}
$main = new GtkVBox();
$mn = new GtkMenuBar();
$mniFile = new GtkMenuItem('_File');
$mnuFile = new GtkMenu();
$mniFileQuit = new GtkImageMenuItem(Gtk::STOCK_QUIT);
{$mniFileQuit->connect_simple('activate', 'hnd_quit');}
$mniHelp = new GtkMenuItem('_Help');
$mnuHelp = new GtkMenu();
$mniHelpAbout = new GtkImageMenuItem(Gtk::STOCK_ABOUT);
{$mniHelpAbout->connect_simple('activate', 'hnd_about');}
$tb = new GtkToolbar();
{$tb->set_show_arrow(false);}
$tbReload = new GtkToolButton(
GtkImage::new_from_stock(Gtk::STOCK_REFRESH, Gtk::ICON_SIZE_SMALL_TOOLBAR),
'Reload data'
);
{$tbReload->connect_simple('clicked', 'reload_data');}
$tbSave = GtkToolButton::new_from_stock(Gtk::STOCK_SAVE);
{$tbSave->connect_simple('clicked', 'save');}
$tbAll = new GtkToolButton(
GtkImage::new_from_stock(
Gtk::STOCK_APPLY,
Gtk::ICON_SIZE_SMALL_TOOLBAR
),
'Select All'
);
{$tbAll->connect_simple('clicked', array($model,'foreach'), 'select_row');}
$tbNone = new GtkToolButton(
GtkImage::new_from_stock(
Gtk::STOCK_CANCEL,
Gtk::ICON_SIZE_SMALL_TOOLBAR
),
'Select None'
);
{$tbNone->connect_simple('clicked', array($model,'foreach'), 'select_row', false);}
$scrl = new GtkScrolledWindow();
{$scrl->set_property('hscrollbar-policy', Gtk::POLICY_AUTOMATIC);}
{$scrl->set_property('vscrollbar-policy', Gtk::POLICY_AUTOMATIC);}
$tree = new GtkTreeView($model);
{$tree->set_search_column(1);}
{$tree->connect_simple('row-activated', 'row_activated');}
$clmnExport = new GtkTreeViewColumn(
'Export',
new GtkCellRendererToggle(),
'active',
0
);
{$clmnExport->set_sort_column_id(0);}
$clmnName = new GtkTreeViewColumn('Name', new GtkCellRendererText(), 'text', 1);
{$clmnName->set_sort_column_id(1);}
$clmnX = new GtkTreeViewColumn('Longitude', new GtkCellRendererText(), 'text', 2);
{$clmnX->set_sort_column_id(2);}
$clmnY = new GtkTreeViewColumn('Latitude', new GtkCellRendererText(), 'text', 3);
{$clmnY->set_sort_column_id(3);}
/*
* connecting GUI elements together
*/
$wnd->add($main);
$main->pack_start($mn, false);
$mn->append($mniFile);
$mniFile->set_submenu($mnuFile);
$mnuFile->append($mniFileQuit);
$mn->append($mniHelp);
$mniHelp->set_submenu($mnuHelp);
$mnuHelp->append($mniHelpAbout);
$main->pack_start($tb, false);
$tb->insert($tbReload, -1);
$tb->insert($tbSave, -1);
$tb->insert($tbAll, -1);
$tb->insert($tbNone, -1);
$main->pack_start($scrl);
$scrl->add($tree);
$tree->append_column($clmnExport);
$tree->append_column($clmnName);
$tree->append_column($clmnX);
$tree->append_column($clmnY);
/*
* and run it:)
*/
$wnd->show_all();
gtk::main();
?>PS: actual KML can be downloaded at http://www.vpp-net.com/php-gtk/
PPS: to this script, the PEAR implementation of XML-RPC can be used as well as the standard xml-rpc extension