Label edit
LabelEdit.cpp
// Copyright 2011 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.
// 

  
#include "LabelEdit.h"

// Motif Widgets
Widget g_topLevel;                          // application
Widget g_mainWindow;                        
Widget g_mainForm;   
Widget g_leftPanel;                       
Widget g_midPanel;
Widget g_rightPanel;
Widget g_notebook;
Widget g_layoutPage;
Widget g_mapPage;
Widget g_mapTab;
Widget g_layoutTab;
Widget g_mapWidget;                
Widget g_tocWidget;                         
Widget g_pageLayoutWidget;
Widget g_loadButton;
Widget g_selectFile;
Widget g_radioLabel;
Widget g_howToLabel;
Widget g_radioToggle;

// Control Interfaces
IMapControl3Ptr g_ipMapControl;             
ITOCControlPtr g_ipTOCControl;             
IPageLayoutControlPtr g_ipPageLayoutControl;

TOCControlEvents* g_tocEvents;
IEventListenerHelperPtr g_ipTOCControlEventHelper;

#define LABEL_EDITING_AUTO 1
#define LABEL_EDITING_MANUAL 2
int main (int argc, char* argv[])
{
  // Initialize the Engine
  ::AoInitialize(NULL);
  {
    IAoInitializePtr ipInit(CLSID_AoInitialize);
    esriLicenseStatus status;
    ipInit->Initialize(esriLicenseProductCodeEngine, &status);
    if (status != esriLicenseCheckedOut)
    {
      std::cerr << "Invalid Licensing." << std::endl;
      AoExit(0);  
    }
  }

  XtSetLanguageProc(NULL,NULL,NULL);
  XtAppContext app_context;

  // Initialize the Motif toolkit and create the parent widget
  g_topLevel = XtVaAppInitialize(&app_context, "XApplication", NULL, 
                                 0, &argc, argv, NULL, NULL);
  XtVaSetValues(g_topLevel, 
                XmNtitle, "Label Editing",
                NULL);
  
  // Set the application size by resizing the created widget
  XtResizeWidget(g_topLevel, 800, 640, 1);

  g_mainWindow = XtVaCreateWidget("g_mainWindow",
                                  xmMainWindowWidgetClass, g_topLevel,
                                  NULL);
  
  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 a sub-form to place TOCControl and Load button 
  g_leftPanel = XtVaCreateWidget("g_leftPanel",
                                 xmFormWidgetClass,   g_mainForm,
                                 XmNtopAttachment,    XmATTACH_FORM,
                                 XmNbottomAttachment, XmATTACH_FORM,
                                 XmNleftAttachment,   XmATTACH_FORM,
                                 XmNwidth,            200,
                                 NULL);
  
  // Create and place the load file button
  XmString label = XmStringCreateLocalized("Load Map Document");
  g_loadButton = XtVaCreateWidget("g_loadButton",
                                  xmPushButtonWidgetClass, g_leftPanel,
                                  XmNlabelString,          label,
                                  XmNrightAttachment,      XmATTACH_FORM,
                                  XmNtopAttachment,        XmATTACH_FORM,
                                  XmNleftAttachment,       XmATTACH_FORM,
                                  XmNheight,               35,
                                  XmNwidth,                100,
                                  NULL);
  XmStringFree(label);
  XtAddCallback(g_loadButton, XmNactivateCallback, LoadClick, NULL);
  
  // TOCControl setup
  g_tocWidget = XtVaCreateWidget("g_tocWidget",
                                 mwCtlWidgetClass,        g_leftPanel,
                                 XmNleftAttachment,       XmATTACH_FORM,
                                 XmNrightAttachment,      XmATTACH_FORM,
                                 XmNbottomAttachment,     XmATTACH_FORM,
                                 XmNtopAttachment,        XmATTACH_WIDGET,
                                 XmNtopWidget,            g_loadButton,
                                 MwNprogID,               AoPROGID_TOCControl,
                                 NULL);
  XtVaSetValues(g_tocWidget, XmNwidth, 200, NULL);
  MwCtlGetInterface(g_tocWidget, (IUnknown**)&g_ipTOCControl);
  
  // Create a sub-form to place MapControl and PageLayoutControl 
  g_rightPanel = XtVaCreateWidget("g_rightPanel",
                                  xmFormWidgetClass,   g_mainForm,
                                  XmNtopAttachment,    XmATTACH_FORM,
                                  XmNbottomAttachment, XmATTACH_FORM,
                                  XmNrightAttachment,  XmATTACH_FORM,
                                  XmNwidth,            200,
                                  NULL);
  
  // Create the radiobutton label
  label = XmStringCreateLocalized("\n \n \nLabel Editing");
  g_radioLabel = XtVaCreateWidget("g_radioLabel",
                                  xmLabelWidgetClass,  g_rightPanel,
                                  XmNlabelString,      label,
                                  XmNalignment,        XmALIGNMENT_BEGINNING,
                                  XmNleftAttachment,   XmATTACH_FORM,
                                  XmNtopAttachment,    XmATTACH_FORM,
                                  XmNrightAttachment,  XmATTACH_FORM,
                                  NULL);
  XmStringFree(label);

  // Create the radio buttons to set TOC's LabelEdit
  Arg placement[6];
  XtSetArg(placement[0], XmNleftAttachment, XmATTACH_FORM);
  XtSetArg(placement[1], XmNrightAttachment, XmATTACH_FORM);
  XtSetArg(placement[2], XmNtopAttachment, XmATTACH_WIDGET);
  XtSetArg(placement[3], XmNtopWidget, g_radioLabel);
  //  XtSetArg(placement[4], XmNbottomAttachment, XmATTACH_WIDGET);
  //XtSetArg(placement[5], XmNbottomWidget, g_howToLabel);
  g_radioToggle = XmCreateRadioBox(g_rightPanel, "g_radioToggle", 
                                   placement, 4);

  Widget autoEdit = XtVaCreateManagedWidget("Automatic", 
                                            xmToggleButtonGadgetClass, g_radioToggle,
                                            NULL);
  // Start on auto
  XmToggleButtonGadgetSetState(autoEdit, true, true);
  XtAddCallback(autoEdit, XmNvalueChangedCallback, ToggledEdit, (XtPointer*)LABEL_EDITING_AUTO);

  Widget manualEdit = XtVaCreateManagedWidget("Manual", 
                                              xmToggleButtonGadgetClass, g_radioToggle, 
                                              NULL);
  XtAddCallback(manualEdit, XmNvalueChangedCallback, ToggledEdit, (XtPointer*)LABEL_EDITING_MANUAL);
  
  // Create the how-to label
  label = XmStringCreateLocalized("Click on a label, then click on \nit a second time to invoke \nlabel editing. The ESC key on \nthe keyboard can be used \nduring the edit to cancel the \nlabel edit. \n \nIn this sample, only layer labels \ncan be edited and no empty \nlabels are permitted when label \nediting is set to manual.");
  g_howToLabel = XtVaCreateWidget("g_howToLabel",
                                  xmLabelWidgetClass,  g_rightPanel,
                                  XmNlabelString,      label,
                                  XmNalignment,        XmALIGNMENT_BEGINNING,
                                  XmNleftAttachment,   XmATTACH_FORM,
                                  XmNbottomAttachment, XmATTACH_FORM,
                                  XmNrightAttachment,  XmATTACH_FORM,
                                  XmNtopAttachment,    XmATTACH_WIDGET,
                                  XmNtopWidget,        g_radioToggle,
                                  NULL);
  
  XmStringFree(label);
  
  // Create a sub-form to place g_notebook
  g_midPanel = XtVaCreateWidget("g_midPanel",
                                xmFormWidgetClass,   g_mainForm,
                                XmNtopAttachment,    XmATTACH_FORM,
                                XmNbottomAttachment, XmATTACH_FORM,
                                XmNleftAttachment,   XmATTACH_WIDGET,
                                XmNleftWidget,       g_leftPanel,
                                XmNrightAttachment,  XmATTACH_WIDGET,
                                XmNrightWidget,      g_rightPanel,
                                NULL);
  
  // G_Notebook setup
  g_notebook = XtVaCreateWidget("g_notebook",
                                xmNotebookWidgetClass,    g_midPanel,
                                XmNtopAttachment,         XmATTACH_FORM,
                                XmNleftAttachment,        XmATTACH_FORM,
                                XmNbottomAttachment,      XmATTACH_FORM,
                                XmNrightAttachment,       XmATTACH_FORM,
                                XmNbindingType,           XmNONE,
                                XmNorientation,           XmVERTICAL,
                                XmNbackPagePlacement,     XmTOP_RIGHT,
                                XmNmajorTabSpacing,       0,
                                XmNminorTabSpacing,       0,
                                XmNbackPageNumber,        0,
                                NULL);
  
  // Create the (tabbed) pages of the notebook
  Arg tabs[1];
  XtSetArg(tabs[0], XmNnotebookChildType, XmMAJOR_TAB);
  char buffer[32];
  (void) sprintf(buffer, "%s", "MapControl");
  g_mapPage = XmCreateForm(g_notebook, "g_mapPage", NULL, 0);
  g_mapTab = XmCreatePushButton(g_notebook, buffer, tabs, 1);
  (void) sprintf(buffer, "%s", "PageLayoutControl");
  g_layoutPage = XmCreateForm(g_notebook, "g_mapPage", NULL, 0);
  g_layoutTab = XmCreatePushButton(g_notebook, buffer, tabs, 1);
  
  // Create a page scroller to disable it later
  Arg scroll[1];
  XtSetArg(scroll[0], XmNnotebookChildType, XmPAGE_SCROLLER);
  Widget scroller = XmCreateSpinBox(g_notebook, "scroller", scroll, 0);
  
  // PageLayoutControl setup
  g_pageLayoutWidget = XtVaCreateWidget("g_pageLayoutWidget",
                                        mwCtlWidgetClass,     g_layoutPage,
                                        XmNtopAttachment,     XmATTACH_FORM,
                                        XmNleftAttachment,    XmATTACH_FORM,
                                        XmNbottomAttachment,  XmATTACH_FORM,
                                        XmNrightAttachment,   XmATTACH_FORM,
                                        MwNprogID,            AoPROGID_PageLayoutControl,
                                        NULL);
  MwCtlGetInterface(g_pageLayoutWidget, (IUnknown**)&g_ipPageLayoutControl);
  
  // MapControl setup
  g_mapWidget = XtVaCreateWidget("g_mapWidget",
                                 mwCtlWidgetClass,        g_mapPage,
                                 XmNbottomAttachment,     XmATTACH_FORM,
                                 XmNleftAttachment,       XmATTACH_FORM,
                                 XmNrightAttachment,      XmATTACH_FORM,
                                 XmNtopAttachment,        XmATTACH_FORM,
                                 MwNprogID,               AoPROGID_MapControl,
                                 NULL);
  MwCtlGetInterface(g_mapWidget, (IUnknown**)&g_ipMapControl);
  
  // Buddy the toolbar and TOC with the PageLayoutControl
  //    Since map and page have same data, doesn't matter which one
  g_ipTOCControl->SetBuddyControl(g_ipPageLayoutControl);
  
  // Create a file selection dialog with a *.mxd mask
  XmString mask;
  Arg args[1];
  mask  = XmStringCreateLocalized("*.mxd");
  XtSetArg(args[0], XmNdirMask, mask);
  g_selectFile = XmCreateFileSelectionDialog(g_mainForm, "Select File", 
                                             args, 1);
  XtAddCallback(g_selectFile, XmNokCallback, FileSelected, NULL);
  XtAddCallback(g_selectFile, XmNnoMatchCallback, FileSelected, NULL);
  XtAddCallback(g_selectFile, XmNcancelCallback, FileSelected, NULL);
  
  // Disable the Help button
  XtSetSensitive(XmFileSelectionBoxGetChild(g_selectFile, 
                                            XmDIALOG_HELP_BUTTON), 
                 False);
  
  // Set the name of the FileSelectionDialog  
  XmString title;
  title = XmStringCreateLocalized("Browse to Map Document");
  XtVaSetValues(g_selectFile, XmNdialogTitle, title, NULL);
  XmStringFree(title);

  // Manage the non-parent widgets
  XtManageChild(g_mainWindow);
  XtManageChild(g_mainForm);
  XtManageChild(g_leftPanel);
  XtManageChild(g_rightPanel);
  XtManageChild(g_midPanel);
  XtManageChild(g_notebook);
  XtManageChild(g_mapTab);
  XtManageChild(g_layoutTab);
  XtManageChild(g_mapPage);
  XtManageChild(g_layoutPage);
  XtManageChild(g_mapWidget);
  XtManageChild(g_tocWidget);
  XtManageChild(g_pageLayoutWidget);
  XtManageChild(g_loadButton);
  XtManageChild(g_radioLabel);
  XtManageChild(g_howToLabel);
  XtManageChild(g_radioToggle);

  // Hide the notebook's page scroller
  XtUnmanageChild(scroller);

  // Listen for the TOC events
  g_tocEvents = new TOCControlEvents();
  g_ipTOCControlEventHelper.CreateInstance(CLSID_TOCControlEventsListener);
  g_ipTOCControlEventHelper->Startup(
    static_cast<ITOCControlEventsHelper*> (g_tocEvents));
  g_ipTOCControlEventHelper->AdviseEvents(g_ipTOCControl, 0);

  // Handle the window manager message that the window is about to be closed 
  Atom wm_delete_window = XmInternAtom(XtDisplay(g_topLevel), 
                                       "WM_DELETE_WINDOW", FALSE);
  XmAddWMProtocolCallback(g_topLevel, 
                          wm_delete_window, CloseAppCallback, 
                          NULL);

  // Start the application running
  XtRealizeWidget(g_topLevel);
  MwCtlAppMainLoop(app_context);
}

// Function called when WM_DELETE_WINDOW protocol is passed
void CloseAppCallback(Widget w, XtPointer client_data, XtPointer call_data)
{
  g_ipTOCControlEventHelper->UnadviseEvents();
  g_ipTOCControlEventHelper->Shutdown();
  g_ipTOCControlEventHelper = 0;
  delete g_tocEvents;

  g_ipMapControl = 0;             
  g_ipTOCControl = 0;             
  g_ipPageLayoutControl = 0;

  // Uninitialize the engine
  {
    IAoInitializePtr ipInit(CLSID_AoInitialize);
    ipInit->Shutdown();
  }
  ::AoUninitialize();
 
  AoExit(0);
}

void LoadClick(Widget w, XtPointer client_data, XtPointer call_data)
{
  XtManageChild(g_selectFile);
}

void ShowMessage(char *dialogtitle, char *text)
{
  // Create a MessageDialog
  Widget err;
  Arg args[1];
  XmString str;
  int n = 0;
  str = XmStringCreateLocalized(text);
  XtSetArg(args[n], XmNmessageString, str);
  n++;
  err = XmCreateMessageDialog(g_mainWindow, "error", args, n);
  
  // Remove the help and cancel buttons
  Widget remove1; 
  remove1 = XmMessageBoxGetChild(err, XmDIALOG_HELP_BUTTON);
  XtUnmanageChild(remove1);
  Widget remove2; 
  remove2 = XmMessageBoxGetChild(err, XmDIALOG_CANCEL_BUTTON);
  XtUnmanageChild(remove2);
  
  // Set the title of the MessageDialog
  XmString title;
  title = XmStringCreateLocalized(dialogtitle);
  XtVaSetValues(err, XmNdialogTitle, title, NULL);
  XmStringFree(title);
  
  XtManageChild(err);
  XmStringFree(str);
}

void FileSelected(Widget w, XtPointer client_data, XtPointer call_data)
{
  char* fileName;
  XmFileSelectionBoxCallbackStruct *cbs;
  cbs = (XmFileSelectionBoxCallbackStruct *)call_data;
  
  // Hide the dialog if they canceled
  if (cbs->reason == XmCR_CANCEL)
  {
    XtUnmanageChild(w);
    return;
  }

  // Get the file name and check for errors
  if (!XmStringGetLtoR(cbs->value, XmFONTLIST_DEFAULT_TAG, &fileName))
  {
    ShowMessage("File Open Error", "INTERNAL ERROR PROCESSING FILE");
    XtUnmanageChild(w);
    return;
  }
  if (!*fileName) 
  {
    ShowMessage("File Open Error", "NO FILE SELECTED");
    XtUnmanageChild(w);
    return;
  }

  // Try to add the layer to the PageLayoutControl and MapControl
  if (cbs->reason != XmCR_NO_MATCH)
  {
    VARIANT_BOOL varbool;
    g_ipPageLayoutControl->CheckMxFile(CComBSTR(fileName), &varbool);
    if (varbool)
    {
      // Set mouse pointers
      g_ipPageLayoutControl->put_MousePointer(esriPointerHourglass);
      g_ipMapControl->put_MousePointer(esriPointerHourglass);

      // Load the map document
      g_ipPageLayoutControl->LoadMxFile(CComBSTR(fileName));
      g_ipMapControl->LoadMxFile(CComBSTR(fileName));

      // Set mouse pointers
      g_ipPageLayoutControl->put_MousePointer(esriPointerDefault);
      g_ipMapControl->put_MousePointer(esriPointerDefault);
    }
    else
    {
      ShowMessage("Invalid MXD", "Not a valid ArcMap Document");
      XtUnmanageChild(w);
      return;
    }
      
    // Hide file selection dialog
    XtUnmanageChild(w);
  }
}

void ToggledEdit(Widget w, XtPointer client_data, XtPointer call_data)
{
  int button = (int) client_data;
  XmToggleButtonCallbackStruct *state = 
    (XmToggleButtonCallbackStruct *) call_data;

  if (state->set)
  {
    if (button == LABEL_EDITING_AUTO)   
      g_ipTOCControl->put_LabelEdit(esriTOCControlAutomatic);
    else if (button == LABEL_EDITING_MANUAL)
      g_ipTOCControl->put_LabelEdit(esriTOCControlManual);
  
  return;
  }
}