* Program..: Browse.prg * Author...: Jeremy Suiter * Date.....: 26/03/2003 * * Notice...: Copyright (c) 2003, Jeremy Suiter, All Rights Reserved * Notes....: Visual DbEditor browse functions #Include "Font.ch" #Include "Gra.ch" #Include "Xbp.ch" #Include "Appevent.ch" #Include "Common.ch" #Include "Dmlb.ch" #Include "Dbstruct.ch" #Include "Inkey.ch" #Include "DbEditor.ch" #Include "Resources.ch" Static oProgress *************** Func EditBrowse(oDlg, oProgressBar) *************** Local x, aPP:={}, oColumn:=Nil, oBrowse:=Nil Begin Sequence // Create browser in the window oBrowse:=XbpBrowse():new(oDlg:drawingArea,,,,PRESPARAM_FANCY,.F.):create() oFocusBrowse:=oBrowse // Navigation code blocks for the browser oBrowse:skipBlock :={|n| (oDlg:area)->(DbSkipper(n)) } oBrowse:goTopBlock :={| | (oDlg:area)->(DbGoTop()) } oBrowse:goBottomBlock:={| | (oDlg:area)->(DbGoBottom()) } oBrowse:phyPosBlock :={| | (oDlg:area)->(Recno()) } oBrowse:stableBlock :={| | RefreshBrowses(oBrowse) } // Navigation code blocks for the vertical scroll bar oBrowse:posBlock :={| | (oDlg:area)->(DbPosition()) } oBrowse:goPosBlock :={|n| (oDlg:area)->(DbGoPosition(n)) } oBrowse:lastPosBlock :={| | 100 } oBrowse:firstPosBlock:={| | 0 } // 04/18/03 by MMM oBrowse:softTrack:=.F. // add record number column aPP:={{XBP_PP_COL_HA_CAPTION, "RECORD #" }, ; {XBP_PP_COL_FA_CAPTION, "RECORD #" }, ; {XBP_PP_COL_DA_BGCLR, GRA_CLR_DARKBLUE}, ; {XBP_PP_COL_DA_FGCLR, GRA_CLR_WHITE}, ; {XBP_PP_COL_DA_FRAMELAYOUT , XBPFRAME_BOX+XBPFRAME_THICK+XBPFRAME_RAISED }, ; {XBP_PP_COL_DA_CELLFRAMELAYOUT, XBPFRAME_BOX+XBPFRAME_RAISED }, ; {XBP_PP_COL_DA_HILITEFRAMELAYOUT, XBPFRAME_BOX+XBPFRAME_THICK+XBPFRAME_RAISED+XBPFRAME_DASHED}, ; {XBP_PP_COL_HA_BGCLR, GRA_CLR_DARKGRAY }, ; {XBP_PP_COL_HA_FGCLR, GRA_CLR_WHITE }, ; {XBP_PP_COL_FA_BGCLR, GRA_CLR_DARKGRAY }, ; {XBP_PP_COL_FA_FGCLR, GRA_CLR_WHITE }} oColumn:=XbpColumn():new(oBrowse,,,, aPP) oColumn:dataLink:={|| IIf(Eof(),"",Ntrim((oDlg:area)->(RecNo()))) } oColumn:colorBlock:={|| {GRA_CLR_WHITE, Iif(lShowDeleted .And. (oDlg:area)->(Deleted()),GRA_CLR_RED,GRA_CLR_DARKBLUE) } } oBrowse:addColumn(oColumn) oColumn:disable() // Add columns for all fields of the database For x:=1 To FCount() AddFieldColumn(x, oBrowse) IF oProgressBar != NIL oProgressBar:Increment() ENDIF Next // Delegate keys for editing to the Xbp???Column object oBrowse:keyBoard:={ |nKey, x, obj| BrowseKeys(nKey, obj, oBrowse) } // cargo used for deleted array oBrowse:cargo:={} oBrowse:show() oDlg:show() // show dialog after browse stable // set focus to browse and put cursor on correct column oBrowse:setLeftFrozen({1}) oBrowse:right() End Return Nil ******************* Func AddFieldColumn(x, oBrowse) ******************* Local cField, aPP, oColumn, nWidth:=0 , cHead, cFoot Begin Sequence cField:=FieldName(x) cHead:=cField cFoot:="["+DbStruct()[x,DBS_TYPE]+","+Ntrim(DbStruct()[x,DBS_LEN])+","+Ntrim(DbStruct()[x,DBS_DEC])+"]" nWidth:=Max(StringLength(cField),StringLength(XtoC(FieldGet(x)))) aPP:={{XBP_PP_COL_DA_CELLWIDTH, nWidth}, ; {XBP_PP_COL_HA_CAPTION, cHead }, ; {XBP_PP_COL_FA_CAPTION, cFoot }, ; {XBP_PP_COL_HA_BGCLR, GRA_CLR_DARKGRAY }, ; {XBP_PP_COL_HA_FGCLR, GRA_CLR_WHITE }, ; {XBP_PP_COL_FA_BGCLR, GRA_CLR_DARKGRAY }, ; {XBP_PP_COL_FA_FGCLR, GRA_CLR_WHITE } } If ValType(FieldGet(x))="M" // Memo field oColumn:=XbpMleColumn():new(oBrowse,,,, aPP) oColumn:bufferLength:=50 ElseIf ValType(FieldGet(x))="N" .And. DbStruct()[x,DBS_LEN]>0 .And. DbStruct()[x,DBS_DEC]=0 // Numeric integer oColumn:=XbpSpinbuttonColumn():new(oBrowse,,,, aPP) oColumn:setNumLimits(0, Val(Replicate("9",DbStruct()[x,DBS_LEN]))) ElseIf ValType(FieldGet(x))="N" .And. DbStruct()[x,DBS_LEN]>0 .And. DbStruct()[x,DBS_DEC]>0 // Numeric non-integer oColumn:=XbpGetColumn():new(oBrowse,,,, aPP) oColumn:picture :=Replicate("9",DbStruct()[x,DBS_LEN])+"."+Replicate("9",DbStruct()[x,DBS_DEC]) Else // other field types oColumn:=XbpGetColumn():new(oBrowse,,,, aPP) oColumn:bufferLength:=DbStruct()[x,DBS_LEN] If cField$cUpperCase oColumn:picture:="@!" EndIf EndIf oColumn:dataLink:=EditBlock(Alias()+"->"+cField) oColumn:cargo=cField oBrowse:addColumn(oColumn) End Return Nil *************** Func BrowseKeys(nKey, obj, oBrowse) *************** * handle browse keys Begin Sequence If obj:colpos==2 .And. nKey==xbeK_LEFT oBrowse:panLeft() oBrowse:right() Break EndIf Do Case Case nKey=xbeK_F2 // F2 - duplicate record DupRecord() Case nKey=xbeK_F3 .OR. nKey=xbeK_DEL // F3 - delete record DelRecord() Case nKey=xbeK_F4 // F4 - restore record RestRecord() Case nKey==xbeK_F6 // F6 - set scope or filter SetScope() Case nKey==xbeK_F8 // F8 - freeze colums FreezeCol() Case nKey==xbeK_F9 // F9 - unfreeze colums DefrostCol() Case nKey=xbeK_ALT_A // ALT-A append records from a file ImportData() Case nKey=xbeK_ALT_C // ALT-C copy records to a new file ExportData() Case nKey==xbeK_ALT_D // ALT-D bulk delete records BulkDeleteRecall(.T.) Case nKey=xbeK_ALT_E // ALT-E set database relations SetRelations() Case nKey=xbeK_ALT_G // ALT-G goto record number GotoRecord() Case nKey=xbeK_ALT_I .OR. nKey = xbeK_INS // ALT-I Insert record InsertRec() Case nKey=xbeK_ALT_P // ALT-P pack table PackZapTable(.T.) Case nKey=xbeK_ALT_L // ALT-L locate record LocateRecords() Case nKey=xbeK_ALT_M // ALT-M Sum/Average/Count MathFunc() Case nKey=xbeK_ALT_R // ALT-R replace data BulkReplace() Case nKey=xbeK_ALT_S // ALT-S seek record SeekRecord() Case nKey==xbeK_ALT_U // ALT-U bulk un-delete (recall) records BulkDeleteRecall(.F.) Case nKey=xbeK_ALT_Z // ALT-Z zap table PackZapTable(.F.) Case nKey==xbeK_CTRL_C // CTRL-C copies CopyField() Case nKey==xbeK_CTRL_P // CTRL-P previews table PreviewTable() Case nKey==xbeK_CTRL_V // CTRL-V pastes PasteField() Case nKey==xbeK_CTRL_X // CTRL-X cuts CutField() Case nKey==xbeK_ESC // Encerra PostAppEvent(xbeP_Close+1000, NIL, NIL, oBrowse:setParent()) Case nKey>31 .Or. nKey<256 // normal keys for editing If !"SDF"$DbInfo(DBO_DBENAME) .And. !"DEL"$DbInfo(DBO_DBENAME) .And. !oBrowse:setParent():setParent():read_only If obj:colPos>1 obj:getColumn(obj:colPos):keyboard(nKey) EndIf EndIf EndCase End Return Nil ************** Func DelRecord() ************** * deleted current record Begin Sequence If oFocusBrowse==Nil .Or. ("SDF"$DbInfo(DBO_DBENAME) .Or. "DEL"$DbInfo(DBO_DBENAME)) Break EndIf IF Deleted() RestRecord() ELSE If YesNo(BROWSE_DEL1,GEN_DELETE) If RecLock() If !lShowDeleted Aadd(oFocusBrowse:cargo,RecNo()) EndIf DbDelete() CommitUnlock() If !lShowDeleted DbSkip() If Eof() oFocusBrowse:goBottom() EndIf oFocusBrowse:refreshAll() oFocusBrowse:forceStable() Else oFocusBrowse:refreshAll() oFocusBrowse:forceStable() EndIf EndIf EndIf ENDIF End Return Nil *************** Func RestRecord() *************** * restore last deleted record record Local nRecNo:=0 Begin Sequence If oFocusBrowse==Nil .Or. ("SDF"$DbInfo(DBO_DBENAME) .Or. "DEL"$DbInfo(DBO_DBENAME)) Break EndIf If lShowDeleted .And. Len(oFocusBrowse:cargo)==0 .And. Deleted() .And. YesNo("Restore deleted record","Restore") .And. RecLock() DbRecall() CommitUnlock() oFocusBrowse:refreshAll() oFocusBrowse:forceStable() ElseIf Len(oFocusBrowse:cargo)>0 .And. YesNo(BROWSE_REC1,BROWSE_REC2) Set Deleted Off nRecNo:=RecNo() DbGoto(oFocusBrowse:cargo[Len(oFocusBrowse:cargo)]) If RecLock() DbRecall() CommitUnlock() Aremove(oFocusBrowse:cargo,Len(oFocusBrowse:cargo),1) oFocusBrowse:refreshAll() oFocusBrowse:forceStable() Else DbGoto(nRecNo) EndIf If lShowDeleted Set Deleted Off Else Set Deleted On EndIf EndIf End Return Nil *************** Func GotoRecord() *************** * goto selected record Local nEvent, mp1:=Nil, mp2:=Nil Local oDlg, oXbp, drawingArea, oGroup1, aPos:={}, oRecord:=Nil Begin Sequence aPos:=CenterPos({245,146},AppDesktop():currentSize()) oDlg:=XbpDialog():new(AppDesktop(), SetAppWindow(), aPos, {245,146}, , .F.) oDlg:icon:=ICON_MAIN oDlg:taskList:=.T. oDlg:border:=XBPDLG_RAISEDBORDERTHIN_FIXED oDlg:close:={|mp1,mp2,obj| PostAppEvent(xbeP_Close+1000) } oDlg:title:=BROWSE_GOTO oDlg:create() oDlg:setModalState(XBP_DISP_APPMODAL) oDlg:keyBoard:={| nKeyCode, uNIL, self | Iif(nKeyCode==xbeK_ESC,PostAppEvent(xbeP_Close+1000),Nil) } drawingArea:=oDlg:drawingArea drawingArea:setFontCompoundName("8.Helv") // goto record number oGroup1:=XbpStatic():new(drawingArea, , {12,48}, {216,60}) oGroup1:caption:=BROWSE_GOTO oGroup1:clipSiblings:=.T. oGroup1:type:=XBPSTATIC_TYPE_GROUPBOX oGroup1:create() oXbp:=XbpStatic():new(oGroup1, , {12,12}, {100,24}) oXbp:caption:=BROWSE_RECNUM oXbp:clipSiblings:=.T. oXbp:options:=XBPSTATIC_TEXT_VCENTER oXbp:create() oRecord:=XbpSpinbutton():new(oGroup1, , {124,12}, {80,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } }) oRecord:tabStop:=.T. oRecord:fastSpin:=.T. oRecord:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oRecord:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oRecord:create() oRecord:setNumLimits(1,LastRec()) oRecord:setData(RecNo()) // pushbuttons oXbp:=XbpPushButton():new(drawingArea, , {24,12}, {96,24}, { { XBP_PP_BGCLR, XBPSYSCLR_BUTTONMIDDLE }, { XBP_PP_FGCLR, -58 } }) oXbp:caption:=GEN_GOTO oXbp:tabStop:=.T. oXbp:create() oXbp:activate:={|| DbGoto(oRecord:getData()), oFocusBrowse:refreshAll(), oFocusBrowse:forceStable() } oXbp:=XbpPushButton():new(drawingArea, , {132,12}, {96,24}, { { XBP_PP_BGCLR, XBPSYSCLR_BUTTONMIDDLE }, { XBP_PP_FGCLR, -58 } }) oXbp:caption:=GEN_CLOSE oXbp:tabStop:=.T. oXbp:create() oXbp:activate:={|| PostAppEvent(xbeP_Close+1000) } oDlg:show() SetAppFocus(oRecord) nEvent:=xbe_None Do While nEvent<>xbeP_Close+1000 nEvent:=AppEvent(@mp1, @mp2, @oXbp) oXbp:handleEvent(nEvent, mp1, mp2) if nEvent == xbeP_Keyboard .and.; mp1 == xbeK_ESC exit endif EndDo oDlg:destroy() SetAppFocus(oFocusBrowse) End Return Nil *************** Func SeekRecord() *************** * goto selected record Local nEvent, mp1:=Nil, mp2:=Nil Local oDlg, oXbp, drawingArea, oGroup1, aPos:={}, oSeek:=Nil, nRecord:=Nil Begin Sequence aPos:=CenterPos({419,143},AppDesktop():currentSize()) oDlg:=XbpDialog():new(AppDesktop(), SetAppWindow(), aPos, {419,143}, , .F.) oDlg:icon:=ICON_MAIN oDlg:taskList:=.T. oDlg:border:=XBPDLG_RAISEDBORDERTHIN_FIXED oDlg:close:={|mp1,mp2,obj| PostAppEvent(xbeP_Close+1000) } oDlg:title:=GEN_SEEK oDlg:create() oDlg:setModalState(XBP_DISP_APPMODAL) oDlg:keyBoard:={| nKeyCode, uNIL, self | Iif(nKeyCode==xbeK_ESC,PostAppEvent(xbeP_Close+1000),Nil) } drawingArea:=oDlg:drawingArea drawingArea:setFontCompoundName("8.Helv") // seek data oGroup1:=XbpStatic():new(drawingArea, , {12,48}, {384,60}) oGroup1:caption:=BROWSE_SEEKDET oGroup1:clipSiblings:=.T. oGroup1:type:=XBPSTATIC_TYPE_GROUPBOX oGroup1:create() oXbp:=XbpStatic():new(oGroup1, , {12,12}, {84,24}) oXbp:caption:=GEN_SEEK oXbp:clipSiblings:=.T. oXbp:options:=XBPSTATIC_TEXT_VCENTER+XBPSTATIC_TEXT_RIGHT oXbp:create() oSeek:=XbpSLE():new(oGroup1, , {108,12}, {264,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } }) oSeek:tabStop:=.T. oSeek:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oSeek:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oSeek:create() // pushbuttons oXbp:=XbpPushButton():new(drawingArea, , {192,12}, {96,24}, { { XBP_PP_BGCLR, XBPSYSCLR_BUTTONMIDDLE }, { XBP_PP_FGCLR, -58 } }) oXbp:caption:=GEN_SEEK oXbp:tabStop:=.T. oXbp:create() oXbp:activate:={|| nRecord:=RecNo(), DbSeek(oSeek:getData()), IIf(Found(),Tone(100,3),DbGoto(nRecord)), ; oFocusBrowse:refreshAll(), oFocusBrowse:forceStable() } oXbp:=XbpPushButton():new(drawingArea, , {300,12}, {96,24}, { { XBP_PP_BGCLR, XBPSYSCLR_BUTTONMIDDLE }, { XBP_PP_FGCLR, -58 } }) oXbp:caption:=GEN_CLOSE oXbp:tabStop:=.T. oXbp:create() oXbp:activate:={|| PostAppEvent(xbeP_Close+1000) } oDlg:show() SetAppFocus(oSeek) nEvent:=xbe_None Do While nEvent<>xbeP_Close+1000 nEvent:=AppEvent(@mp1, @mp2, @oXbp) oXbp:handleEvent(nEvent, mp1, mp2) EndDo oDlg:destroy() SetAppFocus(oFocusBrowse) End Return Nil ****************** Func LocateRecords() ****************** * locate records Local nEvent, mp1:=Nil, mp2:=Nil Local oDlg, oXbp, drawingArea, oGroup1, aPos:={}, oFor:=Nil, oWhile:=Nil, lRest:=.F., oCount:=Nil Begin Sequence aPos:=CenterPos({426,251},AppDesktop():currentSize()) oDlg:=XbpDialog():new(AppDesktop(), SetAppWindow(), aPos, {426,251}, , .F.) oDlg:icon:=ICON_MAIN oDlg:taskList:=.T. oDlg:border:=XBPDLG_RAISEDBORDERTHIN_FIXED oDlg:close:={|mp1,mp2,obj| PostAppEvent(xbeP_Close+1000) } oDlg:title:=BROWSE_LOCREC oDlg:create() oDlg:setModalState(XBP_DISP_APPMODAL) oDlg:keyBoard:={| nKeyCode, uNIL, self | Iif(nKeyCode==xbeK_ESC,PostAppEvent(xbeP_Close+1000),Nil) } drawingArea:=oDlg:drawingArea drawingArea:setFontCompoundName("8.Helv") // locate conditions oGroup1:=XbpStatic():new(drawingArea, , {12,48}, {396,168}) oGroup1:caption:=BROWSE_LOCSET oGroup1:clipSiblings:=.T. oGroup1:type:=XBPSTATIC_TYPE_GROUPBOX oGroup1:create() oXbp:=XbpStatic():new(oGroup1, , {12,120}, {96,24}) oXbp:caption:=GEN_FOR oXbp:clipSiblings:=.T. oXbp:options:=XBPSTATIC_TEXT_VCENTER+XBPSTATIC_TEXT_RIGHT oXbp:create() oFor:=XbpSLE():new(oGroup1, , {120,120}, {264,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } }) oFor:tabStop:=.T. oFor:BufferLength:=512 oFor:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oFor:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oFor:create() oXbp:=XbpStatic():new(oGroup1, , {12,84}, {96,24}) oXbp:caption:=GEN_WHILE oXbp:clipSiblings:=.T. oXbp:options:=XBPSTATIC_TEXT_VCENTER+XBPSTATIC_TEXT_RIGHT oXbp:create() oWhile:=XbpSLE():new(oGroup1, , {120,84}, {264,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } }) oWhile:tabStop:=.T. oWhile:BufferLength:=512 oWhile:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oWhile:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oWhile:create() oCount:=XbpSpinbutton():new(oGroup1, , {120,48}, {72,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } }) oCount:tabStop:=.T. oCount:fastSpin:=.T. oCount:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oCount:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oCount:create() oCount:setNumLimits(1,LastRec()-RecNo()) oCount:setData(1) oXbp:=XbpStatic():new(oGroup1, , {12,48}, {96,24}) oXbp:caption:=GEN_COUNT oXbp:clipSiblings:=.T. oXbp:options:=XBPSTATIC_TEXT_VCENTER+XBPSTATIC_TEXT_RIGHT oXbp:create() oXbp:=XbpCheckbox():new(oGroup1, , {120,12}, {108,24}) oXbp:caption:=GEN_REST oXbp:tabStop:=.T. oXbp:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oXbp:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oXbp:create() oXbp:selected:={|| lRest:=IIf(lRest,.F.,.T.) } // pushbuttons oXbp:=XbpPushButton():new(drawingArea, , {96,12}, {96,24}, { { XBP_PP_BGCLR, XBPSYSCLR_BUTTONMIDDLE }, { XBP_PP_FGCLR, -58 } }) oXbp:caption:=GEN_LOCATE oXbp:tabStop:=.T. oXbp:create() oXbp:activate:={|| LocateFirstRecord(oFor:getData(), oWhile:getData(), oCount:getData(), lRest) } oXbp:=XbpPushButton():new(drawingArea, , {204,12}, {96,24}, { { XBP_PP_BGCLR, XBPSYSCLR_BUTTONMIDDLE }, { XBP_PP_FGCLR, -58 } }) oXbp:caption:=GEN_CONT oXbp:tabStop:=.T. oXbp:create() oXbp:activate:={|| LocateNextRecord(oFor:getData()) } oXbp:=XbpPushButton():new(drawingArea, , {312,12}, {96,24}, { { XBP_PP_BGCLR, XBPSYSCLR_BUTTONMIDDLE }, { XBP_PP_FGCLR, -58 } }) oXbp:caption:=GEN_CLOSE oXbp:tabStop:=.T. oXbp:create() oXbp:activate:={|| PostAppEvent(xbeP_Close+1000) } oDlg:show() SetAppFocus(oFor) nEvent:=xbe_None Do While nEvent<>xbeP_Close+1000 nEvent:=AppEvent(@mp1, @mp2, @oXbp) oXbp:handleEvent(nEvent, mp1, mp2) if nEvent == xbeP_Keyboard .and.; mp1 == xbeK_ESC exit endif EndDo oDlg:destroy() SetAppFocus(oFocusBrowse) End Return Nil ********************** Func LocateFirstRecord(cFor, cWhile, nCount, lRest) ********************** * locate first record (DbLocate) Local nRecord:=RecNo(), bFor:=Nil, bWhile:=Nil Begin Sequence If Empty(cFor) DbGoto(nRecord) Break EndIf bFor:=&("{|| "+cFor+" }") If !Empty(cWhile) bWhile:=&("{|| "+cWhile+" }") EndIf DbLocate(bFor, bWhile, nCount, , lRest) If Found() oFocusBrowse:refreshAll() oFocusBrowse:forceStable() Else DbGoto(nRecord) EndIf End Return Nil ********************** Func LocateNextRecord(cFor) ********************** * locate next record (DbContinue) Local nRecord:=RecNo() Begin Sequence If Empty(cFor) DbGoto(nRecord) Break EndIf If DbContinue() oFocusBrowse:refreshAll() oFocusBrowse:forceStable() Else DbGoto(nRecord) EndIf End Return Nil ***************** Func PackZapTable(lPack) ***************** Local lShared:=DbInfo(DBO_SHARED), cFileDbe:=DbInfo(DBO_DBENAME), x, nOrder:=0, aIndexes:={}, cTemp:="" Begin Sequence cTemp:=IIf(lPack,GEN_PACK,GEN_ZAP) If !YesNo(cTemp+" this table",cTemp) .Or. !YesNo(GEN_SURE,cTemp) Break EndIf // remember original work area and order number nOrder:=OrdNumber() // build list of index elements For x:=1 To OrdCount() OrdSetFocus(x) aAdd(aIndexes,{Upper(cPath+OrdBagName(x)), OrdName(x), OrdKey(x), OrdIsUnique(), OrdIsDescend(), OrdFor(x)}) Next // open exclusively If lShared DbCloseArea() If !NetUse(cFile,.T.,,Iif(!Empty(aIndexes) .And. !".CDX"$aIndexes[1,1],.T.,.F.),cFileDbe) Errm("Couldn't open table exclusively") If !NetUse(cFile,,,Iif(!Empty(aIndexes) .And. !".CDX"$aIndexes[1,1],.T.,.F.),cFileDbe) Break Else If !Empty(aIndexes) .And. !".CDX"$aIndexes[1,1] For x:=1 To Len(aIndexes) OrdListAdd(aIndexes[x,1]) Next EndIf EndIf Break Else If !Empty(aIndexes) .And. !".CDX"$aIndexes[1,1] For x:=1 To Len(aIndexes) OrdListAdd(aIndexes[x,1]) Next EndIf EndIf EndIf If lPack DbPack() Else DbZap() EndIf // reset file status back to shared If necessary If lShared OrdListClear() DbCloseArea() If !NetUse(cFile,,,Iif(!Empty(aIndexes) .And. !".CDX"$aIndexes[1,1],.T.,.F.),cFileDbe) Errm(ERR_ERRM1) Break EndIf If !Empty(aIndexes) .And. !".CDX"$aIndexes[1,1] For x:=1 To Len(aIndexes) OrdListAdd(aIndexes[x,1]) Next EndIf EndIf // reset original order OrdSetFocus(nOrder) DbGoTop() DbRegisterClient(oFocusBrowse:setParent():setParent()) oFocusBrowse:refreshAll() oFocusBrowse:forceStable() Errm(ERR_ERRM2,cTemp) End Return Nil **************** Func BulkReplace() **************** * bulk replace of data Local nEvent, mp1:=Nil, mp2:=Nil Local oDlg, oXbp, drawingArea, oGroup1, oGroup2, aPos:={}, oReplace:=Nil, oFor:=Nil, oWhile:=Nil, oRest:=Nil, oNext:=Nil Begin Sequence aPos:=CenterPos({423,352},AppDesktop():currentSize()) oDlg:=XbpDialog():new(AppDesktop(), SetAppWindow(), aPos, {423,352}, , .F.) oDlg:icon:=ICON_MAIN oDlg:taskList:=.T. oDlg:border:=XBPDLG_RAISEDBORDERTHIN_FIXED oDlg:close:={|mp1,mp2,obj| PostAppEvent(xbeP_Close+1000) } oDlg:title:="Bulk Replace Data" oDlg:create() oDlg:setModalState(XBP_DISP_APPMODAL) oDlg:keyBoard:={| nKeyCode, uNIL, self | Iif(nKeyCode==xbeK_ESC,PostAppEvent(xbeP_Close+1000),Nil) } drawingArea:=oDlg:drawingArea drawingArea:setFontCompoundName("8.Helv") // replace data oGroup1:=XbpStatic():new(drawingArea, , {12,264}, {384,60}) oGroup1:caption:="Replace Details" oGroup1:clipSiblings:=.T. oGroup1:type:=XBPSTATIC_TYPE_GROUPBOX oGroup1:create() oXbp:=XbpStatic():new(oGroup1, , {12,12}, {84,24}) oXbp:caption:="With" oXbp:clipSiblings:=.T. oXbp:options:=XBPSTATIC_TEXT_VCENTER+XBPSTATIC_TEXT_RIGHT oXbp:create() oReplace:=XbpSLE():new(oGroup1, , {108,12}, {264,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } }) oReplace:tabStop:=.T. oReplace:bufferLength:=512 oReplace:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oReplace:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oReplace:create() // options oGroup2:=XbpStatic():new(drawingArea, , {12,48}, {384,204}) oGroup2:caption:="Options" oGroup2:clipSiblings:=.T. oGroup2:type:=XBPSTATIC_TYPE_GROUPBOX oGroup2:create() oXbp:=XbpStatic():new(oGroup2, , {12,156}, {84,24}) oXbp:caption:=GEN_FOR oXbp:clipSiblings:=.T. oXbp:options:=XBPSTATIC_TEXT_VCENTER+XBPSTATIC_TEXT_RIGHT oXbp:create() oFor:=XbpSLE():new(oGroup2, , {108,156}, {264,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } }) oFor:tabStop:=.T. oFor:Bufferlength := 512 oFor:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oFor:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oFor:create() oXbp:=XbpStatic():new(oGroup2, , {12,120}, {84,24}) oXbp:caption:=GEN_WHILE oXbp:clipSiblings:=.T. oXbp:options:=XBPSTATIC_TEXT_VCENTER+XBPSTATIC_TEXT_RIGHT oXbp:create() oWhile:=XbpSLE():new(oGroup2, , {108,120}, {264,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } }) oWhile:tabStop:=.T. oWhile:Bufferlength := 512 oWhile:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oWhile:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oWhile:create() oXbp:=XbpStatic():new(oGroup2, , {12,84}, {84,24}) oXbp:caption:=GEN_NEXT oXbp:clipSiblings:=.T. oXbp:options:=XBPSTATIC_TEXT_VCENTER+XBPSTATIC_TEXT_RIGHT oXbp:create() oNext:=XbpSpinbutton():new(oGroup2, , {108,84}, {60,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } }) oNext:tabStop:=.T. oNext:fastSpin:=.T. oNext:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oNext:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oNext:create() oNext:setNumLimits(0,LastRec()-RecNo()) oNext:setData(0) oRest:=XbpCheckbox():new(oGroup2, , {108,48}, {96,24}) oRest:caption:=GEN_REST oRest:tabStop:=.T. oRest:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oRest:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oRest:create() // recessed static for export progress bar oXbp:=XbpStatic():new(oGroup2, , {12,12}, {360,20}) oXbp:type:=XBPSTATIC_TYPE_RECESSEDBOX oXbp:create() oProgress:=ProgressBar():new(oGroup2, , {12,12}, {360,20},,.F.) oProgress:create() oProgress:hide() // pushbuttons oXbp:=XbpPushButton():new(drawingArea, , {192,12}, {96,24}, { { XBP_PP_BGCLR, XBPSYSCLR_BUTTONMIDDLE }, { XBP_PP_FGCLR, -58 } }) oXbp:caption:="Replace" oXbp:tabStop:=.T. oXbp:create() oXbp:activate:={|| ReplaceData(oReplace:getData(), oFor:getData(), oWhile:getData(), oNext:getData(), oRest:getData()), ; Iif(!Empty(oReplace:getData()),PostAppEvent(xbeP_Close+1000),Nil) } oXbp:=XbpPushButton():new(drawingArea, , {300,12}, {96,24}, { { XBP_PP_BGCLR, XBPSYSCLR_BUTTONMIDDLE }, { XBP_PP_FGCLR, -58 } }) oXbp:caption:=GEN_CLOSE oXbp:tabStop:=.T. oXbp:create() oXbp:activate:={|| PostAppEvent(xbeP_Close+1000) } oDlg:show() SetAppFocus(oReplace) nEvent:=xbe_None Do While nEvent<>xbeP_Close+1000 nEvent:=AppEvent(@mp1, @mp2, @oXbp) oXbp:handleEvent(nEvent, mp1, mp2) if nEvent == xbeP_Keyboard .and.; mp1 == xbeK_ESC exit endif EndDo oDlg:destroy() SetAppFocus(oFocusBrowse) End Return Nil **************** Func ReplaceData(obj, cFor, cWhile, nNext, lRest) **************** * replace the data Local cType:=Nil, nRecord:=RecNo(), bField, bFor, bWhile, cField, nCount:=1, bTemp LOCAL bValue, cBValue Begin Sequence If obj=Nil .Or. Empty(obj) Break EndIf cField:=oFocusBrowse:getColumn(oFocusBrowse:colpos):cargo If !Empty(DbFilter()) .And. DbScope() Errm(ERR_ERRM3) EndIf If (!Empty(cFor) .And. !TestCondition(cFor)) .Or. (!Empty(cWhile) .And. !TestCondition(cWhile)) Break EndIf cType:=ValType(oFocusBrowse:getData()[1]) bValue := &("{||" + ALLTRIM(obj) + "}") cBValue := ValType(EVAL(bValue)) IF cBValue = "M" cBValue := "C" ENDIF If !cBValue==cType Errm(ERR_ERRM4) Break EndIf If !YesNo(cField+" with '"+ ALLTRIM(obj) +"'",GEN_REPLACE) Break EndIf If !Empty(cFor) bTemp:=&("{|| "+cFor+" }") bFor:={|| oProgress:increment(), Eval(bTemp) } Else bFor:={|| oProgress:increment() } EndIf If !Empty(cWhile) bWhile:=&("{|| "+cWhile+" }") EndIf DbSuspendNotifications() If !Empty(cFor) .Or. !Empty(bWhile) .Or. nNext>0 .Or. lRest DbEval({|| nCount++ }, bFor, bWhile, Iif(nNext>0,nNext,Nil), , lRest) DbGoto(nRecord) Else nCount:=LastRec() EndIf oProgress:minimum:=1 oProgress:maximum:=nCount oProgress:current:=1 oProgress:show() // In case of replaces with nNext or lRest specified, go to current record DbGoto(nRecord) bField:=FieldBlock(cField) DbEval({|| IIf(RecLock(),Eval(bField,Eval(bValue)),Nil) }, bFor, bWhile, Iif(nNext>0,nNext,Nil), , lRest) CommitUnlockAll() DbResumeNotifications() oProgress:hide() DbGoto(nRecord) oFocusBrowse:refreshAll() oFocusBrowse:forceStable() End Return Nil ******************* Func RefreshBrowses(oBrowse) ******************* Local x, y, z, aChildList:={}, aBrowseChilds:={} Begin Sequence aChildList:=oBrowse:setParent():setParent():setParent():childList() For x:=1 To Len(oBrowse:setParent():setParent():relations) For y:=1 to Len(aChildList) If aChildList[y]:isDerivedFrom("XbpBrowseDialog") .And. Alias(aChildList[y]:area)==oBrowse:setParent():setParent():relations[x,1] aBrowseChilds:=aChildList[y]:drawingArea:childlist() For z:=1 to Len(aBrowseChilds) If aBrowseChilds[z]:isDerivedFrom("XbpBrowse") aBrowseChilds[z]:refreshAll() aBrowseChilds[z]:forceStable() EndIf Next EndIf Next Next End Return Nil ********************* Func BulkDeleteRecall(lDelete) ********************* * bulk delete or recall records Local nEvent, mp1:=Nil, mp2:=Nil Local oDlg, oXbp, drawingArea, oGroup1, aPos:={}, oFor:=Nil, oWhile:=Nil, oRest:=Nil, oNext:=Nil Begin Sequence aPos:=CenterPos({415,291},AppDesktop():currentSize()) oDlg:=XbpDialog():new(AppDesktop(), SetAppWindow(), aPos, {415,291}, , .F.) oDlg:icon:=ICON_MAIN oDlg:taskList:=.T. oDlg:border:=XBPDLG_RAISEDBORDERTHIN_FIXED oDlg:close:={|mp1,mp2,obj| PostAppEvent(xbeP_Close+1000) } oDlg:title:="Bulk "+IIf(lDelete,GEN_DELETE,GEN_RECALL)+" Records" oDlg:create() oDlg:setModalState(XBP_DISP_APPMODAL) oDlg:keyBoard:={| nKeyCode, uNIL, self | Iif(nKeyCode==xbeK_ESC,PostAppEvent(xbeP_Close+1000),Nil) } drawingArea:=oDlg:drawingArea drawingArea:setFontCompoundName("8.Helv") oGroup1:=XbpStatic():new(drawingArea, , {12,48}, {384,204}) oGroup1:caption:="Options" oGroup1:clipSiblings:=.T. oGroup1:type:=XBPSTATIC_TYPE_GROUPBOX oGroup1:create() oXbp:=XbpStatic():new(oGroup1, , {12,156}, {84,24}) oXbp:caption:=GEN_FOR oXbp:clipSiblings:=.T. oXbp:options:=XBPSTATIC_TEXT_VCENTER+XBPSTATIC_TEXT_RIGHT oXbp:create() oFor:=XbpSLE():new(oGroup1, , {108,156}, {252,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } }) oFor:tabStop:=.T. oFor:bufferLength:=512 oFor:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oFor:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oFor:create() oXbp:=XbpStatic():new(oGroup1, , {12,120}, {84,24}) oXbp:caption:=GEN_WHILE oXbp:clipSiblings:=.T. oXbp:options:=XBPSTATIC_TEXT_VCENTER+XBPSTATIC_TEXT_RIGHT oXbp:create() oWhile:=XbpSLE():new(oGroup1, , {108,120}, {252,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } }) oWhile:tabStop:=.T. oWhile:bufferLength:=512 oWhile:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oWhile:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oWhile:create() oXbp:=XbpStatic():new(oGroup1, , {12,84}, {84,24}) oXbp:caption:=GEN_NEXT oXbp:clipSiblings:=.T. oXbp:options:=XBPSTATIC_TEXT_VCENTER+XBPSTATIC_TEXT_RIGHT oXbp:create() oNext:=XbpSpinbutton():new(oGroup1, , {108,84}, {60,24}, { { XBP_PP_BGCLR, XBPSYSCLR_ENTRYFIELD } }) oNext:tabStop:=.T. oNext:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oNext:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oNext:create() oRest:=XbpCheckbox():new(oGroup1, , {108,48}, {96,24}) oRest:caption:=GEN_REST oRest:tabStop:=.T. oRest:setInputFocus:={| uNil1,uNil2,self | XbpBorder(self,GRA_CLR_BLUE) } oRest:killInputFocus:={| uNil1,uNil2,self | XbpBorder(self, GRA_CLR_BACKGROUND) } oRest:create() oRest:selected:={|| NIL } oXbp:=XbpStatic():new(oGroup1, , {12,12}, {360,24}) oXbp:caption:="" oXbp:clipSiblings:=.T. oXbp:options:=6 oXbp:type:=XBPSTATIC_TYPE_RECESSEDBOX oXbp:create() oProgress:=ProgressBar():new(oGroup1, , {12,12}, {360,24},,.F.) oProgress:create() oProgress:hide() // pushbuttons oXbp:=XbpPushButton():new(drawingArea, , {300,12}, {96,24}, { { XBP_PP_BGCLR, XBPSYSCLR_BUTTONMIDDLE }, { XBP_PP_FGCLR, -58 } }) oXbp:caption:=GEN_CLOSE oXbp:tabStop:=.T. oXbp:create() oXbp:activate:={|| PostAppEvent(xbeP_Close+1000) } oXbp:=XbpPushButton():new(drawingArea, , {192,12}, {96,24}, { { XBP_PP_BGCLR, XBPSYSCLR_BUTTONMIDDLE }, { XBP_PP_FGCLR, -58 } }) oXbp:caption:=IIf(lDelete,GEN_DELETE,GEN_RECALL) oXbp:tabStop:=.T. oXbp:create() oXbp:activate:={|| DeleteRecallData(lDelete, oFor:getData(), oWhile:getData(), oNext:getData(), oRest:getData()), PostAppEvent(xbeP_Close+1000) } oDlg:show() SetAppFocus(oFor) nEvent:=xbe_None Do While nEvent<>xbeP_Close+1000 nEvent:=AppEvent(@mp1, @mp2, @oXbp) oXbp:handleEvent(nEvent, mp1, mp2) if nEvent == xbeP_Keyboard .and.; mp1 == xbeK_ESC exit endif EndDo oDlg:destroy() SetAppFocus(oFocusBrowse) End Return Nil ********************* Func DeleteRecallData(lDelete, cFor, cWhile, nNext, lRest) ********************* * Delete recall data Local nRecord:=RecNo(), bFor, bWhile, nCount:=1, bTemp Begin Sequence If !Empty(DbFilter()) .And. DbScope() Errm(ERR_ERRM7) EndIf If (!Empty(cFor) .And. !TestCondition(cFor)) .Or. (!Empty(cWhile) .And. !TestCondition(cWhile)) Break EndIf If !YesNo("Bulk "+Iif(lDelete,GEN_DELETE,GEN_RECALL)+" records") Break EndIf If !Empty(cFor) bTemp:=&("{|| "+cFor+" }") bFor:={|| oProgress:increment(), Eval(bTemp) } Else bFor:={|| oProgress:increment() } EndIf If !Empty(cWhile) bWhile:=&("{|| "+cWhile+" }") EndIf DbSuspendNotifications() DbEval({|| nCount++ }, bFor, bWhile, Iif(nNext>0,nNext,Nil), , lRest) DbGoto(nRecord) oProgress:minimum:=1 oProgress:maximum:=nCount oProgress:current:=1 oProgress:show() // In case of delets or recalls with nNext orlRest specified, go back to the current record DbGoto(nRecord) DbEval({|| IIf(!EOF() .AND. RecLock(),IIf(lDelete, DbDelete(), DbRecall()),Nil) }, bFor, bWhile, Iif(nNext>0,nNext,Nil), , lRest) CommitUnlockAll() DbResumeNotifications() oProgress:hide() DbGoto(nRecord) oFocusBrowse:refreshAll() oFocusBrowse:forceStable() End Return Nil