/*----------------------------------------------------------------------------*/
/*                                                                            */
/* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved.             */
/* Copyright (c) 2005-2014 Rexx Language Association. All rights reserved.    */
/*                                                                            */
/* This program and the accompanying materials are made available under       */
/* the terms of the Common Public License v1.0 which accompanies this         */
/* distribution. A copy is also available at the following address:           */
/* https://www.oorexx.org/license.html                                        */
/*                                                                            */
/* Redistribution and use in source and binary forms, with or                 */
/* without modification, are permitted provided that the following            */
/* conditions are met:                                                        */
/*                                                                            */
/* Redistributions of source code must retain the above copyright             */
/* notice, this list of conditions and the following disclaimer.              */
/* Redistributions in binary form must reproduce the above copyright          */
/* notice, this list of conditions and the following disclaimer in            */
/* the documentation and/or other materials provided with the distribution.   */
/*                                                                            */
/* Neither the name of Rexx Language Association nor the names                */
/* of its contributors may be used to endorse or promote products             */
/* derived from this software without specific prior written permission.      */
/*                                                                            */
/* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS        */
/* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT          */
/* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS          */
/* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT   */
/* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,      */
/* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED   */
/* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,        */
/* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY     */
/* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING    */
/* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS         */
/* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.               */
/*                                                                            */
/*----------------------------------------------------------------------------*/

/**
 * Name: employee11tab.rex
 * Type: Open Object REXX Script
 *
 * Description:  Example to demonstrate the property sheet dialog class.
 */

  sd = locate()

  -- Note to self, we do not use data attributes in this app, need explanation.
  .application~setDefaults("O", sd"employee11tab.h", .false)

  -- Create the dialog pages.
  p1 = .EmployeeAdd~new(sd"employee11tab.rc", IDD_EMPLOYEES_ADD)
  p2 = .EmployeeEdit~new(sd"employee11tab.rc", IDD_EMPLOYEES_EDIT)
  p3 = .EmployeeBrowse~new(sd"employee11tab.rc", IDD_EMPLOYEES_BROWSE)
  p4 = .EmployeeList~new(sd"employee11tab.rc", IDD_EMPLOYEES_LIST)

  pages = .array~of(p1, p2, p3, p4)
  dlg = .AcmeEmployeesDlg~new(pages, "NOAPPLYNOW", "Acme Software - Employee Manager Version 10.00.0")

  dlg~execute

  return 0

::requires "ooDialog.cls"


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
  AcmeEmployeesDlg - The property sheet dialog for this application.
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
::class 'AcmeEmployeesDlg' subclass PropertySheetDialog

::constant  DATABASE    'employee11tab.db'

::attribute employees
::attribute empCount
::attribute empIndex

::method init
    expose dbChanged

    forward class (super) continue

    self~readDataBase

    dbChanged = .false

    if self~employees~items == 0 then self~startPage = 1
    else self~startPage = 4

    do page over self~pages
      page~configure(self~employees, self~empCount, self~empIndex)
    end


::method newEmployeeNotify
    expose dbChanged
    use strict arg emp

    dbChanged = .true

    self~empCount += 1
    self~employees[self~empCount] = emp
    self~empIndex = self~empCount

    self~notifyPages

    listPage = self~pages[4]

    -- If the user has not yet visited the List Employees page, then there is
    -- no list view to update.  Instead, when the user first visits that page,
    -- the list view will be filled with all existing employees.
    if listPage~wasActivated then listPage~newEmployeeNotify


::method editedEmployeeNotify
    expose dbChanged
    use strict arg emp

    dbChanged = .true
    self~employees[self~empIndex] = emp

    listPage = self~pages[4]
    if listPage~wasActivated then listPage~editedEmployeeNotify

    self~setCurSel( , 4)


::method selectedEmployeeNotify
    use strict arg index

    self~empIndex = index
    self~notifyPages


::method maybeDeleteEmployee
    expose dbChanged

    emp = self~employees[self~empIndex]

    pronoun = 'him'
    if \ emp~male then pronoun = 'her'

    title = "Acme Software - Deleting Employee:" emp~name
    msg   = "Deleting" emp~name "will permanently remove" pronoun "from"        || .endOfLine ||           -
            'the database.  No further pay checks can be issued to' emp~name'.' || .endOfLine~copies(2) || -
            "Are you sure you want to continue this action?"

    answer = MessageDialog(msg, self~hwnd, title, 'YESNO', 'QUESTION', 'DEFBUTTON2')
    if answer == self~IDYES then do
        oldIndex = self~empIndex

        self~employees~delete(self~empIndex)
        self~empCount -= 1
        self~empIndex = 1

        listPage = self~pages[4]
        if listPage~wasActivated then listPage~deleteEmployeeNotify(oldIndex)

        self~notifyPages
        dbChanged = .true
    end

::method leaving
    expose dbChanged

    if dbChanged & self~getResult == 'CLOSEDOK' then do
        self~writeDataBase
    end


::method notifyPages private

    do page over self~pages
      page~empCount = self~empCount
      page~empIndex = self~empIndex
    end


::method readDataBase private

    db = self~DATABASE

    fsObj = .stream~new(db)
    if fsObj~query('EXISTS') == '' then do
        self~employees = .array~new(10)
        self~empCount  = 0
        self~empIndex  = 0
    end
    else do
        lines = fsObj~makeArray
        fsObj~close

        emps = .array~new(lines~items)
        do l over lines
            l = l~strip
            if l~length == 0 | l~abbrev("#") | l~abbrev("/*") then iterate

            parse var l name', 'city', 'pos', 'male', 'married', 'fullTime .

            if male == 'M' then male = .true
            else male = .false

            if married == 'M' then married = .true
            else married = .false

            if fullTime == 'F' then fullTime = .true
            else fullTime = .false

            emp = .Employee~new(name, city, pos, male, married, fullTime)
            emps~append(emp)
        end

        self~employees = emps
        self~empCount  = emps~items
        self~empIndex  = 1
    end


::method writeDataBase private

    db = self~DATABASE

    fsObj = .stream~new(db)

    fsObj~open('WRITE REPLACE')

    if fsObj~state == 'READY' then do e over self~employees
        line = e~toCSV
        fsObj~lineout(line)
    end
    else do
      title = "Acme Software - Internal Error Detected"
      msg   = "The database could not be opened to record current changes."
      j = MessageDialog(msg, 0, title, 'OK', 'ERROR')
    end

    fsObj~close



/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
  EmployeeAdd - A dialog class for a page in the PropertySheetDialog.  This page
                allows the user to add employee records.
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
::class 'EmployeeAdd' subclass RcPSPDialog

::attribute employees
::attribute empCount
::attribute empIndex
::attribute empView
::attribute empInitial

::method configure
    expose isChanged
    use arg employees, count, index

    self~employees = employess
    self~empCount  = count
    self~empIndex  = index
    self~empInitial = .Employee~new()

    self~connectEditEvent(IDC_EDIT_NAME_A,      "CHANGE",    onChange)
    self~connectComboBoxEvent(IDC_CB_CITY_A,    "SELCHANGE", onChange)
    self~connectListBoxEvent(IDC_LB_POSITION_A, "SELCHANGE", onChange)
    self~connectButtonEvent(IDC_RB_MALE_A,      "CLICKED",   onChange)
    self~connectButtonEvent(IDC_RB_FEMALE_A,    "CLICKED",   onChange)
    self~connectButtonEvent(IDC_CHK_MARRIED_A,  "CLICKED",   onChange)
    self~connectButtonEvent(IDC_CHK_FULLTIME_A, "CLICKED",   onChange)
    isChanged = .false

    self~connectButtonEvent(IDC_PB_PRINT_A, "CLICKED", onPrint)
    self~connectButtonEvent(IDC_PB_ADD_A, "CLICKED", onAdd)

::method initDialog
    expose cbCity lbPosition editName

    self~setControls
    self~empView~fillBoxes

    editName~connectCharEvent(onChar)

    -- If we are the start page, it means there are no employees.  So we put up
    -- a message box informing the user she needs to add employees through this
    -- page.
    if self~propSheet~startPage == 1 then do
        title = "Acme Software - Employee Manager"
        msg   = "The Employee Database is empty." || .endOfLine~copies(2) ||     -
                "Use the 'Add Employees' page to add employees."

        ret = MessageDialog(msg, self~hwnd, title)
    end


::method setActive unguarded

    self~defaultForm
    return 0

::method killActive unguarded
  expose isChanged
  use arg psDlg

  if isChanged then do
      title = "Acme Software - Add Employee"
      msg   = 'The addition of the new employee is not'  || .endOfLine ||           -
              'complete.  Leaving this page will result' || .endOfLine ||           -
              'in all changes being lost.'               || .endOfLine~copies(2) || -
              'To leave this page and abandon changes,'  || .endOfLine ||           -
              'press Ok.  To stay on the page and con-'  || .endOfLine ||           -
              'tinue adding a new employee, press Cancel'

      ret = MessageDialog(msg, self~hwnd, title, "OKCANCEL", "WARNING", 'DEFBUTTON2')
      if ret == self~IDCANCEL then return .false
  end

  return .true


::method onPrint unguarded

    currentEmployee = self~empView~createEmployee
    currentEmployee~print(self)
    return 0


::method onAdd unguarded

    newEmployee = self~empView~createEmployee
    self~propSheet~newEmployeeNotify(newEmployee)

    self~defaultForm
    return 0


::method onChar unguarded
    use arg char, isShift, isCtrl, isAlt, misc, editControl

    if char~d2c == ',' then do
      result = ' '~c2d
      reply result

      msg   = 'Employee names can not contain a comma. You can not type a comma here'
      title = "Unacceptable Character"
      editControl~showBalloon(title, msg, "ERROR")
    end
    else do
      return .true
    end


::method onChange unguarded
    expose isChanged pbPrint pbAdd editName

    if isChanged then do
        if self~empView~sameAs(self~empInitial) then isChanged = .false
    end
    else do
        if \ self~empView~sameAs(self~empInitial) then isChanged = .true
    end

    -- The Add and Print buttons are only enabled when there is some change and
    -- the employee name is not blank.  The status of the buttons *could* change
    -- on any change, but only *will* change under certain cicrcumstances.
    -- Rather than try to track and determine those exact circumstances, we just
    -- check if the buttons should be enabled or not and do that on each change.
    if isChanged, editName~getText~strip \== '' then do
        pbPrint~enable
        pbAdd~enable
    end
    else do
    		pbPrint~disable
        pbAdd~disable
    end

    return 0


::method setControls private
    expose editName cbCity lbPosition rbMale rbFemale chkMarried chkFullTime pbPrint pbAdd

    editName    = self~newEdit(IDC_EDIT_NAME_A)
    cbCity      = self~newComboBox(IDC_CB_CITY_A)
    lbPosition  = self~newListBox(IDC_LB_POSITION_A)
    rbMale      = self~newRadioButton(IDC_RB_MALE_A)
    rbFemale    = self~newRadioButton(IDC_RB_FEMALE_A)
    chkMarried  = self~newCheckBox(IDC_CHK_MARRIED_A)
    chkFullTime = self~newCheckBox(IDC_CHK_FULLTIME_A)

    self~empView = .EmployeeView~new(editName, cbCity, lbPosition, rbMale, rbFemale, chkMarried, chkFullTime)

    pbPrint = self~newPushButton(IDC_PB_PRINT_A)
    pbAdd   = self~newPushButton(IDC_PB_ADD_A)


::method defaultForm private
    expose pbPrint pbAdd

    pbPrint~disable
    pbAdd~disable

    self~empView~displayEmployee(self~empInitial)
    self~empView~editName~assignFocus



/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
  EmployeeEdit - A dialog class for a page in the PropertySheetDialog.  This
                 page allows the user to edit an existing employee's record
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
::class 'EmployeeEdit' subclass RcPSPDialog

::attribute employees
::attribute empCount
::attribute empIndex
::attribute empInitial
::attribute empView

::method configure
    expose isChanged
    use arg employees, count, index

    self~employees = employees
    self~empCount  = count
    self~empIndex  = index

    self~empInitial = .nil

    self~connectEditEvent(IDC_EDIT_NAME_E,      "CHANGE",    onChange)
    self~connectComboBoxEvent(IDC_CB_CITY_E,    "SELCHANGE", onChange)
    self~connectListBoxEvent(IDC_LB_POSITION_E, "SELCHANGE", onChange)
    self~connectButtonEvent(IDC_RB_MALE_E,      "CLICKED",   onChange)
    self~connectButtonEvent(IDC_RB_FEMALE_E,    "CLICKED",   onChange)
    self~connectButtonEvent(IDC_CHK_MARRIED_E,  "CLICKED",   onChange)
    self~connectButtonEvent(IDC_CHK_FULLTIME_E, "CLICKED",   onChange)
    isChanged = .false

    self~connectButtonEvent(IDC_PB_PRINT_E, "CLICKED", onPrint)
    self~connectButtonEvent(IDC_PB_SAVE_E, "CLICKED", onSave)
    self~connectButtonEvent(IDC_PB_RESET_E, "CLICKED", onReset)


::method initDialog
    expose cbCity lbPosition

    self~setControls
    self~empView~fillBoxes


::method setActive unguarded

  self~setEmpRecord
  return 0


::method onPrint unguarded

    if self~empInitial \== .nil then do
        currentEmployee = self~empView~createEmployee
        currentEmployee~print(self)
    end
    return 0

::method onSave unguarded

    editedEmployee = self~empView~createEmployee
    self~propSheet~editedEmployeeNotify(editedEmployee)

    return 0


::method onReset unguarded
    self~setEmpRecord


::method onChange unguarded
    expose isChanged pbPrint pbSave pbReset editName

    if self~empInitial == .nil then return 0

    if isChanged then do
        if self~empView~sameAs(self~empInitial) then isChanged = .false
    end
    else do
        if \ self~empView~sameAs(self~empInitial) then isChanged = .true
    end

    txt = editName~getText~strip

    if txt == '' then do
    		pbPrint~disable
        pbSave~disable
        pbReset~enable
    end
    else if isChanged then do
        pbPrint~enable
        pbSave~enable
        pbReset~enable
    end
    else do
        pbPrint~enable
        pbSave~disable
        pbReset~disable
    end

    return 0


::method setControls private
    expose cbCity lbPosition rbMale rbFemale chkMarried chkFullTime editName pbPrint pbSave pbReset

    cbCity      = self~newComboBox(IDC_CB_CITY_E)
    lbPosition  = self~newListBox(IDC_LB_POSITION_E)
    rbMale      = self~newRadioButton(IDC_RB_MALE_E)
    rbFemale    = self~newRadioButton(IDC_RB_FEMALE_E)
    chkMarried  = self~newCheckBox(IDC_CHK_MARRIED_E)
    chkFullTime = self~newCheckBox(IDC_CHK_FULLTIME_E)
    editName    = self~newEdit(IDC_EDIT_NAME_E)

    self~empView = .EmployeeView~new(editName, cbCity, lbPosition, rbMale, rbFemale, chkMarried, chkFullTime)

    pbReset = self~newPushButton(IDC_PB_RESET_E)
    pbSave  = self~newPushButton(IDC_PB_SAVE_E)
    pbPrint = self~newPushButton(IDC_PB_PRINT_E)


::method setEmpRecord
    expose pbSave pbPrint pbReset isChanged

    if self~empCount < 1 then do
        self~empView~disable
        pbSave~disable
        pbPrint~disable
        pbReset~disable
        return 0
    end

    isChanged = .false
    pbSave~disable
    pbPrint~enable

    self~empInitial = self~employees[self~empIndex]
    self~empView~displayEmployee(self~empInitial)
    self~empView~editName~assignFocus



/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
  EmployeeBrowse - A dialog class for a page in the PropertySheetDialog.  This
                   page allows the user to scroll through employee records one
                   at a time.
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
::class 'EmployeeBrowse' subclass RcPSPDialog

::attribute employees
::attribute empCount
::attribute empIndex
::attribute empView

::method configure
    use arg employees, count, empIndex

    self~employees = employees
    self~empCount  = count
    self~empIndex  = empIndex

    self~connectButtonEvent(IDC_PB_PRINT_B, "CLICKED", onPrint)
    self~connectUpDownEvent(IDC_UPD, "DELTAPOS", onEmpChange)


::method initDialog
    expose upDown

    self~setControls
    self~empView~fillBoxes


::method setActive unguarded

    self~updateUpdown
    return 0


::method onPrint unguarded

    if self~empCount > 0 then do
        currentEmployee = self~empView~createEmployee
        currentEmployee~print(self)
    end
    return 0


::method onEmpChange unguarded
    use arg curPos, increment

    self~setEmpRecord(curPos + increment)
    return .UpDown~deltaPosReply


::method setEmpRecord private
    expose upDown
    use strict arg empIndex

    if empIndex < 1 then return self~noRecord('bottom')
    else if empIndex > upDown~getRange~max then return self~noRecord('top')

    emp = self~employees[empIndex]
    self~empView~displayEmployee(emp)

    self~propSheet~selectedEmployeeNotify(empIndex)


::method setControls private
    expose cbCity lbPosition rbMale rbFemale chkMarried chkFullTime editName upDown pbPrint

    cbCity      = self~newComboBox(IDC_CB_CITY_B)
    lbPosition  = self~newListBox(IDC_LB_POSITION_B)
    rbMale      = self~newRadioButton(IDC_RB_MALE_B)
    rbFemale    = self~newRadioButton(IDC_RB_FEMALE_B)
    chkMarried  = self~newCheckBox(IDC_CHK_MARRIED_B)
    chkFullTime = self~newCheckBox(IDC_CHK_FULLTIME_B)
    editName    = self~newEdit(IDC_EDIT_NAME_B)

    self~empView = .EmployeeView~new(editName, cbCity, lbPosition, rbMale, rbFemale, chkMarried, chkFullTime)

    upDown  = self~newUpDown(IDC_UPD)
    pbPrint = self~newPushButton(IDC_PB_PRINT_B)


::method noRecord private
    use strict arg direction
    return MessageDialog('At the' direction 'of the records', self~hwnd, -
                         'Employee Records')


::method updateUpdown private
    expose pbPrint upDown

    if self~empCount < 1 then do
        upDown~setRange(0, 0)
        upDown~setPosition(0)
        upDown~disable
        pbPrint~disable
        self~empView~blank
    end
    else do
        upDown~enable
        upDown~setRange(1, self~empCount)
        upDown~setPosition(self~empIndex)
        pbPrint~enable
        self~empView~displayEmployee(self~employees[self~empIndex])
    end



/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
  EmployeeList - A dialog class for a page in the PropertySheetDialog.  This
                 page allows the user to look at multiple employee records in
                 one view.
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
::class 'EmployeeList' subclass RcPSPDialog

::attribute employees
::attribute empCount
::attribute empIndex

::method configure
    expose contextMenu
    use arg employees, count, index

    self~employees = employees
    self~empCount  = count
    self~empIndex  = index

    self~connectListViewEvent(IDC_LV_EMPLOYEES, "SELECTCHANGED", onSelectionChanged)

    mb = .ScriptMenuBar~new(.application~srcDir'employee11tab.rc', IDM_CONTEXT_MENUBAR)
    contextMenu = mb~getPopup(IDM_POP_CONTEXT)

::method newEmployeeNotify
    expose lv

    emp = self~employees[self~empIndex]
    self~addEmployeeRow(lv, emp)

    self~ensureSelection


::method editedEmployeeNotify
    expose lv

    emp   = self~employees[self~empIndex]
    index = self~empIndex - 1

    gender = 'Male'
    if \ emp~male then gender = 'Female'

    mStatus = 'Married'
    if \ emp~married then mStatus = 'Unmarried'

    eStatus = 'Full Time'
    if \ emp~fullTime then eStatus = 'Part Time'

    lv~setItemText(index, 0, emp~name)
    lv~setItemText(index, 1, emp~city)
    lv~setItemText(index, 2, emp~position)
    lv~setItemText(index, 3, gender)
    lv~setItemText(index, 4, mStatus)
    lv~setItemText(index, 5, eStatus)

    self~ensureSelection


::method initDialog
    expose lv contextMenu

    lv = self~newListView(IDC_LV_EMPLOYEES)

    lv~addExtendedStyle('CHECKBOXES GRIDLINES FULLROWSELECT')

    lv~insertColumn(0, "Name", 50)
    lv~insertColumn(1, "City", 40)
    lv~insertColumn(2, "Position", 40)
    lv~insertColumn(3, "Gender", 30)
    lv~insertColumn(4, "Marital Status", 30)
    lv~insertColumn(5, "Employment Classification", 40)

    do i = 1 to self~empCount
      self~addEmployeeRow(lv, self~employees[i])
    end

    self~ensureSelection

    contextMenu~assignTo(self, .true)
    contextMenu~connectContextMenu(onContext, lv~hwnd)


::method onSelectionChanged unguarded
    use arg id, itemIndex, state

    if state == 'SELECTED' then do
      self~propSheet~selectedEmployeeNotify(itemIndex + 1)
    end


::method setActive unguarded
    expose lv

    self~ensureSelection
    return 0


::method onContext
  expose contextMenu lv
  use arg hwnd, x, y

  if x == -1, y == -1 then do
      -- The keyboard was used, not the mouse.  Position the context menu
      -- towards the bottom right corner of the list view.
      rect = lv~windowRect
      x = rect~right - .SM~cxVScroll - 15
      y = rect~bottom - 15

      pos = .Point~new(x, y)
  end
  else do
      pos = .Point~new(x, y)

      p = pos~copy
      lv~screen2client(p)
      index = lv~hitTestInfo(p)

      if index == -1 then do
        contextMenu~disable(.array~of(IDM_EDIT, IDM_DELETE))
        self~ensureSelection
      end
  end

  ret = contextMenu~show(pos)

  return 0

::method browseEmployees unguarded
    self~propSheet~setCurSel( , 3)
    return 0

::method addEmployee unguarded
    self~propSheet~setCurSel( , 1)
    return 0

::method editEmployee unguarded
    self~propSheet~setCurSel( , 2)
    return 0

::method deleteEmployee unguarded
    self~propSheet~maybeDeleteEmployee
    return 0

::method deleteEmployeeNotify unguarded
    expose lv
    use strict arg index

    lv~delete(index - 1)
    self~ensureSelection

    return 0

::method ensureSelection private
    expose lv

    index = self~empIndex - 1
    if index < 0 then index = 0
    lv~select(index)
    lv~focus(index)

    return 0


::method addEmployeeRow private
    use strict arg list, employee

    gender = 'Male'
    if \ employee~male then gender = 'Female'

    mStatus = 'Married'
    if \ employee~married then mStatus = 'Unmarried'

    eStatus = 'Full Time'
    if \ employee~fullTime then eStatus = 'Part Time'

    e = employee
    list~addRow( , , e~name, e~city, e~position, gender, mStatus, eStatus)


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
  Employee - A class that reflects a single, specific, employee.
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
::class 'Employee'

::attribute name
::attribute city
::attribute position
::attribute male
::attribute married
::attribute fullTime

::method init
    expose name city position male married fullTime
    use strict arg name = "", city = "New York", position = "Software Developer",     -
                   male = .true, married = .false, fullTime = .true

::method isValid
    expose name
    return name \== ''


::method print
    expose name city position male married fullTime
    use strict arg dlg

    eol = .endOfLine
    tab = '09'x

    if \ self~isValid then do
        title = "Acme Software - Internal Error Detected"
        msg = "Attempting to print invalid employee record." || eol~copies(2)  -
              "Employee record has no assigned name."
        icon = 'ERROR'
    end
    else do
        title = "Acme Software - Employee:"

        if male then msg = "Mr." name
        else msg = "Ms." name

        if married then msg ||= " (married) "

        msg ||= eol

        if fullTime then status = 'Full Time Employee'
        else status = 'Part Time Employee'

        msg ||= eol || "City:"       || tab~copies(2) || city     || eol || -
                       "Profession:" || tab           || position || eol || -
                       'Status:'     || tab~copies(2) || status

        icon = 'INFORMATION'
    end

    j = MessageDialog(msg, dlg~hwnd, title, , icon)


::method toCSV
    expose name city position male married fullTime
    use strict arg

    if male then mf = "M"
    else mf = "F"

    if married then mu = "M"
    else mu = 'U'

    if fullTime then fp = 'F'
    else fp = 'P'

    txt = name', 'city', 'position', 'mf', 'mu', 'fp

    return txt



/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*\
  EmployeeView - A class containing the dialog controls used to display an
                 employee in a dialog.
\* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -*/
::class 'EmployeeView' public

::attribute editName
::attribute cbCity
::attribute lbPosition
::attribute rbMale
::attribute rbFemale
::attribute chkMarried
::attribute chkFullTime

::method init
  expose editName cbCity lbPosition rbMale rbFemale chkMarried chkFullTime
  use strict arg editName, cbCity, lbPosition, rbMale, rbFemale, chkMarried, chkFullTime

/** fillBoxes()
 * Fills the city combo box and the position list box with the correct items.
 */
::method fillBoxes
    expose cbCity lbPosition
    use strict arg

    cbCity~add("Munich")
    cbCity~add("New York")
    cbCity~add("San Francisco")
    cbCity~add("Stuttgart")
    cbCity~add("San Diego")
    cbCity~add("Tucson")
    cbCity~add("Houston")
    cbCity~add("Los Angeles")

    lbPosition~add("Business Manager")
    lbPosition~add("Engineering Manager")
    lbPosition~add("Software Developer")
    lbPosition~add("Software QA")
    lbPosition~add("Accountant")
    lbPosition~add("Security")
    lbPosition~add("Secretary")
    lbPosition~add("Recptionist")
    lbPosition~add("Lab Manager")
    lbPosition~add("Lawyer")
    lbPosition~add("CEO")


/** displayEmployee()
 * Sets the state of the controls to reflect the specified employee
 */
::method displayEmployee
    use strict arg emp

    self~editName~setText(emp~name)
    self~cbCity~select(emp~City)
    self~lbPosition~select(emp~Position)

    if emp~male then do
        self~rbMale~check
        self~rbFemale~uncheck
    end
    else do
        self~rbFemale~check
        self~rbMale~uncheck
    end

    if emp~married then self~chkMarried~check
    else self~chkMarried~uncheck

    if emp~fullTime then self~chkFullTime~check
    else self~chkFullTime~uncheck


/** disable()
 * Disables all the controls and sets the edit control text to the empty string.
 */
::method disable
    use strict arg

    self~editName~setText("")

    self~editName~disable
    self~cbCity~disable
    self~lbPosition~disable

    self~rbMale~disable
    self~rbFemale~disable
    self~chkMarried~disable
    self~chkFullTime~disable


/** blank()
 * Sets all the controls to a 'blank' state.
 */
::method blank
    use strict arg

    self~editName~setText("")
    --self~cbCity~
    self~lbPosition~deselectIndex

    self~rbMale~uncheck
    self~rbFemale~uncheck
    self~chkMarried~uncheck
    self~chkFullTime~uncheck


/** match()
 * Tests if the state of the controls match the specified employee.
 */
::method sameAs
    use strict arg emp

    if self~editName~getText      \== emp~name     then return .false
    if self~cbCity~selected       \== emp~City     then return .false
    if self~lbPosition~selected   \== emp~Position then return .false

    if self~rbMale~checked        & \ emp~male     then return .false
    if \ self~rbMale~checked      &   emp~male     then return .false

    if self~chkMarried~checked    & \ emp~married  then return .false
    if \ self~chkMarried~checked  &   emp~married  then return .false

    if self~chkFullTime~checked   & \ emp~fullTime then return .false
    if \ self~chkFullTime~checked &  emp~fullTime  then return .false

    return .true

/** createEmployee()
 * Instantiates a new Employee object using the current state of the controls,
 * and returns it if it is valid.  If it is not valid, returns .nil
 */
::method createEmployee
    use strict arg

    name     = self~editName~getText~strip
    city     = self~cbCity~selected
    position = self~lbPosition~selected
    male     = self~rbMale~checked
    married  =  self~chkMarried~checked
    fullTime = self~chkFullTime~checked

    emp = .Employee~new(name, city, position, male, married, fullTime)

    if emp~isValid then return emp
    else return .nil


