MapTip.cpp
// Copyright 2010 ESRI // // All rights reserved under the copyright laws of the United States // and applicable international laws, treaties, and conventions. // // You may freely redistribute and use this sample code, with or // without modification, provided you include the original copyright // notice and use restrictions. // // See the use restrictions. // //MapTips.cpp // //This sample illustrates how to display "maptips"- tooltips for map //elements- in Motif. It uses the mouseevents of a class that extends //CAoToolBase to accomplish this. #include "MapTip.h" // Global variables // // Motif Widget g_topLevel; // application Widget g_mainWindow; // main program window Widget g_mainForm; // main prog window's form Widget g_mapWidget; // map control Widget g_tocWidget; // TOC control Widget g_toolbarWidget; // toolbar control Widget g_addLayerWidget; Widget g_fileSelectionDialog; Widget g_layerComboWidget; Widget g_fieldComboWidget; Widget g_tooltipWidget; Widget g_layerLabel; Widget g_fieldLabel; XtAppContext g_appContext; Atom g_wmDeleteWindow; // Other long layerIndex = -1; // which layer is selected in layercombobox long numLayers = 0; // number of layers which have been added int main(int argc, char* argv[]) { // Interfaces for the Controls IMapControl3Ptr ipMapControl; IToolbarControlPtr ipToolbarControl; ITOCControlPtr ipTOCControl; // Structure used to pass data to most of the callback routines MapTipsClientDataStruct mtcds; // Initialize the engine ::AoInitialize(NULL); { IAoInitializePtr ipAOinit(CLSID_AoInitialize); esriLicenseStatus status; ipAOinit->Initialize(esriLicenseProductCodeEngine, &status); if (status != esriLicenseCheckedOut) { std::cerr << "License not available for Engine\n"; std::cerr << "status is " << status << std::endl; ipAOinit->Shutdown(); ipAOinit = 0; ::AoUninitialize(); AoExit(0); } } XtSetLanguageProc(NULL, NULL, NULL); // Initialize the Motif toolkit and create the parent widget g_topLevel = XtVaAppInitialize(&g_appContext, "XApplication", NULL, 0, &argc, argv, NULL, NULL); XtVaSetValues(g_topLevel, XmNtitle, "MapTips Motif Example", NULL); XtResizeWidget(g_topLevel, 999, 800, 1); // Create g_mainWindow g_mainWindow = XtVaCreateWidget("g_mainWindow", xmMainWindowWidgetClass, g_topLevel, NULL); // Create g_mainForm - it will fill the g_mainWindow g_mainForm = XtVaCreateWidget("g_mainForm", xmFormWidgetClass, g_mainWindow, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, g_mainWindow, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, g_mainWindow, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, g_mainWindow, XmNrightAttachment, XmATTACH_WIDGET, XmNrightWidget, g_mainWindow, XmNfractionBase, 100, NULL); //Create button to add a feature layer XmString label; label = XmStringCreateLocalized(const_cast<char*>("Add Feature Layer")); g_addLayerWidget = XtVaCreateWidget("g_addLayerWidget", xmPushButtonWidgetClass, g_mainForm, XmNlabelString, label, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_FORM, XmNheight, 40, XmNwidth, 200, NULL); XmStringFree(label); // NOTE: traversal is turned off for comboboxes and textwidgets // b/c this interferes w/ the MapTipTool's reception of mouse // events // Create the field combobox label g_layerLabel = XtVaCreateWidget("g_layerLabel", xmLabelWidgetClass, g_mainForm, XtVaTypedArg, XmNlabelString, XmRString, " Layer: ", 10, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, g_addLayerWidget, XmNheight, 35, XmNtraversalOn, False, NULL) ; // Create the combobox for selecting a layer g_layerComboWidget = XtVaCreateWidget("g_layerCombo", xmComboBoxWidgetClass, g_mainForm, XmNcomboBoxType, XmDROP_DOWN_LIST, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, g_layerLabel, XmNheight, 40, XmNwidth, 200, XmNtraversalOn, False, NULL) ; XtAddCallback(g_layerComboWidget, XmNselectionCallback, processLayerCombo, &mtcds); // Create the field combobox label g_fieldLabel = XtVaCreateWidget("g_fieldLabel", xmLabelWidgetClass, g_mainForm, XtVaTypedArg, XmNlabelString, XmRString, " Field: ", 10, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, g_layerComboWidget, XmNheight, 35, XmNtraversalOn, False, NULL) ; // Create the combobox for selecting a field g_fieldComboWidget = XtVaCreateWidget("g_fieldCombo", xmComboBoxWidgetClass, g_mainForm, XmNcomboBoxType, XmDROP_DOWN_LIST, XmNtopAttachment, XmATTACH_FORM, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, g_fieldLabel, XmNheight, 40, XmNwidth, 200, XmNtraversalOn, False, NULL) ; XtAddCallback(g_fieldComboWidget, XmNselectionCallback, processFieldCombo, &mtcds); // Create a FileSelectionDialog with a *.lyr mask XmString mask, title; Arg args[2]; mask = XmStringCreateLocalized(const_cast<char*>("*.lyr")); title = XmStringCreateLocalized(const_cast<char*>("Select Layer")); XtSetArg(args[0], XmNdirMask, mask); XtSetArg(args[1], XmNdialogTitle, title); g_fileSelectionDialog = XmCreateFileSelectionDialog(g_mainForm, const_cast<char*>("Select"), args, 2); XmStringFree(mask); XmStringFree(title); XtAddCallback(g_fileSelectionDialog, XmNokCallback, processFileSelect, &mtcds); XtAddCallback(g_fileSelectionDialog, XmNcancelCallback, processFileSelect, &mtcds); // Remove the Help button Widget remove1 = XmFileSelectionBoxGetChild(g_fileSelectionDialog, XmDIALOG_HELP_BUTTON); XtUnmanageChild(remove1); // Create the TextField for the tooltip g_tooltipWidget = XtVaCreateWidget("g_tooltipWidget", xmTextFieldWidgetClass, g_mainForm, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_FORM, XmNheight, 35, XmNeditable, False, XmNtraversalOn, False, NULL); // Toolbar Control setup g_toolbarWidget = XtVaCreateWidget("toolbarWidget", mwCtlWidgetClass, g_mainForm, XmNleftAttachment, XmATTACH_FORM, XmNrightAttachment, XmATTACH_FORM, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, g_addLayerWidget, MwNprogID, AoPROGID_ToolbarControl, NULL); XtVaSetValues(g_toolbarWidget, XmNheight, 25, NULL); MwCtlGetInterface(g_toolbarWidget, (IUnknown**)&ipToolbarControl); // TOC Control setup g_tocWidget = XtVaCreateWidget("tocWidget", mwCtlWidgetClass, g_mainForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, g_toolbarWidget, XmNleftAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, g_tooltipWidget, MwNprogID, AoPROGID_TOCControl, NULL); XtVaSetValues(g_tocWidget, XmNwidth, 200, NULL); MwCtlGetInterface(g_tocWidget, (IUnknown**)&ipTOCControl); // Map Control setup g_mapWidget = XtVaCreateWidget("mapWidget", mwCtlWidgetClass, g_mainForm, XmNtopAttachment, XmATTACH_WIDGET, XmNtopWidget, g_toolbarWidget, XmNleftAttachment, XmATTACH_WIDGET, XmNleftWidget, g_tocWidget, XmNrightAttachment, XmATTACH_FORM, XmNbottomAttachment, XmATTACH_WIDGET, XmNbottomWidget, g_tooltipWidget, MwNprogID, AoPROGID_MapControl, NULL); MwCtlGetInterface(g_mapWidget, (IUnknown**)&ipMapControl); // Manage the non-parent widgets XtManageChild(g_mainWindow); XtManageChild(g_mainForm); XtManageChild(g_addLayerWidget); XtManageChild(g_layerLabel); XtManageChild(g_layerComboWidget); XtManageChild(g_fieldLabel); XtManageChild(g_fieldComboWidget);; XtManageChild(g_toolbarWidget); XtManageChild(g_tocWidget); XtManageChild(g_mapWidget); XtManageChild(g_tooltipWidget); // Buddy the toolbar and TOC with the map ipToolbarControl->SetBuddyControl(ipMapControl); ipTOCControl->SetBuddyControl(ipMapControl); // Add tools to toolbar ::AddStandardToolbarItems(ipToolbarControl); // Add custom MapTip tool // Custom Tool MapTipTool* maptipAoTool = new MapTipTool(g_tooltipWidget); AoToolbarAddTool(ipToolbarControl, maptipAoTool, esriCommandStyleIconOnly); // Set up structures used to pass data to callback routines CloseFormClientDataStruct cfcds; cfcds.pMapControl = ipMapControl; cfcds.pToolbarControl = ipToolbarControl; cfcds.pTOCControl = ipTOCControl; mtcds.pMapControl = ipMapControl; mtcds.pMapTipTool = maptipAoTool; // Handle the window manager message that the window is about to be closed g_wmDeleteWindow = XmInternAtom(XtDisplay(g_topLevel), "WM_DELETE_WINDOW", FALSE); XmAddWMProtocolCallback(g_topLevel, g_wmDeleteWindow, processClickCloseForm, &cfcds); // Realize the container widget XtRealizeWidget(g_topLevel); XtResizeWidget(g_topLevel, 1000, 800, 1); XtAddCallback(g_addLayerWidget, XmNactivateCallback, processClick, NULL); // Turn application control over to the X Toolkit Intrinsics MwCtlAppMainLoop(g_appContext); } // Function called when WM_DELETE_WINDOW protocol is passed void processClickCloseForm(Widget w, XtPointer client_data, XtPointer call_data) { // To be on the safe side we will make sure the controls are // destroyed before uninitializing CloseFormClientDataStruct *cfcds = (CloseFormClientDataStruct *) client_data; IMapControl3Ptr ipMapControl = cfcds->pMapControl; ipMapControl = 0; IToolbarControlPtr ipToolbarControl = cfcds->pToolbarControl; ipToolbarControl = 0; ITOCControlPtr ipTOCControl = cfcds->pTOCControl; ipTOCControl = 0; // Uninitialize the engine { IAoInitializePtr ipAOinit(CLSID_AoInitialize); ipAOinit->Shutdown(); } ::AoUninitialize(); AoExit(0); } // Open a FileSelectionDialog window to allow the user to select a .lyr file // to add to the map control and TOC void processClick(Widget w, XtPointer client_data, XtPointer call_data) { XtManageChild(g_fileSelectionDialog); } // Add the .lyr file that the user selected to the map control and TOC void processFileSelect(Widget w, XtPointer client_data, XtPointer call_data) { USES_CONVERSION; MapTipsClientDataStruct *mtcds = (MapTipsClientDataStruct *) client_data; IMapControl3Ptr ipMapControl (mtcds->pMapControl); MapTipTool *maptipAoTool = mtcds->pMapTipTool; XmFileSelectionBoxCallbackStruct *cbs; cbs = (XmFileSelectionBoxCallbackStruct *)call_data; // Kill the dialog if they canceled if (cbs->reason == XmCR_CANCEL) { XtUnmanageChild(g_fileSelectionDialog); return; } // Get the file name and check for errors char *fileName = 0; if (!XmStringGetLtoR(cbs->value, XmFONTLIST_DEFAULT_TAG, &fileName)) { XtUnmanageChild(g_fileSelectionDialog); return; } if (!*fileName) { XtFree(fileName); return; } // Try to add the layer to the map ipMapControl->AddLayerFromFile(CComBSTR(fileName), numLayers); XtFree(fileName); // Add the layer's name to layercombo if it is a FeatureLayer ILayerPtr ipLayer; ipMapControl->get_Layer(numLayers++, &ipLayer); IFeatureLayerPtr ipFeatLayer (ipLayer); //QI if (ipFeatLayer == 0) { XtUnmanageChild(g_fileSelectionDialog); return; } // Clear the fields combobox ::ClearCombo(g_fieldComboWidget); // Get the layer name and add it to the combobox BSTR layerName; XmString cboName; ipFeatLayer->get_Name(&layerName); cboName = XmStringCreateLocalized(OLE2A(layerName)); ::AoFreeBSTR(layerName); // remember to free the BSTR that was returned XmComboBoxAddItem(g_layerComboWidget, cboName, 0, True); XmStringFree(cboName); // Hide file selection dialog XtUnmanageChild(g_fileSelectionDialog); // Set the textfield of the layercombobox and the fieldcombobox Widget txtwidget; XtVaGetValues(g_layerComboWidget, XmNtextField, &txtwidget, NULL); XmTextSetString(txtwidget, const_cast<char*>("Select Layer...")); XtVaGetValues(g_fieldComboWidget, XmNtextField, &txtwidget, NULL); XmTextSetString(txtwidget, NULL); // Reset MapTipsTool maptipAoTool->SetLayerIndex(-1); maptipAoTool->SetFieldIsSet(false); } // Callback for when layer combobox selection changes. Gets the // current text of the combobox (which is a layer name) and adds this // layer's fields to the field combobox. One thing to notice in this // function is the "cast" of ipLayer from ILayer to ILayerFields: // // ILayerPtr ipLayer; // ipMapControl->get_Layer(layerIndex, &ipLayer); // if (0 == ipLayer) return; // ((ILayerFieldsPtr)ipLayer)->get_FieldCount(&count); // // This is perfectly OK to do as it performs a QI behind the scense, // just be sure that you know that the QI will succeed. Here we know // that the layer is a FeatureLayer (b/c only FeatureLayers are added // to the combobox). void processLayerCombo(Widget menu_item, XtPointer client_data, XtPointer call_data) { USES_CONVERSION; MapTipsClientDataStruct *mtcds = (MapTipsClientDataStruct *) client_data; IMapControl3Ptr ipMapControl (mtcds->pMapControl); MapTipTool *maptipAoTool = mtcds->pMapTipTool; XmComboBoxCallbackStruct *cb = (XmComboBoxCallbackStruct *) call_data; // If nothing was selected then just return if (cb->event == NULL) return; layerIndex = cb->item_position; maptipAoTool->SetLayerIndex(layerIndex); // Add the fields of the feature class to the combobox ILayerPtr ipLayer; ipMapControl->get_Layer(layerIndex, &ipLayer); if (0 == ipLayer) return; long count; ((ILayerFieldsPtr)ipLayer)->get_FieldCount(&count); IFieldPtr ipField; esriFieldType fType; BSTR fieldName; XmString cboName; ::ClearCombo(g_fieldComboWidget); for (long i=0; i<count; i++) { ((ILayerFieldsPtr)ipLayer)->get_Field(i, &ipField); ipField->get_Type(&fType); if (fType != esriFieldTypeGeometry) { ipField->get_Name(&fieldName); cboName = XmStringCreateLocalized(OLE2A(fieldName)); ::AoFreeBSTR(fieldName); // remember to free the BSTR that was returned XmComboBoxAddItem(g_fieldComboWidget, cboName, 0, True); XmStringFree(cboName); } } // Set the textfield of the fieldcombobox Widget txtwidget; XtVaGetValues(g_fieldComboWidget, XmNtextField, &txtwidget, NULL); XmTextSetString(txtwidget, const_cast<char*>("Select Field...")); } // Callback for when field combobox selection changes. Gets the // current text of the combobox (which is a field name) and sets the // currently selected FeatureLayer's DisplayField to this field void processFieldCombo(Widget menu_item, XtPointer client_data, XtPointer call_data) { MapTipsClientDataStruct *mtcds = (MapTipsClientDataStruct *) client_data; IMapControl3Ptr ipMapControl (mtcds->pMapControl); MapTipTool *maptipAoTool = mtcds->pMapTipTool; XmComboBoxCallbackStruct *cb = (XmComboBoxCallbackStruct *) call_data; // If nothing was selected then just return if (cb->event == NULL) return; // Get the selected text (i.e. the bookmark name) char *value = (char *) XmStringUnparse(cb->item_or_text, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); // Set the FeatureLayer's DisplayField ILayerPtr ipLayer; ipMapControl->get_Layer(layerIndex, &ipLayer); ((IFeatureLayerPtr)ipLayer)->put_DisplayField(CComBSTR(value)); maptipAoTool->SetFieldIsSet(true); XtFree(value); }