diff --git a/harbour/ChangeLog b/harbour/ChangeLog index 63fcdfcd16..c673bf7698 100644 --- a/harbour/ChangeLog +++ b/harbour/ChangeLog @@ -1,3 +1,10 @@ +2000-12-18 16:55 GMT+1 Maurilio Longo + * source/rtl/memoedit.prg + + Added all missing functionalities. Should be 100% compatible (tested very little) + * source/rtl/teditor.prg + * little changes to make it work better with memoedit.prg. Removed cUdF parameter from + ::New() method. + 2000-12-15 22:10 GMT -3 Luiz Rafael Culik *utils/hbmake/radios.prg utils/hbmake/checks.prg diff --git a/harbour/contrib/mysql/tsqlbrw.prg b/harbour/contrib/mysql/tsqlbrw.prg index 8c80a6c7a7..b1facca221 100644 --- a/harbour/contrib/mysql/tsqlbrw.prg +++ b/harbour/contrib/mysql/tsqlbrw.prg @@ -313,9 +313,8 @@ METHOD BrowseTable(lCanEdit, aExitKeys) CLASS TBrowseSQL while lKeepGoing - if !::Stable - ::ForceStable() - endif + while !::Stabilize() .and. NextKey() == 0 + enddo nKey := Inkey(0) diff --git a/harbour/source/rtl/memoedit.prg b/harbour/source/rtl/memoedit.prg index 12cc39647f..8e9018bd21 100644 --- a/harbour/source/rtl/memoedit.prg +++ b/harbour/source/rtl/memoedit.prg @@ -33,12 +33,191 @@ * */ -/* TODO: MemoEdit() is not compatible with clipper one. - Needs a lot more work to become */ #include "common.ch" +#include "hbclass.ch" +#include "memoedit.ch" #include "inkey.ch" + +// A specialized TEditor which can simulate MemoEdit() behaviour +CLASS TMemoEditor FROM TEditor + + DATA xUserFunction // User Function called to change default MemoEdit() behaviour + + METHOD MemoInit(cUserFunction) // This method is called after ::New() returns to perform ME_INIT actions + METHOD Edit() // Calls super:Edit(nKey) but is needed to handle configurable keys + METHOD KeyboardHook(nKey) // Gets called every time there is a key not handled directly by TEditor + METHOD IdleHook() // Gets called every time there are no more keys to hanlde just before TEditor blocks itself waiting for a char + +ENDCLASS + + +METHOD MemoInit(cUserFunction) CLASS TMemoEditor + + local nKey + + default cUserFunction to nil + + // Save/Init object internal representation of user function + ::xUserFunction := cUserFunction + + if ::xUserFunction <> nil + // Keep calling user function until it returns 0 + while (nKey := Do(::xUserFunction, ME_INIT, ::nRow, ::nCol - 1)) <> ME_DEFAULT + + do case + case nKey >= 1 .AND. nKey <= 31 + super:Edit(nKey) + + case nKey == ME_DATA + super:Edit(nKey) + + case nKey == ME_TOGGLEWRAP + ::lWordWrap := !::lWordWrap + + case nKey == ME_TOGGLESCROLL + // Don't know what to do ;-) + + case nKey == ME_WORDRIGHT + ::MoveCursor(K_CTRL_RIGHT) + + case nKey == ME_BOTTOMRIGHT + ::MoveCursor(K_CTRL_END) + + otherwise + + endcase + + enddo + + endif + +return Self + + +METHOD Edit() CLASS TMemoEditor + + local nKey, nUserKey + local lKeepGoing := .T. + + // NOTE: K_ALT_W is not compatible with clipper exit memo and save key, but I cannot discriminate + // K_CTRL_W and K_CTRL_END from harbour code. + local aConfigurableKeys := {K_CTRL_Y, K_CTRL_T, K_CTRL_B, K_CTRL_V, K_ALT_W, K_ESC } + + // If I have an user function I need to trap configurable keys and ask to + // user function if handle them the standard way or not + if ::lEditAllow .AND. ::xUserFunction <> nil + + while lKeepGoing + + // I need to test this condition here since I never block inside TEditor:Edit() + // if there is an user function + if NextKey() == 0 + ::IdleHook() + endif + nKey := Inkey(0) + + // Is it a configurable key ? + if AScan(aConfigurableKeys, nKey) > 0 + nUserKey := Do(::xUserFunction, iif(::lDirty, ME_UNKEYX, ME_UNKEY), ::nRow, ::nCol - 1) + + do case + case nUserKey == ME_DEFAULT + super:Edit(nKey) + if nKey == K_ESC .OR. ::lSaved + lKeepGoing := .F. + endif + + case nUserKey >= 1 .AND. nUserKey <= 31 + super:Edit(nUserKey) + + case nUserKey == ME_DATA + super:Edit(nKey) + + case nUserKey == ME_TOGGLEWRAP + ::lWordWrap := !::lWordWrap + + case nUserKey == ME_TOGGLESCROLL + // Don't know what to do ;-) + + case nUserKey == ME_WORDRIGHT + ::MoveCursor(K_CTRL_RIGHT) + + case nUserKey == ME_BOTTOMRIGHT + ::MoveCursor(K_CTRL_END) + + otherwise + + endcase + + else + super:Edit(nKey) + + endif + + enddo + + else + // If I can't edit text buffer or there is not a user function enter standard TEditor + // ::Edit() method which is able to handle everything + super:Edit() + + endif + +return Self + + +// I come here if I have an unknown key and it is not a configurable key +// if there is an user function I leave to it its handling +METHOD KeyboardHook(nKey) CLASS TMemoEditor + + local nUserKey + + if ::xUserFunction <> nil + nUserKey := Do(::xUserFunction, iif(::lDirty, ME_UNKEYX, ME_UNKEY), ::nRow, ::nCol - 1) + + do case + case nUserKey >= 1 .AND. nUserKey <= 31 + super:Edit(nUserKey) + + case nUserKey == ME_DATA + //super:Edit(nKey) + + case nUserKey == ME_TOGGLEWRAP + ::lWordWrap := !::lWordWrap + + case nUserKey == ME_TOGGLESCROLL + // Don't know what to do ;-) + + case nUserKey == ME_WORDRIGHT + ::MoveCursor(K_CTRL_RIGHT) + + case nUserKey == ME_BOTTOMRIGHT + ::MoveCursor(K_CTRL_END) + + otherwise + + endcase + + endif + +return Self + + +METHOD IdleHook() CLASS TMemoEditor + + if ::xUserFunction <> nil + Do(::xUserFunction, ME_IDLE, ::nRow, ::nCol - 1) + + endif + +return Self + + +/*----------------------------------------------------------------------------------------*/ + + FUNCTION MemoEdit(cString,; nTop, nLeft,; nBottom, nRight,; @@ -64,9 +243,12 @@ FUNCTION MemoEdit(cString,; DEFAULT nTextBuffColumn TO 0 DEFAULT nWindowRow TO 0 DEFAULT nWindowColumn TO nTextBuffColumn + DEFAULT cUserFunction TO nil + DEFAULT cString TO "" // Original MemoEdit() converts Tabs into spaces - oEd := TEditor():New(StrTran(cString, Chr(K_TAB), Space(1)), nTop, nLeft, nBottom, nRight, lEditMode, nil, nLineLength, nTabSize) + oEd := TMemoEditor():New(StrTran(cString, Chr(K_TAB), Space(1)), nTop, nLeft, nBottom, nRight, lEditMode, nLineLength, nTabSize) + oEd:MemoInit(cUserFunction) oEd:RefreshWindow() if ! ISLOGICAL(cUserFunction) .OR. cUserFunction == .T. @@ -79,5 +261,5 @@ FUNCTION MemoEdit(cString,; endif endif - RETURN cString +RETURN cString diff --git a/harbour/source/rtl/teditor.prg b/harbour/source/rtl/teditor.prg index e80f4342dd..9a443864f0 100644 --- a/harbour/source/rtl/teditor.prg +++ b/harbour/source/rtl/teditor.prg @@ -74,13 +74,13 @@ CLASS TEditor DATA lSaved INIT .F. // True if user exited editor with K_CTRL_W DATA lWordWrap INIT .F. // True if word wrapping is active DATA nWordWrapCol INIT 0 // At which column word wrapping occurs + DATA lDirty // .T. if there are changes not saved DATA cColorSpec INIT SetColor() // Color string used for screen writes METHOD New(cString, nTop, nLeft, nBottom,; // Converts a string to an array of strings splitting input string at EOL boundaries - nRight, lEditMode, cUdF, nLineLength,; - nTabSize) + nRight, lEditMode, nLineLength, nTabSize) METHOD LoadFile(cFileName) // Load cFileName into active editor METHOD LoadText(cString) // Load cString into active editor @@ -227,7 +227,7 @@ METHOD GetText() CLASS TEditor return cString -METHOD New(cString, nTop, nLeft, nBottom, nRight, lEditMode, cUdF, nLineLength, nTabSize) CLASS TEditor +METHOD New(cString, nTop, nLeft, nBottom, nRight, lEditMode, nLineLength, nTabSize) CLASS TEditor default cString to "" default nTop to 0 @@ -235,7 +235,6 @@ METHOD New(cString, nTop, nLeft, nBottom, nRight, lEditMode, cUdF, nLineLength, default nBottom to MaxRow() default nRight to MaxCol() default lEditMode to .T. - default cUdF to nil default nLineLength to nil default nTabSize to nil @@ -266,6 +265,9 @@ METHOD New(cString, nTop, nLeft, nBottom, nRight, lEditMode, cUdF, nLineLength, ::InsertState(::lInsert) endif + // No need to save + ::lDirty := .F. + // is word wrap required? if nLineLength != NIL ::lWordWrap := .T. @@ -336,6 +338,7 @@ METHOD LoadFile(cFileName) CLASS TEditor ::naTextLen++ endif + ::lDirty := .F. ::MoveCursor(K_CTRL_PGUP) return Self @@ -351,6 +354,7 @@ METHOD LoadText(cString) CLASS TEditor ::naTextLen++ endif + ::lDirty := .F. ::MoveCursor(K_CTRL_PGUP) return Self @@ -363,7 +367,9 @@ METHOD SaveFile() CLASS TEditor if !Empty(::cFile) cString := ::GetText() - return MemoWrit(::cFile, cString) + ::lDirty := !MemoWrit(::cFile, cString) + return !::lDirty + endif return .F. @@ -817,6 +823,7 @@ METHOD Edit(nPassedKey) CLASS TEditor do case case nKey >= K_SPACE .AND. nKey < 256 + ::lDirty := .T. // If I'm past EOL I need to add as much spaces as I need to reach ::nCol if ::nCol > ::LineLen(::nRow) ::aText[::nRow]:cText += Space(::nCol - ::LineLen(::nRow)) @@ -832,6 +839,7 @@ METHOD Edit(nPassedKey) CLASS TEditor ::SplitLine(::nRow) case nKey == K_RETURN + ::lDirty := .T. if ::lInsert .OR. ::nRow == ::naTextLen if ::LineLen(::nRow) > 0 // Split current line at cursor position @@ -851,6 +859,7 @@ METHOD Edit(nPassedKey) CLASS TEditor ::InsertState(!::lInsert) case nKey == K_DEL + ::lDirty := .T. // If I'm on last char of a line and there are more lines, append next line to current one lDelAppend := ::nCol > ::LineLen(::nRow) ::aText[::nRow]:cText := Stuff(::aText[::nRow]:cText, ::nCol, 1, "") @@ -870,6 +879,7 @@ METHOD Edit(nPassedKey) CLASS TEditor // insert char if in insert mode or at end of current line if ::lInsert .OR. (::nCol == ::LineLen(::nRow)) ::aText[::nRow]:cText := Stuff(::aText[::nRow]:cText, ::nCol, 0, Space(::nTabWidth)) + ::lDirty := .T. endif for i := 1 to ::nTabWidth ::MoveCursor(K_RIGHT) @@ -877,6 +887,7 @@ METHOD Edit(nPassedKey) CLASS TEditor ::RefreshLine() case nKey == K_BS + ::lDirty := .T. // delete previous character ::aText[::nRow]:cText := Stuff(::aText[::nRow]:cText, --::nCol, 1, "") // correct column position for next call to MoveCursor() @@ -885,6 +896,7 @@ METHOD Edit(nPassedKey) CLASS TEditor ::RefreshLine() case nKey == K_CTRL_Y + ::lDirty := .T. if ::naTextLen > 1 ::RemoveLine(::nRow) // if we have less lines of text than our current position, up one line