/* CLASS: BKPTLIST.CLS
   Provide the specific capabilities of a list box that holds breakpoint       information.  This include managing a parallel collection of breakpoint.
   See BkptPresenter and associated classes for more information.
   Use findStrings() in globals.act.

   REQUIRE: BKPTPRES.CLS BKPTINFO.CLS
 */!!

inherit(ListBox, #BkptList, #(bkptCollection /* breakpoints in server */), 2, nil)!!

now(class(BkptList))!!

/* 6/14/1992 21:49 - Actor
  Create a instance of BkptList. 
*/
Def new(self, id, par | theLB)
{ 
  theLB := new(self:Behavior);
  /* create object */
  setVars(theLB, id, par);
  create(theLB, nil, "ListBox", LBS_STANDARD_NOSORT bitOr WS_CHILD
    bitOr LBS_USETABSTOPS);
  if handle(theLB) = 0
  then alert(System, self, #wCreateError);
  endif;
  init(theLB);
  ^theLB;
}

!!

now(BkptList)!!

/* 10/8/1992 10:28 - PUBLIC (to its parent) 
  Return the bkptCollection.
*/
Def bkptCollection(self)
{ 
  ^bkptCollection; 
}
!!

/* Allow function keys to work without using accelerators. */
Def WM_KEYDOWN(self, wp, lp)
{ 
  if between(wp, 0x70, 0x79)
    checkFuncKey(parent, wp, 0x10000);
  else
    execWindowProc(self,#WM_KEYDOWN,wp,lp);
  endif;
}!!

/* 6/14/1992 21:53 - PUBLIC
  Add a new breakpoint entry to the list. Return error code in idx.
*/
Def addBkpt(self, bkpt | idx, bkptStr )
{ 
  bkptStr := asLBString(bkpt);
  idx := addString(self, bkptStr);
  add(bkptCollection, bkptID(bkpt), bkpt);
  ^idx;
}
!!

/* 6/15/1992 14:09 - Actor
  Clear the list box and bkptCollection
*/
Def clear(self)
{
  /* Delete all BkptInfo object in colection first */
  if size(bkptCollection) > 0 then
    do (bkptCollection,
      {using(bkptObj) deleteBkptInfo(bkptObj);
      });
  endif;    
  clear(bkptCollection);
  clearList(self);
}
!!

/* 6/14/1992 22:42 - PUBLIC
  Delete a breakpoint from the list and server.
*/
Def deleteBkpt(self, bkpt | selStr, bkptID)
{ 
  if bkptID :=  bkptID(bkpt) then
    deleteBkptInfo(bkptCollection[bkptID]);
    remove(bkptCollection, bkptID);   
    deleteString(self, getSelIdx(self));
    removeBkpt(HLBreakLibClass$Inst, bkptID);
    invalidate(self);
    ^GOOD;
  endif;  
  ^nil;    
}
!!

/* 6/18/1992 16:08 - PUBLIC
  Delete all breakpoints
*/
Def deleteBkpts(self)
{ 
  if size(bkptCollection) > 0 then
    clear(self);  /* Remove all bkptInfo objects */   
    ^removeAllBkpt(HLBreakLibClass$Inst);
  endif; 
}
!!

/* 6/15/1992 14:51 - PUBLIC
  Return the BkptInfo object correspond to the current selection of the list.
  Return nil if there is no selection.
*/
Def getSelBkpt(self | bkptID)
{ 
  if (bkptID := getSelBkptId(self)) then
    ^bkptCollection[bkptID];
  endif;
  ^nil;  
}
!!

/* 6/15/1992 14:45 - PRIVATE
  Return the ID of the current selected breakpoint.
*/
Def getSelBkptId(self | selStr, subStr, bkptID)
{ 
  bkptID := nil;
  if (selStr := getSelString(self)) <> nil then 
    /* Parse selStr into ("#module#func#line..." "id") */
    if (subStr := findStrings(selStr, "@")) cand subStr[1] then 
      bkptID := asInt(subStr[1], 10); /* Notes: id has value base 10 */
    endif;
  endif;

  ^bkptID;    
}
!!

/* 6/14/1992 21:51 - PRIVATE 
  Initializes the BkptList object by initializing the bkptCollection 
  instance variable  and setting the list box's tab stops and font. 
*/
Def init(self | tabStruct) 
{
  bkptCollection := new(Dictionary, 256);
  sendMessage(self, WM_SETFONT,
  Call GetStockObject(SYSTEM_FIXED_FONT), 1L);
  /* Set tab locations in LoadFile List box */
  tabStruct := new(Struct, 6);
  putWord(tabStruct, 30, 0);
  putWord(tabStruct, 50, 2);
  putWord(tabStruct, 100, 4);
  sendMessage(self, LB_SETTABSTOPS, 3, lP(tabStruct));
  freeHandle(tabStruct); 
}!!

/* 6/15/1992 14:13 - PUBLIC (to its parent) 
  Rebuild breakpoints collection and load all breakpoints into list.
*/
Def rebuildBkptCollection(self | bkptResult, loopBkpt, nextBkpt, err)
{ 
  /* Turn off redraw list box to avoid screen flickering */
  redrawOff(self);
  loopBkpt := nil;
  showWaitCurs();
  clear(self);
  loop
  while (bkptResult := getAllBkptNext(HLBreakLibClass$Inst, loopBkpt)) 
    begin
      /* WHERE: bkptResult = #(loopBkpt, nextBkpt) */
      loopBkpt := bkptResult[0];    /* Save the loopBkpt for the next one */
      /* add it to the list and collection */
      if (err := addBkpt(self, new(BkptInfo, bkptResult[1]))) < 0 then
        select 
          case err = -2 /* LB_ERRSPACE */
            displayFormattedError(ErrorTextLibClass$Inst, 
               ER_BKPT_MEM_FAIL, FORCE_POPUP, nil, nil, nil);
          endCase
          case err = -1 /* LB_ERR */
            displayFormattedError(ErrorTextLibClass$Inst, 
               ER_BKPT_CANT_ADD, FORCE_POPUP, nil, nil, nil);
          endCase
        endSelect;
        ^nil;
      endif; 
  endLoop;
  showOldCurs();
  redrawOn(self);
  invalidate(self);
  ^bkptCollection; 
}
!!

/* 6/19/1992 10:16 - PUBLIC
  Dynamically adjust the tabstop of LB string.
*/
Def setLBStringTabs(self, tmWidth | tabStruct)
{ 
  /* Set tab locations in LoadFile List box */
  tabStruct := new(Struct, 6);
  putWord(tabStruct, tmWidth*5, 0);
  putWord(tabStruct, tmWidth*10, 2);
  putWord(tabStruct, tmWidth*20, 4);
  sendMessage(self, LB_SETTABSTOPS, 3, lP(tabStruct));
  freeHandle(tabStruct); 
  ^GOOD;
}

!!

/* 6/15/1992 14:57 - PUBLIC
  After modified a breakpoint, update the its list. 
*/
Def updateBkptDisplay(self, bkpt | idx)
{ 
  if idx := getSelIdx(self) then
    deleteString(self, idx);
    setCurSel(self, insertString(self, asLBString(bkpt), idx));
  endif;  
}
!!
