[cairo-commit] roadster/src location.c, 1.4, 1.5 location.h, 1.2, 1.3 locationset.c, 1.9, 1.10 locationset.h, 1.5, 1.6 main.c, 1.18, 1.19 main.h, 1.1, 1.2 mainwindow.c, 1.34, 1.35 map.c, 1.36, 1.37 map.h, 1.15, 1.16 map_draw_cairo.c, 1.15, 1.16 map_draw_gdk.c, 1.12, 1.13 search_location.c, 1.8, 1.9 search_location.h, 1.2, 1.3 search_road.c, 1.17, 1.18 searchwindow.c, 1.16, 1.17

Ian McIntosh commit at pdx.freedesktop.org
Thu Mar 31 00:29:56 PST 2005


Committed by: ian

Update of /cvs/cairo/roadster/src
In directory gabe:/tmp/cvs-serv726/src

Modified Files:
	location.c location.h locationset.c locationset.h main.c 
	main.h mainwindow.c map.c map.h map_draw_cairo.c 
	map_draw_gdk.c search_location.c search_location.h 
	search_road.c searchwindow.c 
Log Message:
	* src/location.c: Inserting of POI and POI attributes.
	* src/locationset.c: Keep track of whether a set is visible.
	* src/search_road.c:
	* src/search_location.c: Add basic POI searching.
	* src/mainwindow.c: Sidebar now shows POI sets and can toggle their visibility.
	* src/map.c: Some changes to layer draw order to facilitate river borders.  Also made important roads get labeled first.
	* src/map_draw_cairo.c: Fixed Cairo road drawing bug from 2005-03-28's switch to road_t.
	* src/map_draw_gdk.c: Respect a POI set's visibility status.
	* src/searchwindow.c: Remove incorrect attempt to set results list not-sorted before adding results.
	* data/layers.xml: Major style changes.  Changed colors and added outlines for parks, lakes, rivers.


Index: location.c
===================================================================
RCS file: /cvs/cairo/roadster/src/location.c,v
retrieving revision 1.4
retrieving revision 1.5
diff -u -d -r1.4 -r1.5
--- location.c	29 Mar 2005 09:16:20 -0000	1.4
+++ location.c	31 Mar 2005 08:29:53 -0000	1.5
@@ -83,3 +83,25 @@
 	*pnReturnID = db_get_last_insert_id();
 	return TRUE;
 }
+
+gboolean location_insert_attribute(gint nLocationID, gint nAttributeID, const gchar* pszValue, gint* pnReturnID)
+{
+	g_assert(nLocationID != 0);
+	g_assert(nAttributeID != 0);
+	g_assert(pszValue != NULL);
+
+	gchar* pszSQL = g_strdup_printf(
+		"INSERT INTO LocationAttributeValue"
+		" SET LocationID=%d, AttributeNameID=%d, Value='%s';", 
+		nLocationID, nAttributeID, pszValue
+		);
+
+	db_query(pszSQL, NULL);
+	g_free(pszSQL);
+
+	if(pnReturnID) {
+		*pnReturnID = db_get_last_insert_id();
+	}
+	return TRUE;
+}
+

Index: location.h
===================================================================
RCS file: /cvs/cairo/roadster/src/location.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- location.h	29 Mar 2005 09:16:20 -0000	1.2
+++ location.h	31 Mar 2005 08:29:53 -0000	1.3
@@ -43,6 +43,7 @@
 gboolean location_alloc(location_t** ppLocation);
 void location_free(location_t* pLocation);
 gboolean location_insert(gint nLocationSetID, mappoint_t* pPoint, gint* pnReturnID);
+gboolean location_insert_attribute(gint nLocationID, gint nAttributeID, const gchar* pszValue, gint* pnReturnID);
 
 G_END_DECLS
 

Index: locationset.c
===================================================================
RCS file: /cvs/cairo/roadster/src/locationset.c,v
retrieving revision 1.9
retrieving revision 1.10
diff -u -d -r1.9 -r1.10
--- locationset.c	29 Mar 2005 09:16:20 -0000	1.9
+++ locationset.c	31 Mar 2005 08:29:53 -0000	1.10
@@ -56,7 +56,13 @@
 {
 	g_return_val_if_fail(g_LocationSet.m_pLocationSetChunkAllocator != NULL, NULL);
 
-	*ppReturn = g_mem_chunk_alloc0(g_LocationSet.m_pLocationSetChunkAllocator);
+	locationset_t* pNew = g_mem_chunk_alloc0(g_LocationSet.m_pLocationSetChunkAllocator);
+
+	// set defaults
+	pNew->m_bVisible = TRUE;
+
+	// return it
+	*ppReturn = pNew;
 	return TRUE;
 }
 
@@ -81,7 +87,7 @@
 // Load all locationsets into memory
 void locationset_load_locationsets(void)
 {
-	gchar* pszSQL = g_strdup_printf("SELECT ID, Name FROM LocationSet;");
+	gchar* pszSQL = g_strdup_printf("SELECT LocationSet.ID, LocationSet.Name, COUNT(Location.ID) FROM LocationSet LEFT JOIN Location ON (LocationSet.ID=Location.LocationSetID) GROUP BY LocationSet.ID;");
 
 	db_resultset_t* pResultSet = NULL;
 	if(db_query(pszSQL, &pResultSet)) {
@@ -93,6 +99,7 @@
 
 			pNewLocationSet->m_nID = atoi(aRow[0]);
 			pNewLocationSet->m_pszName = g_strdup(aRow[1]);
+			pNewLocationSet->m_nLocationCount = atoi(aRow[2]);
 
 			// Add the new set to both data structures
 			g_ptr_array_add(g_LocationSet.m_pLocationSetArray, pNewLocationSet);
@@ -119,6 +126,16 @@
 	return FALSE;	
 }
 
+gboolean locationset_is_visible(locationset_t* pLocationSet)
+{
+	return pLocationSet->m_bVisible;
+}
+
+void locationset_set_visible(locationset_t* pLocationSet, gboolean bVisible)
+{
+	pLocationSet->m_bVisible = bVisible;
+}
+
 #ifdef ROADSTER_DEAD_CODE
 /*
 // return a locationset struct (and all locations) to the allocator

Index: locationset.h
===================================================================
RCS file: /cvs/cairo/roadster/src/locationset.h,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- locationset.h	29 Mar 2005 09:16:20 -0000	1.5
+++ locationset.h	31 Mar 2005 08:29:53 -0000	1.6
@@ -38,16 +38,18 @@
 typedef struct locationset {
 	gint m_nID;
 	gchar* m_pszName;
+	gint m_nLocationCount;
+	gboolean m_bVisible;
 	locationsetstyle_t m_Style;
 } locationset_t;
 
 void locationset_init(void);
-
 void locationset_load_locationsets(void);
 const GPtrArray* locationset_get_array(void);
 gboolean locationset_find_by_id(gint nLocationSetID, locationset_t** ppLocationSet);
-
 gboolean locationset_insert(const gchar* pszName, gint* pnReturnID);
+void locationset_set_visible(locationset_t* pLocationSet, gboolean bVisible);
+gboolean locationset_is_visible(locationset_t* pLocationSet);
 
 G_END_DECLS
 

Index: main.c
===================================================================
RCS file: /cvs/cairo/roadster/src/main.c,v
retrieving revision 1.18
retrieving revision 1.19
diff -u -d -r1.18 -r1.19
--- main.c	29 Mar 2005 09:16:20 -0000	1.18
+++ main.c	31 Mar 2005 08:29:53 -0000	1.19
@@ -55,18 +55,28 @@
 	if(!main_init())
 		return 1;
 
-/*         gint nNewLocationSetID = 0;                                                                                                                             */
-/*         locationset_insert("Coffee Shops", &nNewLocationSetID);                                                                                                 */
-/*         mappoint_t pt;                                                                                                                                          */
-/*         pt.m_fLatitude = 41.54944;                                                                                                                              */
-/*         pt.m_fLongitude = -70.61409;                                                                                                                            */
-/*                                                                                                                                                                 */
-/*         gint nNewLocationID = 0;                                                                                                                                */
-/*         location_insert(nNewLocationSetID, &pt, &nNewLocationID);                                                                                               */
-/*                                                                                                                                                                 */
-/*         gchar* pszSQL = g_strdup_printf("INSERT INTO LocationAttributeValue SET LocationID=%d, AttributeNameID=1, Value='1369 Coffee House';", nNewLocationID); */
-/*         db_query(pszSQL, NULL);                                                                                                                                 */
-/*         g_free(pszSQL);                                                                                                                                         */
+	// Insert some POI for testing...
+/*
+	gint nNewLocationSetID = 0;
+	locationset_insert("Coffee Shops", &nNewLocationSetID);
+
+	gint nNewLocationID;
+
+	mappoint_t pt;
+	pt.m_fLatitude = 41.54930;  // these are in MA somewhere
+	pt.m_fLongitude = -70.61403;
+	nNewLocationID = 0;
+	location_insert(nNewLocationSetID, &pt, &nNewLocationID);
+	location_insert_attribute(nNewLocationID, LOCATION_ATTRIBUTE_ID_NAME, "1369 Coffee House", NULL);
+	location_insert_attribute(nNewLocationID, LOCATION_ATTRIBUTE_ID_ADDRESS, "1369 Cambridge Street\nCambridge, MA, 02141", NULL);
+
+	pt.m_fLatitude = 41.54762;
+	pt.m_fLongitude = -70.61409;
+	nNewLocationID = 0;
+	location_insert(nNewLocationSetID, &pt, &nNewLocationID);
+	location_insert_attribute(nNewLocationID, LOCATION_ATTRIBUTE_ID_NAME, "One Cup of Coffee", NULL);
+	location_insert_attribute(nNewLocationID, LOCATION_ATTRIBUTE_ID_ADDRESS, "29 Shore Street\nCambridge, MA, 02141", NULL);
+*/
 
 	prefs_read();
 

Index: main.h
===================================================================
RCS file: /cvs/cairo/roadster/src/main.h,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -d -r1.1 -r1.2
--- main.h	28 Mar 2005 18:49:50 -0000	1.1
+++ main.h	31 Mar 2005 08:29:53 -0000	1.2
@@ -21,7 +21,7 @@
  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  */
 
-#define USE_GNOME_VFS
+#define USE_GNOME_VFS		// comment this out to get a faster single-threaded compile (can't import, though)
 //#define ENABLE_TIMING
 #define USE_GFREELIST
 

Index: mainwindow.c
===================================================================
RCS file: /cvs/cairo/roadster/src/mainwindow.c,v
retrieving revision 1.34
retrieving revision 1.35
diff -u -d -r1.34 -r1.35
--- mainwindow.c	29 Mar 2005 09:16:20 -0000	1.34
+++ mainwindow.c	31 Mar 2005 08:29:53 -0000	1.35
@@ -81,6 +81,11 @@
 // Locationset columns
 #define	LOCATIONSETLIST_COLUMN_ENABLED  (0)
 #define LOCATIONSETLIST_COLUMN_NAME	(1)
+#define LOCATIONSETLIST_COLUMN_ID	(2)
+
+//
+#define MOUSE_BUTTON_LEFT		(1)
+#define MOUSE_BUTTON_RIGHT		(3)
 
 // Limits
 #define MAX_SEARCH_TEXT_LENGTH		(100)
@@ -126,6 +131,7 @@
 static void mainwindow_setup_selected_tool(void);
 static gboolean mainwindow_on_enter_notify(GtkWidget* w, GdkEventCrossing *event);
 static gboolean mainwindow_on_leave_notify(GtkWidget* w, GdkEventCrossing *event);
+static void mainwindow_on_locationset_visible_checkbox_clicked(GtkCellRendererToggle *cell, gchar *path_str, gpointer data);
 
 void mainwindow_add_history();
 
@@ -164,9 +170,10 @@
 
 	// Sidebar
 
-	// "Draw" Sidebar
+	// "Draw" Sidebar (currently POI)
 	GtkTreeView* m_pLayersListTreeView;
 	GtkTreeView* m_pLocationSetsTreeView;
+	GtkListStore* m_pLocationSetsListStore;
 	GtkNotebook* m_pSidebarNotebook;
 
 	// "GPS" sidebar
@@ -359,13 +366,13 @@
         g_MainWindow.m_nGPSLocationGlyph = glyph_load(PACKAGE_DATA_DIR"/car.svg");
 
 	// create location sets tree view
-	GtkListStore* pLocationSetsListStore = gtk_list_store_new(2, G_TYPE_BOOLEAN, G_TYPE_STRING);
-	gtk_tree_view_set_model(g_MainWindow.m_pLocationSetsTreeView, GTK_TREE_MODEL(pLocationSetsListStore));
+	g_MainWindow.m_pLocationSetsListStore = gtk_list_store_new(3, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_INT);
+	gtk_tree_view_set_model(g_MainWindow.m_pLocationSetsTreeView, GTK_TREE_MODEL(g_MainWindow.m_pLocationSetsListStore));
 
 	// NEW COLUMN: Visible checkbox
 	pCellRenderer = gtk_cell_renderer_toggle_new();
   	g_object_set_data(G_OBJECT(pCellRenderer), "column", (gint *)LAYERLIST_COLUMN_ENABLED);
-//	g_signal_connect(pCellRenderer, "toggled", G_CALLBACK(on_layervisible_checkbox_clicked), pLocationSetsListStore);
+	g_signal_connect(pCellRenderer, "toggled", G_CALLBACK(mainwindow_on_locationset_visible_checkbox_clicked), NULL);
 	pColumn = gtk_tree_view_column_new_with_attributes("Visible", pCellRenderer, "active", LOCATIONSETLIST_COLUMN_ENABLED, NULL);
 	gtk_tree_view_append_column(g_MainWindow.m_pLocationSetsTreeView, pColumn);
 
@@ -382,11 +389,15 @@
 	for(i=0 ; i<pLocationSetArray->len ; i++) {
 		locationset_t* pLocationSet = g_ptr_array_index(pLocationSetArray, i);
 
-		gtk_list_store_append(pLocationSetsListStore, &iter);
-		gtk_list_store_set(pLocationSetsListStore, &iter, 
-				   LOCATIONSETLIST_COLUMN_NAME, pLocationSet->m_pszName, 
+		gchar* pszName = g_strdup_printf("%s (%d)", pLocationSet->m_pszName, pLocationSet->m_nLocationCount);
+
+		gtk_list_store_append(g_MainWindow.m_pLocationSetsListStore, &iter);
+		gtk_list_store_set(g_MainWindow.m_pLocationSetsListStore, &iter, 
+				   LOCATIONSETLIST_COLUMN_NAME, pszName, 
 				   LOCATIONSETLIST_COLUMN_ENABLED, TRUE,
+				   LOCATIONSETLIST_COLUMN_ID, pLocationSet->m_nID, 
 				   -1);
+		g_free(pszName);
 	}
 
 #ifdef ROADSTER_DEAD_CODE
@@ -829,132 +840,123 @@
 	map_windowpoint_to_mappoint(g_MainWindow.m_pMap, &screenpoint, &mappoint);
 	
 	maphit_t* pHitStruct = NULL;
-	if(map_hit_test(g_MainWindow.m_pMap, &mappoint, &pHitStruct) && pHitStruct->m_eHitType == MAP_HITTYPE_LOCATION) {
-		if(event->button == 1) {
-			if(event->type == GDK_BUTTON_PRESS) {
-				g_print("click on location ID #%d\n", pHitStruct->m_LocationHit.m_nLocationID);
+	gboolean bLocationHit = (map_hit_test(g_MainWindow.m_pMap, &mappoint, &pHitStruct) && pHitStruct->m_eHitType == MAP_HITTYPE_LOCATION);
+	// hitstruct free'd far below
+
+	if(event->button == MOUSE_BUTTON_LEFT) {
+		// Left mouse button down?
+		if(event->type == GDK_BUTTON_PRESS) {
+			tooltip_hide(g_MainWindow.m_pTooltip);
+
+			// Is it at a border?
+			eScrollDirection = match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
+			if(eScrollDirection != DIRECTION_NONE) {
+				// begin a scroll
+				GdkCursor* pCursor = gdk_cursor_new(g_aDirectionCursors[eScrollDirection].m_nCursor);
+				gdk_window_set_cursor(GTK_WIDGET(g_MainWindow.m_pDrawingArea)->window, pCursor);
+				gdk_cursor_unref(pCursor);
+
+				g_MainWindow.m_bScrolling = TRUE;
+				g_MainWindow.m_eScrollDirection = eScrollDirection;
+				g_MainWindow.m_bScrollMovement = FALSE;	// no movement yet
+
+				mainwindow_set_scroll_timeout();
 			}
-			else if(event->type == GDK_2BUTTON_PRESS) {
-				g_print("double-click on location ID #%d\n", pHitStruct->m_LocationHit.m_nLocationID);
+			else {
+				g_MainWindow.m_bMouseDragging = TRUE;
+				g_MainWindow.m_bMouseDragMovement = FALSE;
+				g_MainWindow.m_ptClickLocation.m_nX = nX;
+				g_MainWindow.m_ptClickLocation.m_nY = nY;
 			}
 		}
-	}
-	else {
-		if(event->button == 1) {
-			// Left mouse button down?
-			if(event->type == GDK_BUTTON_PRESS) {
-				tooltip_hide(g_MainWindow.m_pTooltip);
-
-				// Is it at a border?
-				eScrollDirection = match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
-				if(eScrollDirection != DIRECTION_NONE) {
-					// begin a scroll
-					GdkCursor* pCursor = gdk_cursor_new(g_aDirectionCursors[eScrollDirection].m_nCursor);
-					gdk_window_set_cursor(GTK_WIDGET(g_MainWindow.m_pDrawingArea)->window, pCursor);
-					gdk_cursor_unref(pCursor);
+		// Left mouse button up?
+		else if(event->type == GDK_BUTTON_RELEASE) {
+			// end mouse dragging, if active
+			if(g_MainWindow.m_bMouseDragging == TRUE) {
+				// restore cursor
+				GdkCursor* pCursor = gdk_cursor_new(GDK_LEFT_PTR);
+				gdk_window_set_cursor(GTK_WIDGET(g_MainWindow.m_pDrawingArea)->window, pCursor);
+				gdk_cursor_unref(pCursor);
 
-					g_MainWindow.m_bScrolling = TRUE;
-					g_MainWindow.m_eScrollDirection = eScrollDirection;
-					g_MainWindow.m_bScrollMovement = FALSE;	// no movement yet
+				g_MainWindow.m_bMouseDragging = FALSE;
+				if(g_MainWindow.m_bMouseDragMovement) {
+					mainwindow_cancel_draw_pretty_timeout();
+					mainwindow_draw_map(DRAWFLAG_ALL);
 
-					mainwindow_set_scroll_timeout();
+					mainwindow_add_history();
 				}
-				else {
-					g_MainWindow.m_bMouseDragging = TRUE;
-					g_MainWindow.m_bMouseDragMovement = FALSE;
-					g_MainWindow.m_ptClickLocation.m_nX = nX;
-					g_MainWindow.m_ptClickLocation.m_nY = nY;
+				else if(bLocationHit) {
+					g_print("click on location ID #%d\n", pHitStruct->m_LocationHit.m_nLocationID);
 				}
 			}
-			// Left mouse button up?
-			else if(event->type == GDK_BUTTON_RELEASE) {
-				// end mouse dragging, if active
-				if(g_MainWindow.m_bMouseDragging == TRUE) {
-					// restore cursor
-					GdkCursor* pCursor = gdk_cursor_new(GDK_LEFT_PTR);
-					gdk_window_set_cursor(GTK_WIDGET(g_MainWindow.m_pDrawingArea)->window, pCursor);
-					gdk_cursor_unref(pCursor);
-
-					g_MainWindow.m_bMouseDragging = FALSE;
-					if(g_MainWindow.m_bMouseDragMovement) {
-						mainwindow_cancel_draw_pretty_timeout();
-						mainwindow_draw_map(DRAWFLAG_ALL);
 
-						mainwindow_add_history();
-					}
-				}
+			// end scrolling, if active
+			if(g_MainWindow.m_bScrolling == TRUE) {
+				// NOTE: don't restore cursor (mouse could *still* be over screen edge)
 
-				// end scrolling, if active
-				if(g_MainWindow.m_bScrolling == TRUE) {
-					// NOTE: don't restore cursor (mouse could *still* be over screen edge)
+				g_MainWindow.m_bScrolling = FALSE;
+				mainwindow_cancel_draw_pretty_timeout();
 
-					g_MainWindow.m_bScrolling = FALSE;
-					mainwindow_cancel_draw_pretty_timeout();
+				// has there been any movement?
+				if(g_MainWindow.m_bScrollMovement) {
+					g_MainWindow.m_bScrollMovement = FALSE;
+					mainwindow_draw_map(DRAWFLAG_ALL);
+				}
+				else {
+					// user clicked the edge of the screen, but so far we haven't moved at all (they released the button too fast)
+					// so consider this a 'click' and just jump a bit in that direction
+					gint nHeight = GTK_WIDGET(g_MainWindow.m_pDrawingArea)->allocation.height;
+					gint nWidth = GTK_WIDGET(g_MainWindow.m_pDrawingArea)->allocation.width;
 
-					// has there been any movement?
-					if(g_MainWindow.m_bScrollMovement) {
-						g_MainWindow.m_bScrollMovement = FALSE;
-						mainwindow_draw_map(DRAWFLAG_ALL);
+					gint nDistanceInPixels;
+					if(g_MainWindow.m_eScrollDirection == DIRECTION_N || g_MainWindow.m_eScrollDirection == DIRECTION_S) {
+						// scroll half the height of the screen
+						nDistanceInPixels = nHeight/2;
+					}
+					else if(g_MainWindow.m_eScrollDirection == DIRECTION_E || g_MainWindow.m_eScrollDirection == DIRECTION_W) {
+						nDistanceInPixels = nWidth/2;
 					}
 					else {
-						// user clicked the edge of the screen, but so far we haven't moved at all (they released the button too fast)
-						// so consider this a 'click' and just jump a bit in that direction
-						gint nHeight = GTK_WIDGET(g_MainWindow.m_pDrawingArea)->allocation.height;
-						gint nWidth = GTK_WIDGET(g_MainWindow.m_pDrawingArea)->allocation.width;
-
-						gint nDistanceInPixels;
-						if(g_MainWindow.m_eScrollDirection == DIRECTION_N || g_MainWindow.m_eScrollDirection == DIRECTION_S) {
-							// scroll half the height of the screen
-							nDistanceInPixels = nHeight/2;
-						}
-						else if(g_MainWindow.m_eScrollDirection == DIRECTION_E || g_MainWindow.m_eScrollDirection == DIRECTION_W) {
-							nDistanceInPixels = nWidth/2;
-						}
-						else {
-							// half the distance from corner to opposite corner
-							nDistanceInPixels = sqrt(nHeight*nHeight + nWidth*nWidth)/2;
-						}
-
-						mainwindow_scroll_direction(g_MainWindow.m_eScrollDirection, nDistanceInPixels);
+						// half the distance from corner to opposite corner
+						nDistanceInPixels = sqrt(nHeight*nHeight + nWidth*nWidth)/2;
 					}
-					g_MainWindow.m_eScrollDirection = DIRECTION_NONE;
-					mainwindow_add_history();
+
+					mainwindow_scroll_direction(g_MainWindow.m_eScrollDirection, nDistanceInPixels);
 				}
+				g_MainWindow.m_eScrollDirection = DIRECTION_NONE;
+				mainwindow_add_history();
 			}
-			else if(event->type == GDK_2BUTTON_PRESS) {
-				// can only double click in the middle (not on a scroll border)
-				eScrollDirection = match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
-				if(eScrollDirection == DIRECTION_NONE) {
-					animator_destroy(g_MainWindow.m_pAnimator);
+		}
+		else if(event->type == GDK_2BUTTON_PRESS) {
+			// can only double click in the middle (not on a scroll border)
+			eScrollDirection = match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
+			if(eScrollDirection == DIRECTION_NONE) {
+				animator_destroy(g_MainWindow.m_pAnimator);
 
-					g_MainWindow.m_bSliding = TRUE;
-					g_MainWindow.m_pAnimator = animator_new(ANIMATIONTYPE_FAST_THEN_SLIDE, SLIDE_TIME_IN_SECONDS);
+				g_MainWindow.m_bSliding = TRUE;
+				g_MainWindow.m_pAnimator = animator_new(ANIMATIONTYPE_FAST_THEN_SLIDE, SLIDE_TIME_IN_SECONDS);
 
-					// set startpoint
-					map_get_centerpoint(g_MainWindow.m_pMap, &g_MainWindow.m_ptSlideStartLocation);
+				// set startpoint
+				map_get_centerpoint(g_MainWindow.m_pMap, &g_MainWindow.m_ptSlideStartLocation);
 
-					// set endpoint
-					screenpoint_t ptScreenPoint = {nX, nY};
-					map_windowpoint_to_mappoint(g_MainWindow.m_pMap, &ptScreenPoint, &(g_MainWindow.m_ptSlideEndLocation));
-				}
+				// set endpoint
+				screenpoint_t ptScreenPoint = {nX, nY};
+				map_windowpoint_to_mappoint(g_MainWindow.m_pMap, &ptScreenPoint, &(g_MainWindow.m_ptSlideEndLocation));
 			}
 		}
-		/*
-		// Right-click?
-	//         else if (event->button == 3 && event->type == GDK_BUTTON_PRESS)
-	//         {
-	//                 // Save click location for use by callback
-	//                 g_MainWindow.m_ptClickLocation.m_nX = nX;
-	//                 g_MainWindow.m_ptClickLocation.m_nY = nY;
-	//
-	//                 // Show popup!
-	//                 gtk_menu_popup(g_MainWindow.m_pMapPopupMenu, NULL, NULL, NULL, NULL, event->button, event->time);
-	//                 return TRUE;
-	//         }
-		//	map_redraw_if_needed();
-		*/
 	}
-	map_free_hitstruct(g_MainWindow.m_pMap, pHitStruct);
+	else if (event->button == MOUSE_BUTTON_RIGHT) {
+		// single right-click?
+		if(event->type == GDK_BUTTON_PRESS) {
+			// Save click location for use by callback
+	//		g_MainWindow.m_ptClickLocation.m_nX = nX;
+	//		g_MainWindow.m_ptClickLocation.m_nY = nY;
+			// Show popup!
+	//		gtk_menu_popup(g_MainWindow.m_pMapPopupMenu, NULL, NULL, NULL, NULL, event->button, event->time);
+	//		return TRUE;
+		}
+	}
+	map_hitstruct_free(g_MainWindow.m_pMap, pHitStruct);
 	return TRUE;
 }
 
@@ -1015,7 +1017,6 @@
 		}
 	}
 	else {
-
 		EDirection eScrollDirection = match_border(nX, nY, nWidth, nHeight, BORDER_SCROLL_CLICK_TARGET_SIZE);
   
 		if(eScrollDirection == DIRECTION_NONE) {
@@ -1051,7 +1052,7 @@
 
 				tooltip_show(g_MainWindow.m_pTooltip);	// ensure it's visible
 				
-				map_free_hitstruct(g_MainWindow.m_pMap, pHitStruct);
+				map_hitstruct_free(g_MainWindow.m_pMap, pHitStruct);
 			}
 			else {
 				// no hit. hide the tooltip
@@ -1497,6 +1498,37 @@
 	mainwindow_update_forward_back_buttons();
 }
 
+static void mainwindow_on_locationset_visible_checkbox_clicked(GtkCellRendererToggle *pCell, gchar *pszPath, gpointer pData)
+{
+	// get an iterator for this item
+	GtkTreePath *pPath = gtk_tree_path_new_from_string(pszPath);
+	GtkTreeIter iter;
+	gtk_tree_model_get_iter(g_MainWindow.m_pLocationSetsListStore, &iter, pPath);
+	gtk_tree_path_free (pPath);
+
+	// get locationset ID and whether it's set or not
+	gboolean bEnabled;
+	gint nLocationSetID;
+	gtk_tree_model_get(GTK_TREE_MODEL(g_MainWindow.m_pLocationSetsListStore), &iter, LOCATIONSETLIST_COLUMN_ENABLED, &bEnabled, -1);
+	gtk_tree_model_get(GTK_TREE_MODEL(g_MainWindow.m_pLocationSetsListStore), &iter, LOCATIONSETLIST_COLUMN_ID, &nLocationSetID, -1);
+
+	// toggle selection and set it
+	bEnabled = !bEnabled;
+	gtk_list_store_set(g_MainWindow.m_pLocationSetsListStore, &iter, LOCATIONSETLIST_COLUMN_ENABLED, bEnabled, -1);
+
+	locationset_t* pLocationSet = NULL;
+	if(locationset_find_by_id(nLocationSetID, &pLocationSet)) {
+		locationset_set_visible(pLocationSet, bEnabled);
+	}
+	else {
+		g_assert_not_reached();
+	}
+
+	GTK_PROCESS_MAINLOOP;
+
+	mainwindow_draw_map(DRAWFLAG_ALL);
+}
+
 #ifdef ROADSTER_DEAD_CODE
 /*
 
@@ -1506,30 +1538,6 @@
 	importwindow_show();
 }
 
-static void on_layervisible_checkbox_clicked(GtkCellRendererToggle *cell, gchar *path_str, gpointer data)
-{
-	GtkTreeModel *model = (GtkTreeModel *)data;
-	GtkTreePath *path = gtk_tree_path_new_from_string (path_str);
-	GtkTreeIter iter;
-	gboolean toggle_item;
-	gint *column;
-
-	column = g_object_get_data (G_OBJECT (cell), "column");
-
-	// get toggled iter
-	gtk_tree_model_get_iter (model, &iter, path);
-	gtk_tree_model_get (model, &iter, column, &toggle_item, -1);
-
-	// do something with the value
-	toggle_item ^= 1;
-
-	// set new value
-	gtk_tree_store_set (GTK_TREE_STORE (model), &iter, column,
-			  toggle_item, -1);
-
-	// clean up
-	gtk_tree_path_free (path);
-}
 
 void mainwindow_on_datasetmenuitem_activate(GtkWidget *pWidget, gpointer* p)
 {

Index: map.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map.c,v
retrieving revision 1.36
retrieving revision 1.37
diff -u -d -r1.36 -r1.37
--- map.c	29 Mar 2005 09:16:20 -0000	1.36
+++ map.c	31 Mar 2005 08:29:53 -0000	1.37
@@ -59,8 +59,9 @@
 #define TILE_MODULUS			(23)		// how many of the above units each tile is on a side
 #define MAP_TILE_WIDTH			(TILE_MODULUS / TILE_SHIFT)	// width and height of a tile, in degrees
 
-#define MIN_ROAD_HIT_TARGET_WIDTH	(4)	// make super thin roads a bit easier to hover over/click, in pixels
+#define MIN_ROAD_HIT_TARGET_WIDTH	(6)	// make super thin roads a bit easier to hover over/click, in pixels
 
+#define MIN_ZOOMLEVEL_FOR_LOCATIONS	(6)
 
 /* Prototypes */
 
@@ -71,7 +72,7 @@
 
 // hit testing
 static gboolean map_hit_test_layer_roads(GPtrArray* pPointStringsArray, gdouble fMaxDistance, mappoint_t* pHitPoint, maphit_t** ppReturnStruct);
-static gboolean map_hit_test_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pHitPoint, gdouble fDistance, mappoint_t* pReturnClosestPoint);
+static gboolean map_hit_test_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pHitPoint, gdouble fMaxDistance, mappoint_t* pReturnClosestPoint, gdouble* pfReturnPercentAlongLine);
 static ESide map_side_test_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pClosestPointOnLine, mappoint_t* pHitPoint);
 
 static gboolean map_hit_test_locationsets(map_t* pMap, rendermetrics_t* pRenderMetrics, mappoint_t* pHitPoint, maphit_t** ppReturnStruct);
@@ -101,13 +102,14 @@
 
 	{LAYER_MISC_AREA, 0, SUBLAYER_RENDERTYPE_POLYGONS}, //map_draw_layer_polygons},
 
-	{LAYER_PARK, 0, SUBLAYER_RENDERTYPE_POLYGONS}, //map_draw_layer_polygons},
-	{LAYER_PARK, 1, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
+	{LAYER_PARK, 0, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
+	{LAYER_PARK, 1, SUBLAYER_RENDERTYPE_POLYGONS}, //map_draw_layer_polygons},
 
+	{LAYER_LAKE, 0, SUBLAYER_RENDERTYPE_LINES},	// NOTE: drawing lines BELOW polygons (and ~double width) lets us avoid drawing seams on top of multi-polygon lakes
 	{LAYER_RIVER, 0, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},	// single-line rivers
-
-	{LAYER_LAKE, 0, SUBLAYER_RENDERTYPE_POLYGONS}, //map_draw_layer_polygons},	// lakes and fat rivers
-//	{LAYER_LAKE, 1, map_draw_layer_lines},
+	
+	{LAYER_LAKE, 1, SUBLAYER_RENDERTYPE_POLYGONS},
+	{LAYER_RIVER, 1, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},	// single-line rivers
 
 	{LAYER_MINORHIGHWAY_RAMP, 0, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
 	{LAYER_MINORSTREET, 0, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
@@ -125,10 +127,10 @@
 	{LAYER_MINORHIGHWAY, 1, SUBLAYER_RENDERTYPE_LINES}, //map_draw_layer_lines},
 
 	// LABELS
+	{LAYER_MINORHIGHWAY, 0, SUBLAYER_RENDERTYPE_LINE_LABELS},
+	{LAYER_MAJORSTREET, 0, SUBLAYER_RENDERTYPE_LINE_LABELS},	// important ones first
 	{LAYER_MINORSTREET, 0, SUBLAYER_RENDERTYPE_LINE_LABELS},
-	{LAYER_MAJORSTREET, 0, SUBLAYER_RENDERTYPE_LINE_LABELS},
 	{LAYER_RAILROAD, 0, SUBLAYER_RENDERTYPE_LINE_LABELS},
-	{LAYER_MINORHIGHWAY, 0, SUBLAYER_RENDERTYPE_LINE_LABELS},
 ///     {LAYER_MAJORHIGHWAY, 0, SUBLAYER_RENDERTYPE_LABELS},
 
 	{LAYER_MISC_AREA, 0, SUBLAYER_RENDERTYPE_POLYGON_LABELS},
@@ -207,8 +209,11 @@
 	pLocationsArray = g_hash_table_lookup(pMap->m_pLocationArrayHashTable, &nLocationSetID);
 	if(pLocationsArray != NULL) {
 		// found existing array
+		//g_print("existing for set %d\n", nLocationSetID);
 	}
 	else {
+		//g_print("new for set %d\n", nLocationSetID);
+
 		// need a new array
 		pLocationsArray = g_ptr_array_new();
 		g_assert(pLocationsArray != NULL);
@@ -220,6 +225,7 @@
 
 	// add location to the array of locations!
 	g_ptr_array_add(pLocationsArray, pLocation);
+	//g_print("pLocationsArray->len = %d\n", pLocationsArray->len);
 }
 
 void map_draw(map_t* pMap, gint nDrawFlags)
@@ -630,8 +636,6 @@
 	}	
 }
 
-#define MIN_ZOOMLEVEL_FOR_LOCATIONS	(6)
-
 static gboolean map_data_load_locations(map_t* pMap, maprect_t* pRect)
 {
 	g_return_val_if_fail(pMap != NULL, FALSE);
@@ -642,7 +646,7 @@
 
 	gint nZoomLevel = map_get_zoomlevel(pMap);
 
-	if(nZoomLevel <= MIN_ZOOMLEVEL_FOR_LOCATIONS) {
+	if(nZoomLevel < MIN_ZOOMLEVEL_FOR_LOCATIONS) {
 		return TRUE;
 	}
 
@@ -786,7 +790,7 @@
 //  Hit Testing
 // ========================================================
 
-void map_free_hitstruct(map_t* pMap, maphit_t* pHitStruct)
+void map_hitstruct_free(map_t* pMap, maphit_t* pHitStruct)
 {
 	if(pHitStruct == NULL) return;
 
@@ -807,6 +811,8 @@
 	// Test things in the REVERSE order they are drawn (otherwise we'll match things that have been painted-over)
 	gint i;
 	for(i=NUM_ELEMS(layerdraworder)-1 ; i>=0 ; i--) {
+		if(layerdraworder[i].eSubLayerRenderType != SUBLAYER_RENDERTYPE_LINES) continue;
+		
 		gint nLayer = layerdraworder[i].nLayer;
 
 		// use width from whichever layer it's wider in
@@ -853,9 +859,12 @@
 			mappoint_t* pPoint2 = g_ptr_array_index(pRoad->m_pPointsArray, iPoint);
 
 			mappoint_t pointClosest;
+			gdouble fPercentAlongLine;
 
 			// hit test this line
-			if(map_hit_test_line(pPoint1, pPoint2, pHitPoint, fMaxDistance, &pointClosest)) {
+			if(map_hit_test_line(pPoint1, pPoint2, pHitPoint, fMaxDistance, &pointClosest, &fPercentAlongLine)) {
+				//g_print("fPercentAlongLine = %f\n",fPercentAlongLine);
+
 				// fill out a new maphit_t struct with details
 				maphit_t* pHitStruct = g_new0(maphit_t, 1);
 				pHitStruct->m_eHitType = MAP_HITTYPE_ROAD;
@@ -896,8 +905,11 @@
 }
 
 // Does the given point come close enough to the line segment to be considered a hit?
-static gboolean map_hit_test_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pHitPoint, gdouble fMaxDistance, mappoint_t* pReturnClosestPoint)
+static gboolean map_hit_test_line(mappoint_t* pPoint1, mappoint_t* pPoint2, mappoint_t* pHitPoint, gdouble fMaxDistance, mappoint_t* pReturnClosestPoint, gdouble* pfReturnPercentAlongLine)
 {
+	if(pHitPoint->m_fLatitude < (pPoint1->m_fLatitude - fMaxDistance) && pHitPoint->m_fLatitude < (pPoint2->m_fLatitude - fMaxDistance)) return FALSE;
+	if(pHitPoint->m_fLongitude < (pPoint1->m_fLongitude - fMaxDistance) && pHitPoint->m_fLongitude < (pPoint2->m_fLongitude - fMaxDistance)) return FALSE;
+
 	// Some bad ASCII art demonstrating the situation:
 	//
 	//             / (u)
@@ -969,6 +981,9 @@
 				pReturnClosestPoint->m_fLongitude = a.m_fLongitude + pPoint1->m_fLongitude;
 			}
 
+			if(pfReturnPercentAlongLine) {
+				*pfReturnPercentAlongLine = (fLengthAlongV / fLengthV);
+			}
 			return TRUE;
 		}
 	}
@@ -1020,7 +1035,8 @@
 	for(i=0 ; i<pLocationSetsArray->len ; i++) {
 		locationset_t* pLocationSet = g_ptr_array_index(pLocationSetsArray, i);
 
-		// XXX: check that it's visible
+		// the user is NOT trying to click on invisible things :)
+		if(!locationset_is_visible(pLocationSet)) continue;
 
 		// 2. Get array of Locations from the hash table using LocationSetID
 		GPtrArray* pLocationsArray;
@@ -1041,7 +1057,7 @@
 static gboolean map_hit_test_locations(map_t* pMap, rendermetrics_t* pRenderMetrics, GPtrArray* pLocationsArray, mappoint_t* pHitPoint, maphit_t** ppReturnStruct)
 {
 	gint i;
-	for(i=0 ; i<pLocationsArray->len ; i++) {
+	for(i=(pLocationsArray->len-1) ; i>=0 ; i--) {	// NOTE: test in *reverse* order so we hit the ones drawn on top first
 		location_t* pLocation = g_ptr_array_index(pLocationsArray, i);
 
 		// bounding box test

Index: map.h
===================================================================
RCS file: /cvs/cairo/roadster/src/map.h,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- map.h	29 Mar 2005 09:16:20 -0000	1.15
+++ map.h	31 Mar 2005 08:29:53 -0000	1.16
@@ -257,7 +257,7 @@
 void map_add_track(map_t* pMap, gint hTrack);
 
 gboolean map_hit_test(map_t* pMap, mappoint_t* pMapPoint, maphit_t** ppReturnStruct);
-void map_free_hitstruct(map_t* pMap, maphit_t* pHitStruct);
+void map_hitstruct_free(map_t* pMap, maphit_t* pHitStruct);
 
 gboolean map_can_zoom_in(map_t* pMap);
 gboolean map_can_zoom_out(map_t* pMap);

Index: map_draw_cairo.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map_draw_cairo.c,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -d -r1.15 -r1.16
--- map_draw_cairo.c	28 Mar 2005 18:49:50 -0000	1.15
+++ map_draw_cairo.c	31 Mar 2005 08:29:53 -0000	1.16
@@ -215,7 +215,7 @@
 void map_draw_cairo_layer_roads(map_t* pMap, cairo_t* pCairo, rendermetrics_t* pRenderMetrics, GPtrArray* pRoadsArray, sublayerstyle_t* pSubLayerStyle, textlabelstyle_t* pLabelStyle)
 {
 	mappoint_t* pPoint;
-	pointstring_t* pPointString;
+	road_t* pRoad;
 	gint iString;
 	gint iPoint;
 
@@ -264,19 +264,17 @@
 	cairo_set_line_width(pCairo, fLineWidth);
 
 	for(iString=0 ; iString<pRoadsArray->len ; iString++) {
-		RENDERING_THREAD_YIELD;
-
-		pPointString = g_ptr_array_index(pRoadsArray, iString);
+		pRoad = g_ptr_array_index(pRoadsArray, iString);
 
-		if(pPointString->m_pPointsArray->len >= 2) {
-			pPoint = g_ptr_array_index(pPointString->m_pPointsArray, 0);
+		if(pRoad->m_pPointsArray->len >= 2) {
+			pPoint = g_ptr_array_index(pRoad->m_pPointsArray, 0);
 
 			// go to index 0
 			cairo_move_to(pCairo, SCALE_X(pRenderMetrics, pPoint->m_fLongitude), SCALE_Y(pRenderMetrics, pPoint->m_fLatitude));
 
 			// start at index 1 (0 was used above)
-			for(iPoint=1 ; iPoint<pPointString->m_pPointsArray->len ; iPoint++) {
-				pPoint = g_ptr_array_index(pPointString->m_pPointsArray, iPoint);//~ g_print("  point (%.05f,%.05f)\n", ScaleX(pPoint->m_fLongitude), ScaleY(pPoint->m_fLatitude));
+			for(iPoint=1 ; iPoint<pRoad->m_pPointsArray->len ; iPoint++) {
+				pPoint = g_ptr_array_index(pRoad->m_pPointsArray, iPoint);//~ g_print("  point (%.05f,%.05f)\n", ScaleX(pPoint->m_fLongitude), ScaleY(pPoint->m_fLatitude));
 				cairo_line_to(pCairo, SCALE_X(pRenderMetrics, pPoint->m_fLongitude), SCALE_Y(pRenderMetrics, pPoint->m_fLatitude));
 			}
 #ifdef HACK_AROUND_CAIRO_LINE_CAP_BUG
@@ -516,10 +514,12 @@
 //	gdouble fFontHeight = font_extents.ascent;
 
         // text too big for line?       XXX: This math is not right but good enough for now ;)
+#ifdef LABEL_LIMIT_TO_ROAD
         if((fLabelWidth * fLabelWidth) > (fLineLengthSquared + (ACCEPTABLE_LINE_LABEL_OVERDRAW_IN_PIXELS_SQUARED))) {
             cairo_restore(pCairo);
             return;
         }
+#endif
         gdouble fLineLength = sqrt(fLineLengthSquared);
 
         gdouble fTotalPadding = fLineLength - fLabelWidth;

Index: map_draw_gdk.c
===================================================================
RCS file: /cvs/cairo/roadster/src/map_draw_gdk.c,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -d -r1.12 -r1.13
--- map_draw_gdk.c	29 Mar 2005 09:16:20 -0000	1.12
+++ map_draw_gdk.c	31 Mar 2005 08:29:53 -0000	1.13
@@ -102,9 +102,9 @@
 static void map_draw_gdk_background(map_t* pMap, GdkPixmap* pPixmap)
 {
 	GdkColor clr;
-	clr.red = 240/255.0 * 65535;
-	clr.green = 235/255.0 * 65535;
-	clr.blue = 230/255.0 * 65535;
+	clr.red = 255/255.0 * 65535;
+	clr.green = 227/255.0 * 65535;
+	clr.blue = 181/255.0 * 65535;
 	gdk_gc_set_rgb_fg_color(pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)], &clr);
 	
 	gdk_draw_rectangle(pPixmap, pMap->m_pTargetWidget->style->fg_gc[GTK_WIDGET_STATE(pMap->m_pTargetWidget)],
@@ -328,6 +328,7 @@
 	for(i=0 ; i<pLocationSetsArray->len ; i++) {
 		locationset_t* pLocationSet = g_ptr_array_index(pLocationSetsArray, i);
 
+		if(!locationset_is_visible(pLocationSet)) continue;
 
 		// 2. Get array of Locations from the hash table using LocationSetID
 		GPtrArray* pLocationsArray;

Index: search_location.c
===================================================================
RCS file: /cvs/cairo/roadster/src/search_location.c,v
retrieving revision 1.8
retrieving revision 1.9
diff -u -d -r1.8 -r1.9
--- search_location.c	28 Mar 2005 18:49:50 -0000	1.8
+++ search_location.c	31 Mar 2005 08:29:53 -0000	1.9
@@ -27,6 +27,7 @@
 #include "main.h"
 #include "db.h"
 #include "util.h"
+#include "location.h"
 #include "search.h"
 #include "searchwindow.h"
 #include "search_location.h"
@@ -35,55 +36,112 @@
 #define SEARCH_RESULT_COUNT_LIMIT	(100)
 
 typedef struct {
-	mappoint_t m_ptCenter;
-	gdouble m_fRadiusInDegrees;
-	gint m_nLocationSetID;
+//	mappoint_t m_ptCenter;
+//	gdouble m_fRadiusInDegrees;
+//	gint m_nLocationSetID;
 	gchar* m_pszCleanedSentence;
 	gchar** m_aWords;
 	gint m_nWordCount;
 } locationsearch_t;
 
-void search_location_on_cleaned_sentence(locationsearch_t* pLocationSearch);
-void search_location_on_locationsearch_struct(locationsearch_t* pLocationSearch);
-void search_location_filter_result(gint nLocationID);
-
-// SELECT Location.ID, LocationAttributeValue_Name.Value AS Name, AsText(Location.Coordinates) FROM LocationAttributeValue LEFT JOIN LocationAttributeName ON (LocationAttributeValue.AttributeNameID=LocationAttributeName.ID) LEFT JOIN Location ON (LocationAttributeValue.LocationID=Location.ID) LEFT JOIN LocationAttributeValue AS LocationAttributeValue_Name ON (Location.ID=LocationAttributeValue_Name.LocationID AND LocationAttributeValue_Name.AttributeNameID=1) WHERE MATCH(LocationAttributeValue.Value) AGAINST ('Chang*' IN BOOLEAN MODE) GROUP BY Location.ID;
+void search_location_on_cleaned_sentence(const gchar* pszCleanedSentence);
+void search_location_on_words(gchar** aWords, gint nWordCount);
+void search_location_filter_result(gint nLocationID, const gchar* pszName, const gchar* pszAddress, const mappoint_t* pCoordinates);
 
-void search_location_execute(const gchar* pszSentence, gint nLocationSetID, gfloat fDistance, gint nDistanceUnit)
+void search_location_execute(const gchar* pszSentence)
 {
-	return;
-/*
-	g_print("pszSentence = %s, nLocationSetID = %d, fDistance = %f, nDistanceUnit=%d\n", pszSentence, nLocationSetID, fDistance, nDistanceUnit);
-
-	TIMER_BEGIN(search, "\n\n****************************\nSEARCH BEGIN");
+	g_print("search_location_execute\n");
 
-	locationsearch_t locationsearch = { {0}, 0};
-	locationsearch.m_nLocationSetID = nLocationSetID;
-	locationsearch.m_fRadiusInDegrees = map_distance_in_units_to_degrees(fDistance, nDistanceUnit);
+	TIMER_BEGIN(search, "BEGIN LocationSearch");
 
 	// copy sentence and clean it
-	locationsearch.m_pszCleanedSentence = g_strdup(pszSentence);
-	search_clean_string(locationsearch.m_pszCleanedSentence);
-	search_location_on_cleaned_sentence(&locationsearch);
-	g_free(locationsearch.m_pszCleanedSentence);
+	gchar* pszCleanedSentence = g_strdup(pszSentence);
+	search_clean_string(pszCleanedSentence);
+	search_location_on_cleaned_sentence(pszCleanedSentence);
+	g_free(pszCleanedSentence);
 
-	TIMER_END(search, "SEARCH END");
-*/
+	TIMER_END(search, "END LocationSearch");
 }
 
-/*
-void search_location_on_cleaned_sentence(locationsearch_t* pLocationSearch)
+void search_location_on_cleaned_sentence(const gchar* pszCleanedSentence)
 {
 	// Create an array of the words
-	pLocationSearch->m_aWords = g_strsplit(pLocationSearch->m_pszCleanedSentence," ", 0);	// " " = delimeters, 0 = no max #
-	pLocationSearch->m_nWordCount = g_strv_length(pLocationSearch->m_aWords);
+	gchar** aaWords = g_strsplit(pszCleanedSentence," ", 0);	// " " = delimeters, 0 = no max #
+	gint nWords = g_strv_length(aaWords);
 
-	search_location_on_locationsearch_struct(pLocationSearch);
+//	search_location_on_locationsearch_struct(pLocationSearch);
+	search_location_on_words(aaWords, nWords);
 
 	// cleanup
-	g_strfreev(pLocationSearch->m_aWords);	// free the array of strings		
+	g_strfreev(aaWords);	// free the array of strings		
+}
+
+void search_location_on_words(gchar** aWords, gint nWordCount)
+{
+	gchar* pszSQL = g_strdup_printf(
+		"SELECT Location.ID, LocationAttributeValue_Name.Value AS Name, LocationAttributeValue_Address.Value AS Address, AsBinary(Location.Coordinates)"
+		" FROM LocationAttributeValue"
+		" LEFT JOIN LocationAttributeName ON (LocationAttributeValue.AttributeNameID=LocationAttributeName.ID)"
+		" LEFT JOIN Location ON (LocationAttributeValue.LocationID=Location.ID)"
+		" LEFT JOIN LocationAttributeValue AS LocationAttributeValue_Name ON (Location.ID=LocationAttributeValue_Name.LocationID AND LocationAttributeValue_Name.AttributeNameID=%d)"
+		" LEFT JOIN LocationAttributeValue AS LocationAttributeValue_Address ON (Location.ID=LocationAttributeValue_Address.LocationID AND LocationAttributeValue_Address.AttributeNameID=%d)"
+		" WHERE"
+		" MATCH(LocationAttributeValue.Value) AGAINST ('%s' IN BOOLEAN MODE)"
+		" GROUP BY Location.ID;",
+			LOCATION_ATTRIBUTE_ID_NAME,
+			LOCATION_ATTRIBUTE_ID_ADDRESS,
+			aWords[0]
+		);
+
+	db_resultset_t* pResultSet;
+	if(db_query(pszSQL, &pResultSet)) {
+		db_row_t aRow;
+
+		// get result rows!
+		gint nCount = 0;		
+		while((aRow = mysql_fetch_row(pResultSet))) {
+			nCount++;
+			if(nCount <= SEARCH_RESULT_COUNT_LIMIT) {
+				gint nLocationID = atoi(aRow[0]);
+				gchar* pszLocationName = aRow[1];
+				gchar* pszLocationAddress = aRow[2];
+				// Parse coordinates
+				mappoint_t pt;
+				db_parse_wkb_point(aRow[3], &pt);
+
+				search_location_filter_result(nLocationID, pszLocationName, pszLocationAddress, &pt);
+			}
+		}
+		db_free_result(pResultSet);
+
+		if(nCount == 0) {
+			g_print("no location search results\n");
+		}
+		else {
+			g_print("%d location results\n", nCount);
+		}
+	}
+	else {
+		g_print("search failed\n");
+	}
 }
 
+#define LOCATION_RESULT_SUGGESTED_ZOOMLEVEL	(7)
+
+void search_location_filter_result(gint nLocationID, const gchar* pszName, const gchar* pszAddress, const mappoint_t* pCoordinates)
+{
+	gchar* pszResultText = g_strdup_printf("<b>%s</b>%s%s", pszName,
+					       (pszAddress == NULL || pszAddress[0] == '\0') ? "" : "\n",
+					       (pszAddress == NULL || pszAddress[0] == '\0') ? "" : pszAddress);
+
+	searchwindow_add_result(pszResultText, pCoordinates, LOCATION_RESULT_SUGGESTED_ZOOMLEVEL);
+
+	g_free(pszResultText);
+}
+
+// 
+
+/*
 void search_location_on_locationsearch_struct(locationsearch_t* pLocationSearch)
 {
 	// location matching

Index: search_location.h
===================================================================
RCS file: /cvs/cairo/roadster/src/search_location.h,v
retrieving revision 1.2
retrieving revision 1.3
diff -u -d -r1.2 -r1.3
--- search_location.h	3 Mar 2005 07:32:46 -0000	1.2
+++ search_location.h	31 Mar 2005 08:29:53 -0000	1.3
@@ -26,7 +26,7 @@
 
 G_BEGIN_DECLS
 
-void search_location_execute(const gchar* pszSearch, gint nLocationSetID, gfloat fDistance, gint nDistanceUnit);
+void search_location_execute(const gchar* pszSentence);
 
 G_END_DECLS
 

Index: search_road.c
===================================================================
RCS file: /cvs/cairo/roadster/src/search_road.c,v
retrieving revision 1.17
retrieving revision 1.18
diff -u -d -r1.17 -r1.18
--- search_road.c	29 Mar 2005 09:16:20 -0000	1.17
+++ search_road.c	31 Mar 2005 08:29:53 -0000	1.18
@@ -163,7 +163,7 @@
 
 	// Claim zip code, if present
 	if(search_address_match_zipcode(aWords[iLast])) {
-		g_print("matched ZIP %s\n", aWords[iLast]);
+		//g_print("matched ZIP %s\n", aWords[iLast]);
 		roadsearch.m_pszZIPCode = aWords[iLast];
 
 		iLast--;	// last word taken
@@ -181,10 +181,10 @@
 	if(nRemainingWordCount >= 3) {
 		// try two-word state name
 		gchar* pszStateName = g_strjoinv_limit(" ", aWords, iLast-1, iLast);
-		g_print("trying two-word state name '%s'\n", pszStateName);
+		//g_print("trying two-word state name '%s'\n", pszStateName);
 
 		if(db_state_get_id(pszStateName, &roadsearch.m_nStateID)) {
-			g_print("matched state name!\n");
+			//g_print("matched state name!\n");
 			iLast -= 2;	// last TWO words taken
 			nRemainingWordCount -= 2;
 		}
@@ -192,9 +192,9 @@
 	}
 	// try a one-word state name
 	if(bGotStateName == FALSE && nRemainingWordCount >= 2) {
-		g_print("trying one-word state name '%s'\n", aWords[iLast]);
+		//g_print("trying one-word state name '%s'\n", aWords[iLast]);
 		if(db_state_get_id(aWords[iLast], &roadsearch.m_nStateID)) {
-			g_print("matched state name!\n");
+			//g_print("matched state name!\n");
 			iLast--;	// last word taken
 			nRemainingWordCount--;
 		}
@@ -240,7 +240,7 @@
 	}
 	else {
 		// oops, no street name
-		g_print("no street name found in search\n");
+		//g_print("no street name found in search\n");
 	}
 	g_free(roadsearch.m_pszRoadName);
 }
@@ -312,7 +312,7 @@
 
 	gchar azQuery[MAX_QUERY];
 	gchar* pszSafeRoadName = db_make_escaped_string(pRoadSearch->m_pszRoadName);
-	g_print("pRoadSearch->m_pszRoadName = %s, pszSafeRoadName = %s\n", pRoadSearch->m_pszRoadName, pszSafeRoadName);
+	//g_print("pRoadSearch->m_pszRoadName = %s, pszSafeRoadName = %s\n", pRoadSearch->m_pszRoadName, pszSafeRoadName);
 
 	gchar* pszRoadNameCondition;
 	if(strlen(pRoadSearch->m_pszRoadName) < ROAD_MIN_LENGTH_FOR_WILDCARD_SEARCH) {

Index: searchwindow.c
===================================================================
RCS file: /cvs/cairo/roadster/src/searchwindow.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- searchwindow.c	28 Mar 2005 18:49:50 -0000	1.16
+++ searchwindow.c	31 Mar 2005 08:29:53 -0000	1.17
@@ -100,13 +100,14 @@
 void searchwindow_on_findbutton_clicked(GtkWidget *pWidget, gpointer* p)
 {
 	// make list unsorted (sorting once at the end is much faster than for each insert)
-	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(g_SearchWindow.m_pResultsListStore), MAGIC_GTK_NO_SORT_COLUMN, GTK_SORT_ASCENDING);
+//	gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(g_SearchWindow.m_pResultsListStore), MAGIC_GTK_NO_SORT_COLUMN, GTK_SORT_ASCENDING);
 
 	const gchar* pszSearch = gtk_entry_get_text(g_SearchWindow.m_pSearchEntry);
 
 	void* pBusy = mainwindow_set_busy();
 	searchwindow_clear_results();
 	search_road_execute(pszSearch);
+	search_location_execute(pszSearch);
 	mainwindow_set_not_busy(&pBusy);
 
 	if(g_SearchWindow.m_nNumResults == 0) {




More information about the cairo-commit mailing list