OWLNext    7.0
Borland's Object Windows Library for the modern age
Loading...
Searching...
No Matches
edit.cpp
Go to the documentation of this file.
1//----------------------------------------------------------------------------
2// ObjectWindows
3// Copyright (c) 1991, 1996 by Borland International, All Rights Reserved
4//
5/// \file
6/// Implementation of class TEdit. This defines the basic behavior
7/// of all edit controls.
8//----------------------------------------------------------------------------
9#include <owl/pch.h>
10
11
12#include <owl/edit.h>
13#include <owl/validate.h>
14#include <owl/validate.rh>
15#include <owl/updown.h>
16
17#if !defined(__CYGWIN__)
18//JJH
19# if !defined(WINELIB)
20# include <dos.h>
21# endif // !WINELIB
22#endif
23#include <string.h>
24#include <ctype.h>
25#include <algorithm>
26
27#if defined(__BORLANDC__)
28# pragma option -w-ccc // Disable "Condition is always true/false"
29# pragma option -w-inl // Disable warning "Functions containing 'statement' is not expanded inline".
30#endif
31
32using namespace std;
33
34namespace owl {
35
37
38/// \class TEdit
39///A TEdit is an interface object that represents an edit control interface element.
40///A TEdit object must be used to create an edit control in a parent TWindow. A TEdit
41///can be used to facilitate communication between your application and the edit controls
42///of a TDialog. This class is streamable.
43///
44///There are two styles of edit control objects: single line and multiline. Multiline edit
45///controls allow editing of multiple lines of text.
46///
47///The position of the first character in an edit control is zero. For a multiline edit control,
48///the position numbers continue sequentially from line to line; line breaks count as two characters.
49///
50///Most of TEdit's member functions manage the edit control's text. TEdit also includes some
51///automatic member response functions that respond to selections from the edit control's parent window menu,
52///including cut, copy, and paste. Two important member functions inherited from TEdit's base class
53///(TStatic) are GetText and SetText.
54
55
56//
57/// Class pointer to an edit control that is trying to regain focus after losing
58/// it with invalid contents. Is 0 in all other conditions.
59//
60/// Used to prevent 'oscillation' when a validated window with invalid
61/// input is losing focus to another validated window with invalid input
62/// Without this flag, the two windows will fight for focus
63//
64TEdit* TEdit::ValidatorReFocus = nullptr;
65
66DEFINE_RESPONSE_TABLE1(TEdit, TStatic)
68 EV_COMMAND(CM_EDITCOPY, CmEditCopy),
69 EV_COMMAND(CM_EDITPASTE, CmEditPaste),
70 EV_COMMAND(CM_EDITDELETE, CmEditDelete),
71 EV_COMMAND(CM_EDITCLEAR, CmEditClear),
72 EV_COMMAND(CM_EDITUNDO, CmEditUndo),
73 EV_COMMAND_ENABLE(CM_EDITCUT, CmSelectEnable),
88
89//
90/// Constructs an edit control object with a parent window (parent).
91//
92/// Sets the creation attributes of the edit control and fills its Attr data members with the
93/// specified control ID (Id), position (x, y) relative to the origin of the parent window's client area,
94/// width (w), and height (h).
95/// If text buffer length (textLimit) is 0 or 1, there is no explicit limit to the number of characters
96/// that can be entered. Otherwise textLimit - 1 characters can be entered. By default, initial text (text)
97/// in the edit control is left-justified and the edit control has a border. Multiline edit controls have
98/// horizontal and vertical scroll bars
99
100TEdit::TEdit(TWindow* parent, int id, LPCTSTR text, int x, int y, int w, int h,
101 uint textLen, bool multiline, TModule* module)
102: TStatic(parent, id, text, x, y, w, h, textLen, module), Validator(nullptr), Requirement(roNone)
103{
104 // Undo the styles set by TStatic, & add in edit styles
105 //
107 ModifyExStyle(0, WS_EX_CLIENTEDGE);
108 if (multiline)
110}
111
112//
113/// String-aware overload
114//
115TEdit::TEdit(TWindow* parent, int id, const tstring& text, int x, int y, int w, int h,
116 uint textLen, bool multiline, TModule* module)
117: TStatic(parent, id, text, x, y, w, h, textLen, module), Validator(nullptr), Requirement(roNone)
118{
119 // Undo the styles set by TStatic, & add in edit styles
120 //
123 if (multiline)
125}
126
127//
128/// Constructor for TEdit associated with a MS-Windows interface element created by MS-Windows from a resource definition
129//
130/// Constructs a TEdit object to be associated with an edit control of a TDialog.
131/// Invokes the TStatic constructor with identical parameters. The resourceID
132/// parameter must correspond to an edit resource that you define. Enables the data transfer mechanism
133/// by calling EnableTransfer.
134
136: TStatic(parent, resourceId, textLen, module), Validator(nullptr), Requirement(roNone)
137{
139}
140
141//
142/// Constructs a TEdit object to encapsulate (alias) an existing control.
143//
145: TStatic(hWnd, module), Validator(nullptr), Requirement(roNone)
146{
148}
149
150
151//
152/// Destructor for a TEdit control
153//
155{
156 SetValidator(nullptr);
157}
158
159//
160/// Beeps when edit control runs out of space
161//
162/// Sounds a beep in response to an error notification message that is sent when the
163/// edit control unsuccessfully attempts to allocate more memory.
164//
165void
167{
168 MessageBeep(0);
169
170 DefaultProcessing(); // give parent a chance to process
171}
172
173//
174/// Responds to WM_GETDLGCODE messages that are sent to a dialog box associated with
175/// a control. EvGetDlgCode allows the dialog manager to intercept a message that
176/// would normally go to a control and then ask the control if it wants to process
177/// this message. If not, the dialog manager processes the message. The msg
178/// parameter indicates the kind of message, for example a control, command, or edit
179/// message, sent to the dialog box manager.
180//
181/// If the edit control contains valid input, then TABs are allowed for changing
182/// focus. Otherwise, request that TABs be sent to Self, where we will generate the
183/// Invalid message (See EvKeyDown()).
184//
185/// Tabulator handling is needed, because if EvKillFocus simply disregards validating
186/// upon focus changes to the Ok/Cancel buttons, then tabbing to either of those
187/// controls from an invalid field would bypass validation, an undesired side-effect.
188/// Or simply, if focus is set to the Cancel button because it was pressed, we don't
189/// want validation; if focus was set via tabbing, we do want validation. So tabulator
190/// handling is captured since EvKillFocus won't know the difference.
191//
192uint
194{
195 uint retVal = static_cast<uint>(TStatic::EvGetDlgCode(msg));
196 if (!IsValid(false))
197 {
199 }
200 return retVal;
201}
202
203//
204/// Validates Self whenever a character is entered. Allows
205/// the character entry to be processed normally, then validates
206/// the result and restores Self's text to its original state
207/// if there is an incorrect entry.
208//
209/// By default, the SupressFill parameter of the IsValidInput
210/// method call to the Validator is set to False, so that it
211/// is free to modify the string, if it is so configured.
212//
213void
215{
216 if (Validator && key != VK_BACK) {
217 int oldBuffLen = GetTextLen();
220
221 int startSel, endSel;
224
225 bool preMsgModify = IsModified(); // Save (pre) MODIFY flag
226
227 TStatic::EvChar(key, repeatCount, flags); // Process the new char...
228
229 bool postMsgModify= IsModified(); // Save (post) MODIFY flag
230
232 int buffLen = GetTextLen();
233
234 // We add 1024 as a temporary fix to buffer size due to potential appending
235 // to the buffer and we do not know how many fill bytes might get added.
236 //
237 LPTSTR buff = LockBuffer(std::max(static_cast<int>(TextLimit), std::max(oldBuffLen, buffLen)) + sizeof(tchar) + 1024);
238
239 // Run the result of the edit through the validator. If incorrect,
240 // then restore the original text. Otherwise, range check & position
241 // the selection as needed.
242 //
243 if (!Validator->HasOption(voOnAppend) || (wasAppending && endSel == buffLen)) {
244 if (!Validator->IsValidInput(buff, false)) {
245 ::_tcscpy(buff, oldBuff); // Restore old buffer
246 postMsgModify = preMsgModify; // Restore old modify state too!
247 }
248 else {
249 if (wasAppending)
250 startSel = endSel = static_cast<int>(::_tcslen(buff)); // may have autoFilled--move to end
251 }
252 UnlockBuffer(buff, true);
254 }
255 else {
256 if (endSel == buffLen && !Validator->IsValidInput(buff, false))
257 Validator->Error(this);
259 }
261 }
262 else
263 TStatic::EvChar(key, repeatCount, flags);
264}
265
266//
267/// EvKeyDown translates the virtual key code into a movement. key indicates the
268/// virtual key code of the pressed key, repeatCount holds the number of times the
269/// same key is pressed, flags contains one of the messages that translates to a
270/// virtual key (VK) code for the mode indicators. If the Tab key is sent to the
271/// edit control, EvKeyDown checks the validity before allowing the focus to change.
272/// The control will only get a TAB if
273/// EvGetDlgCode(above) allows it, which is done when the control contains
274/// invalid input (we re-validate here just for completeness, in case
275/// descendants redefine any of this behavior).
276//
277/// We need to validate on TAB focus-changes because there is a case not handled
278/// by EvKillFocus: when focus is lost to an OK or Cancel button by tabbing.
279/// See EvGetDlgCode for more information.
280//
281/// Otherwise, for validators with the OnAppend option, perform an input
282/// validation if the selection moves to the end. i.e. it becomes appending.
283//
284void
285TEdit::EvKeyDown(uint key, uint /*repeatCount*/, uint /*flags*/)
286{
287 if (key == VK_TAB && !IsValid(false))
288 {
290 return;
291 }
292 if (Validator && Validator->HasOption(voOnAppend)) {
293 int startSel, endSel;
295
296 int buffLen = GetTextLen(); // length of buffer
297 bool wasAppending = endSel == buffLen;
298
300
301 if (!wasAppending) {
304 bool err = endSel == static_cast<int>(::_tcslen(buff)) && !Validator->IsValidInput(buff, false);
306 if (err)
307 Validator->Error(this);
308 }
309 }
310 else
312}
313
314//
315/// Validates this whenever the focus is about to be lost.
316//
317/// In response to a WM_KILLFOCUS message sent to a window that is losing the
318/// keyboard, EvKillFocus hides and then destroys the caret. EvKillFocus validates
319/// text whenever the focus is about to be lost and will reclaim the focus if the text
320/// is not valid. It doesn't kill the focus if another application, a Cancel button, or
321/// an OK button (in which case CanClose is called to validate text if pressed) has the
322/// focus. See EvGetDlgCode for more information.
323//
324/// \note Causes focus to be reclaimed via WM_CHILDINVALID. Checks first to make sure
325/// that the focus is not being taken by either (a) another app, or (b) a Cancel
326/// button, or (c) an OK button (in which case CanClose will validate); in each
327/// case, we don't want to validate.
328//
329void
331{
332 // If another validator is attempting to regain focus, then let it
333 //
334 if ((Validator || IsRequired()) && !ValidatorReFocus)
335 {
336 // The window getting focus belongs to this app if any of the window
337 // handles has an OWL object attached that we can get at.
338 //
340 while (hWnd && !GetWindowPtr(hWnd))
342
343 if (hWnd) {
345
346 // Note that we do not allow IsValid to post the message box, since the
347 // change of focus resulting from that message will interfere with the
348 // change we are in the process of completing. Instead, post a message
349 // to the Parent informing it of the validation failure, and providing it
350 // with a handle to us.
351 //
352 if (btnId != IDCANCEL && btnId != IDOK && !IsValid(false)) {
353 ValidatorReFocus = this;
355 }
356 }
357 }
359}
360
361//
362/// Handle the set focus message and make sure the anti-oscillation flag is cleared
363//
364void
366{
367 // If we're getting focus back because of invalid input, then clear the
368 // anti-oscillation flag
369 //
370 if (ValidatorReFocus == this)
371 ValidatorReFocus = nullptr;
372
374}
375
376
377//
378/// Handles up-down messages from an up-down control and adjusts contents if there
379/// is a validator to help.
380// !Y.B think about it, this message send before change not after ??????????????
381bool
383{
384 if (Validator) {
385 int startSel, endSel;
387
389 tstring s = buff;
390 bool changed = Validator->Adjust(s, startSel, endSel, 1) != 0; // !CQ need +- 1
391 if (changed)
392 ::_tcscpy(buff, s.c_str());
395 }
396 return false; // always allow changes for now
397}
398
399//
400/// Handle input validation message sent by parent
401//
402void
407
408//
409/// Handles validation errors that occur as a result of validating the edit control.
410//
411void
413{
414 IsValid(true);
415}
416
417//
418/// Overrides TStatic's virtual member function and clears all text.
419//
420void
422{
423 DeleteSubText(0, -1);
424}
425
426//
427/// Checks to see if all child windows can be closed before closing the current
428/// window. If any child window returns false, CanClose returns false and terminates
429/// the process. If all child windows can be closed, CanClose returns true.
430//
431bool
433{
434 return TStatic::CanClose() && (!IsWindowEnabled() || IsValid(true));
435}
436
437//
438/// This function is called for Cut/Copy/Delete menu items to determine
439/// whether or not the item is enabled.
440//
441void
449
450//
451/// This function is called for the Paste menu item to determine whether or
452/// not the item is enabled.
453//
454void
460
461//
462/// This function is called for the Clear menu item to determine whether or
463/// not the item is enabled.
464//
465void
470
471//
472/// This function is called for the Undo menu item to determine whether or
473/// not the item is enabled.
474//
475void
480
481//
482/// Return the length of line number "lineNumber"
483//
484/// From a multiline edit control, GetLineLength returns the number of characters in
485/// the line specified by lineNumber. If it is -1, the following applies:
486/// - if no text is selected, GetLineLength returns the length of the line
487/// where the caret is positioned;
488/// - if text is selected on the line, GetLineLength returns the line
489/// length minus the number of selected characters;
490/// - if selected text spans more than one line, GetLineLength returns
491/// the length of the lines minus the number of selected characters.
492//
493int
495{
496 return static_cast<int>(CONST_CAST(TEdit*,this)->SendMessage(EM_LINELENGTH,
497 (lineNumber > -1) ? GetLineIndex(lineNumber) : -1));
498}
499
500//
501/// Return the text of line number "lineNumber" (0-terminated)
502///
503/// Retrieves a line of text (whose line number is supplied) from the edit control
504/// and returns it in str (NULL-terminated). strSize indicates how many characters
505/// to retrieve. GetLine returns false if it is unable to retrieve the text or if
506/// the supplied buffer is too small.
507///
508/// \note Requires a buffer of at least 2 bytes, even when the line length is 1
509//
510bool
512{
513 if (strSize <= 0)
514 return false;
515
517 bool success = strSize >= lineLength + 1;
518
519 // The first 16bit word of the buffer is used by EM_GETLINE as the buffer
520 // size. Always need a buffer of at least 2 bytes to pass this word.
521 //
522 if (static_cast<unsigned int>(strSize) < sizeof(int16)) { //JJH added static cast
523 textString[0] = 0;
524 return lineLength == 0; // If lineLen was 0, only then are we successful
525 }
526 (reinterpret_cast<int16 *>(textString))[0] = int16(strSize);
527
528 int bytesCopied = static_cast<int>(CONST_CAST(TEdit*,this)->
530 int n = min(strSize - 1, bytesCopied); // null-terminator index
531 textString[n] = 0; // Windows returns non-0 terminated string
532 if (n != lineLength)
533 return false;
534 return success;
535}
536
537//
538/// For use with CopyText.
539//
540struct TEditGetLine
541{
542 const TEdit& edit;
543 int line;
544 TEditGetLine(const TEdit& c, int line_) : edit(c), line(line_) {}
545
546 int operator()(LPTSTR buf, int buf_size)
547 {
548 bool ok = edit.GetLine(buf, buf_size, line);
549 WARN(!ok, _T("TEdit::GetLine failed, line = ") << line);
550 static_cast<void>(ok); // Suppress not-in-use warning.
551 return buf_size - 1; // line length
552 }
553};
554
555//
556/// String-aware overload
557/// If the length of the returned string differs from GetLineLength an error occured.
558//
561{
562 return CopyText(GetLineLength(lineNumber), TEditGetLine(*this, lineNumber));
563}
564
565//
566/// Lock the edit control's buffer, optionally resizing it first, and return
567/// a pointer to the beginning of it, or 0 if failure.
568/// Must call UnlockBuffer when finished with buffer.
569//
570LPTSTR
572{
573 // Single line edit controls or Win32s will fail the GetMemHandle(),
574 // so do it the hard way and make a copy in this case.
575 // We also copy to avoid a problem when using the new XP common controls.
576 //
577 static const auto v = GetCommCtrlVersion();
578 if (!(GetWindowLong(GWL_STYLE) & ES_MULTILINE) || v >= 0x60000)
579 {
580 if (!newSize)
581 newSize = GetTextLen() + 1;
582 LPTSTR buffer = new tchar[newSize];
584 return buffer;
585 }
586
588 if (newSize)
589 {
591 if (!hBuffer)
592 return nullptr;
593 }
594 return static_cast<LPTSTR>(LocalLock(hBuffer));
595}
596
597//
598/// Unlock the edit control's buffer locked by LockBuffer.
599//
600/// If the contents were changed (buffer is resized or written to), updateHandle should be true.
601/// Ignores call if buffer is 0
602//
603void
605{
606 if (!buffer)
607 return;
608
609 // If a copy was made on lock, copy it back if requested, and then free the buffer.
610 //
611 static const auto v = GetCommCtrlVersion();
612 if (!(GetWindowLong(GWL_STYLE) & ES_MULTILINE) || v >= 0x60000)
613 {
614 if (updateHandle)
616 delete[] const_cast<LPTSTR>(buffer);
617 return;
618 }
619
620 HLOCAL hBuffer = LocalHandle(const_cast<LPTSTR>(buffer));
622
623 // Handle may have moved or buffer contents written.
624 //
625 if (updateHandle)
627}
628
629//
630/// Similar to strstr(), but is case sensitive or insensitive, uses Windows
631/// string functions to work with different language drivers
632//
633static LPCTSTR
634strstrcd(LPCTSTR str1, LPCTSTR str2, bool caseSens)
635{
637 int len2 = static_cast<int>(::_tcslen(str2));
638 LPTSTR p = const_cast<LPTSTR>(str1);
639 LPCTSTR endp = str1 + ::_tcslen(str1) - len2 + 1;
640
641 if (caseSens)
642 while (p < endp) {
643 tchar c = p[len2]; // must term p to match str2 len
644 p[len2] = 0; // for _tcscmp to work.
645 if (_tcscmp(p, str2) == 0) {
646 p[len2] = c;
647 return p;
648 }
649 p[len2] = c;
650#if defined(BI_DBCS_SUPPORT) && !defined(UNICODE)
651 LPTSTR p2 = ::AnsiNext(p);
652 if (p2 <= p)
653 break;
654 p = p2;
655#else
656 p++;
657#endif
658 }
659 else
660 while (p < endp) {
661 tchar c = p[len2];
662 p[len2] = 0;
663 if (_tcsicmp(p, str2) == 0) {
664 p[len2] = c;
665 return p;
666 }
667 p[len2] = c;
668#if defined(BI_DBCS_SUPPORT) && !defined(UNICODE)
669 LPTSTR p2 = ::AnsiNext(p);
670 if (p2 <= p)
671 break;
672 p = p2;
673#else
674 p++;
675#endif
676 }
677 return nullptr;
678}
679
680//
681/// Similar to strstrcd(), but searches backwards. Needs the length of str1
682/// to know where to start.
683//
684static LPCTSTR
685strrstrcd(LPCTSTR str1, uint len1, LPCTSTR str2,
686 bool caseSens)
687{
689 int len2 = static_cast<int>(::_tcslen(str2));
690 LPTSTR p = const_cast<LPTSTR>(str1 + len1 - len2);
691
692#if defined(BI_DBCS_SUPPORT) && !defined(UNICODE)
693 if (p >= str1)
694 p = ::AnsiPrev(str1, p+1);
695#endif
696 if (caseSens)
697 while (p >= str1) {
698 tchar c = p[len2]; // must term p to match str2 len
699 p[len2] = 0; // for _tcscmp to work.
700 if (_tcscmp(p, str2) == 0) {
701 p[len2] = c;
702 return p;
703 }
704 p[len2] = c;
705#if defined(BI_DBCS_SUPPORT) && !defined(UNICODE)
706 LPTSTR p2 = ::AnsiPrev(str1, p);
707 if (p2 >= p)
708 break;
709 p = p2;
710#else
711 p--;
712#endif
713 }
714 else
715 while (p >= str1) {
716 tchar c = p[len2];
717 p[len2] = 0;
718 if (_tcsicmp(p, str2) == 0) {
719 p[len2] = c;
720 return p;
721 }
722 p[len2] = c;
723#if defined(BI_DBCS_SUPPORT) && !defined(UNICODE)
724 LPTSTR p2 = ::AnsiPrev(str1, p);
725 if (p2 >= p)
726 break;
727 p = p2;
728#else
729 p--;
730#endif
731 }
732 return nullptr;
733}
734
735//
736/// searches for and selects the given text and returns the offset of the text or -1 if the text is not found
737//
738/// Performs either a case-sensitive or case-insensitive search for the supplied
739/// text. If the text is found, the matching text is selected, and Search returns
740/// the position of the beginning of the matched text. If the text is not found in
741/// the edit control's text, Search returns -1. If -1 is passed as startPos, then
742/// the search starts from either the end or the beginning of the currently selected
743/// text, depending on the search direction.
744//
745int
747 bool wholeWord, bool up)
748{
749 if (!text || !text[0])
750 return -1;
751
752 if (startPos == -1) {
753 int sBeg, sEnd;
755 startPos = up ? sBeg : sEnd;
756 }
757 int textLen = static_cast<int>(::_tcslen(text));
758
759 // Lock the text buffer to get the pointer, and search thru it for the text
760 //
762 LPCTSTR pos;
763 for (;;) {
764 if (up)
765 pos = strrstrcd(buffer, startPos, text, caseSensitive);
766 else
767 pos = strstrcd(buffer+startPos, text, caseSensitive);
768
769 // If whole-word matching is enabled and we have a match so far, then make
770 // sure the match is on word boundaries.
771 //
772 if (wholeWord && pos) {
773#if defined(BI_DBCS_SUPPORT)
775 if (pos > buffer)
777
778 if ((pos > buffer && _istalnum(*prevPos)) || // Match is in preceding word
779 (textLen < static_cast<int>(::_tcslen(pos)) && _istalnum(pos[textLen])))
780 {
781 if (up)
782 startPos = static_cast<int>(prevPos - buffer + ::_tcslen(text));
783 else
784 startPos = static_cast<int>(::AnsiNext(pos) - buffer);
785 continue; // Skip this match and keep searching
786 }
787#else
788 if ((pos > buffer && _istalnum(pos[-1])) || // Match is in preceding word
790 {
791 startPos = static_cast<uint>(pos-buffer) + !up;
792 continue; // Skip this match and keep searching
793 }
794#endif
795 }
796 break; // Out of for loop
797 }
798
799 // If we've got a match, select that text, cleanup & return.
800 //
801 if (pos) {
802 int sBeg = static_cast<int>(pos - buffer);
807
808 return sBeg;
809 }
811 return -1;
812}
813
814
815//
816/// Deletes the currently selected text, and returns false if no text is selected.
817//
818bool
820{
821 int startPos, endPos;
822
824
825 if (startPos != endPos) {
827 return true;
828 }
829 return false;
830}
831
832//
833/// Deletes the text between the starting and ending positions
834/// specified by startPos and endPos, respectively.
835/// DeleteSubText returns true if successful.
836//
837bool
839{
841 return DeleteSelection();
842
843 else
844 return false;
845}
846
847//
848/// Deletes the text in the line specified by lineNumber in a multiline edit control.
849/// If -1 passed, deletes the current line. DeleteLine does not delete the line break
850/// and affects no other lines. Returns true if successful. Returns false if lineNumber
851/// is not -1 and is out of range or if an error occurs.
852//
853bool
855{
856 if (lineNumber == -1)
858
860
861 if (firstPos != -1) {
863
864 if (lastPos == -1)
866
867 if (firstPos == 0 && firstPos == lastPos) {
868 SetText(_T(""));
869 return true;
870 }
871 else {
873 }
874 }
875
876 return false;
877}
878
879//
880/// Retrieve the text of the associated edit control between the given positions.
881/// Note that the buffer must be large enough to hold the text, otherwise buffer
882/// overrun will occur. The destination is always null-terminated.
883///
884/// NB! This function is deprecated. Use GetTextRange instead.
885//
886void
888{
889 WARN(true, _T("TEdit::GetSubText is deprecated. Use GetTextRange instead."));
890 if (!textBuf) return;
892 _tcscpy(textBuf, t.c_str());
893}
894
895//
896/// Retrieves a specified range of text from the edit control.
897/// The range is half-open; i.e. range [0,2) for "abc" returns "ab".
898/// An empty string is returned if either
899///
900/// - the control is empty (no text), or
901/// - the range is invalid (empty or inverted), or
902/// - whole range is beyond the extents of the actual text.
903///
904/// If the end of the range is beyond the valid range then it is limited to the valid range.
905/// A special case is the range [0, -1). It will return the full text.
906///
907/// \todo Must be tested
908//
911{
912 const int begin = r.cpMin;
913 int end = r.cpMax; // May be adjusted.
914
915 // Check input arguments against EM_GETTEXTRANGE requirements.
916 // Note that [0, -1) for an empty control is not valid for EM_GETTEXTRANGE,
917 // but we'll ignore that, since no buffer issues are involved here.
918 // Otherwise we reject negative positions, as well as empty and inverted ranges.
919 // EM_GETTEXTRANGE would not null-terminate the result in these cases,
920 // so to adhere to the same policy we warn about these cases.
921
922 if (begin == 0 && end == -1)
923 {
924 return GetText();
925 }
926
927 tstring s;
928 if (begin < 0 || end < 0)
929 {
930 WARN(true, _T("Arguments out of range"));
931 return s;
932 }
933 else if (begin == end)
934 {
935 WARN(true, _T("Empty range"));
936 return s;
937 }
938 else if (begin > end)
939 {
940 WARN(true, _T("Inverted range"));
941 return s;
942 }
943
944 // Return empty if the entire range is outside the extents of the actual text.
945 // This is valid for EM_GETTEXTRANGE so we wont complain.
946
947 int n = GetTextLen();
948 if (begin >= n)
949 return s;
950
951 // Limit end to the actual text size.
952
953 end = std::min(end, n);
954
955 // Calculate line indexes and char indexes (within lines).
956 // Then append line by line to the result string, cropping
957 // the start and end line specially.
958
959 const int startLine = GetLineFromPos(begin);
960 const int startChar = begin - GetLineIndex(startLine);
961 const int endLine = GetLineFromPos(end);
962 const int endChar = end - GetLineIndex(endLine);
963 for (int i = startLine; i <= endLine; ++i)
964 {
965 tstring line = GetLine(i) + _T("\r\n"); // CRLF-terminated
966 int b = (i == startLine) ? startChar : 0;
967 int e = (i == endLine) ? endChar : static_cast<int>(line.length());
968 CHECK(b <= e); // sanity check
969 s.append(line, b, e - b);
970 }
971 return s;
972}
973
974
975//
976/// Functional style overload
977//
980{
981 TRange r;
982 GetSelection(r.cpMin, r.cpMax);
983 return r;
984}
985
986
987//
988/// Return name of predefined Windows edit class
989//
991{
992 return TWindowClassName{_T("EDIT")};
993}
994
995//
996/// \note If the textLimit data member is nonzero, SetupWindow limits the number of
997/// characters that can be entered into the edit control to textLimit -1.
998//
999void
1001{
1003
1004 if (TextLimit != 0)
1005 LimitText(TextLimit - 1);
1006 else
1007 LimitText(0); // This will remove the 32K limit under WinNT and later
1008}
1009
1010//
1011/// Always returns true if the TEdit object does not have an associated TValidator
1012/// object (i.e. if TEdit.Validator == 0) and it is not required.
1013/// If the edit control is required, requirement is validated.
1014/// If the edit control has a validator, and the reportError parameter is set to true,
1015/// then IsValid calls the validator's Valid method. If the reportError parameter is
1016/// false, IsValid calls the validator's IsValid method.
1017//
1018bool
1020{
1021 bool valid = true;
1022
1023 // Perform validation if needed.
1024 //
1025 if (Validator || IsRequired())
1026 {
1027
1028 // Make re-focus anti-oscillation flag exception-safe.
1029 //
1030 struct TRefocusGuard
1031 {
1032 bool Dismissed;
1033 ~TRefocusGuard() { if (!Dismissed) ValidatorReFocus = nullptr; }
1034 }
1035 reFocusGuard = {false};
1036
1037 // Set if re-focusing might be needed after error message is displayed.
1038 //
1039 bool reFocus = GetFocus() != *this;
1040 if (reportError) ValidatorReFocus = this;
1041
1042 // Lock the buffer to perform validation.
1043 //
1045
1046 // If requirement option set, check if requirement met.
1047 //
1048 if (IsRequired())
1049 {
1050 valid = *buffer;
1051 if (valid && (GetRequired() == roNonBlank))
1052 valid = _tcsspn(buffer, _T(" \t\n\v\f\r\xA0")) != _tcslen(buffer);
1053 if (!valid && reportError)
1055 }
1056
1057 // If still valid and validator present, have it validate.
1058 //
1059 if (valid && Validator)
1060 valid = reportError ? Validator->Valid(buffer, this) : Validator->IsValid(buffer);
1061
1062 // Unlock the buffer
1063 //
1065
1066 // Give us focus if needed or reset anti-oscillation.
1067 //
1068 if (reportError && !valid && reFocus)
1069 {
1070 SetFocus();
1071 reFocusGuard.Dismissed = true;
1072 }
1073 }
1074 return valid;
1075}
1076
1077//
1078/// Sets a new validator for this control, can be 0. Cleans up the old validator
1079//
1080void
1082{
1083 delete (TStreamableBase*)Validator; // upcast to avoid explicit call to dtor
1084 Validator = validator;
1085}
1086
1087//
1088/// Transfers state information for TEdit controls
1089//
1090/// Transfers information for TEdit controls and sends information to the Validator
1091/// if one exists, and if it has the transfer option set. Transfer can perform type
1092/// conversion when validators are in place, for example, when TRangeValidator
1093/// transfers integers. The return value is the size (in bytes) of the transfer
1094/// data.
1095//
1096/// Delegates to the Validator if there is one & it has the transfer option set,
1097/// allowing the Validator to convert the text to/from the appropriate type.
1098/// Else passes to base, TStatic.
1099//
1100/// The return value is the size (in bytes) of the transfer data
1101//
1102uint
1104{
1105 if (Validator && Validator->HasOption(voTransfer) && GetNumLines() <= 1)
1106 {
1107 CHECK(static_cast<uint>(GetWindowTextLength()) < TextLimit);
1108
1109 // Allocate a buffer for the validator.
1110 // Use a "big enough" size; there's no protocol for the buffer size, unfortunately.
1111 //
1112 const size_t bigEnough = max<size_t>(1024, TextLimit + 1);
1114 GetText(&text[0], static_cast<int>(text.size()));
1115
1116 uint result = Validator->Transfer(&text[0], buffer, direction);
1117 if (result == 0)
1119 else if (direction == tdSetData)
1120 SetText(&text[0]);
1121 return result;
1122 }
1124}
1125
1126
1128
1129#if OWL_PERSISTENT_STREAMS
1130
1131//
1132/// Reads an instance of TEdit from the given ipstream.
1133//
1134void*
1135TEdit::Streamer::Read(ipstream& is, uint32 version) const
1136{
1137 auto t = GetObject(); // Get "this" instance.
1138 CHECK(t);
1140 is >> t->Validator;
1141 if (version < 2)
1142 t->Requirement = TEdit::roNone;
1143 else
1144 {
1145 auto r = static_cast<int>(TEdit::roNone);
1146 is >> r;
1147 t->Requirement = static_cast<TEdit::TRequireOption>(r);
1148 }
1149 return t;
1150}
1151
1152//
1153/// Writes the TEdit to the given opstream.
1154//
1155void
1156TEdit::Streamer::Write(opstream& os) const
1157{
1158 auto t = GetObject(); // Get "this" instance.
1159 CHECK(t);
1161 os << t->Validator;
1162 os << static_cast<int>(t->Requirement);
1163}
1164
1165#endif
1166
1167} // OWL namespace
#define CHECK(condition)
Definition checks.h:239
#define WARN(condition, message)
Definition checks.h:273
#define PRECONDITION(condition)
Definition checks.h:227
The clipboard class encapsulates the methods for the clipboard object of Windows.
Definition clipboar.h:32
bool IsClipboardFormatAvailable(uint format) const
Indicates if the format specified in format exists for use in the Clipboard.
Definition clipboar.h:247
Base class for an extensible interface for auto enabling/disabling of commands (menu items,...
Definition window.h:209
A TEdit is an interface object that represents an edit control interface element.
Definition edit.h:34
ObjectWindows dynamic-link libraries (DLLs) construct an instance of TModule, which acts as an object...
Definition module.h:75
TNmUpDown is a wrapper of the NM_UPDOWN structure sent with notifications from an 'UpDown' control.
Definition commctrl.h:107
An interface object that represents a static text interface element.
Definition static.h:36
tstring GetText() const
String-aware overload.
Definition static.h:219
int GetTextLen() const
Return the current length of the text in the control, excluding the terminating null character.
Definition static.h:202
void SetText(LPCTSTR str)
Sets the static control's text to the string supplied in str.
Definition static.h:226
auto Transfer(void *buffer, TTransferDirection) -> uint override
TWindow override Transfers TextLimit characters of text to or from a transfer buffer pointed to by bu...
Definition static.cpp:122
Classes that inherit from TStreamableBase are known as streamable classes (their objects can be writt...
Definition objstrm.h:108
A streamable class, TValidator defines an abstract data validation object.
Definition validate.h:71
virtual uint Transfer(TCHAR *text, void *buffer, TTransferDirection direction)
Allows a validator to set and read the values of its associated edit control.
Definition validate.cpp:115
bool Valid(LPCTSTR str, TWindow *owner=0)
Returns true if IsValid returns true.
Definition validate.h:344
bool HasOption(int option)
Gets the Options bits. Returns true if a specified option is set.
Definition validate.h:356
virtual bool IsValidInput(TCHAR *input, bool suppressFill)
Checks current input against validator.
Definition validate.cpp:69
virtual void Error(TWindow *owner)
Error is an abstract function called by Valid when it detects that the user has entered invalid infor...
Definition validate.cpp:42
virtual bool IsValid(LPCTSTR input)
Checks input against validator for completeness. Never modifies input.
Definition validate.cpp:87
virtual int Adjust(tstring &text, int &begPos, int &endPos, int amount)
Adjusts the 'value' of the text, given a cursor position and an amount.
Definition validate.cpp:125
Type-safe encapsulation of a Windows class name, a union between ATOM and LPCTSTR.
Definition module.h:47
TWindow, derived from TEventHandler and TStreamableBase, provides window-specific behavior and encaps...
Definition window.h:414
HWND SetFocus()
Sets the keyboard focus to current window and activates the window that receives the focus by sending...
Definition window.h:2151
tstring LoadString(uint id) const
Definition window.h:608
TWindow * GetParent() const
Retrieves the OWL object of the parent window. If none exists, returns 0.
Definition window.h:2013
bool IsWindowEnabled() const
Returns true if the window is enabled.
Definition window.h:2161
long GetWindowLong(int index) const
Retrieves information about the window depending on the value stored in index.
Definition window.h:2388
TWindow * GetParentO() const
Return the OWL's parent for this window.
Definition window.h:2006
uint EvGetDlgCode(const MSG *msg)
The default message handler for WM_GETDLGCODE.
Definition window.h:3698
void EnableTransfer()
Enables the transfer mechanism, which allows state data to be transferred between the window and a tr...
Definition window.h:1828
void EvKillFocus(HWND hWndGetFocus)
Handle WM_KILLFOCUS so that we can have a parent window hold onto our Handle and possibly restore foc...
Definition window.cpp:1611
bool ModifyStyle(uint32 offBits, uint32 onBits, uint swpFlags=0)
Modifies the style bits of the window.
Definition window.cpp:3591
TResult DefaultProcessing()
Handles default processing of events, which includes continued processing of menu/accelerators comman...
Definition window.cpp:852
int GetDlgCtrlID() const
Returns the ID of the control.
Definition window.h:3097
virtual bool CanClose()
Use this function to determine if it is okay to close a window.
Definition window.cpp:2795
void EvSetFocus(HWND hWndLostFocus)
The default message handler for WM_SETFOCUS.
Definition window.h:4084
bool PostMessage(TMsgId, TParam1=0, TParam2=0)
Posts a message (msg) to the window in the application's message queue.
Definition window.h:2103
int MessageBox(LPCTSTR text, LPCTSTR caption=0, uint flags=MB_OK) const
Creates and displays a message box that contains a message (text), a title (caption),...
Definition window.cpp:4284
TResult SendMessage(TMsgId, TParam1=0, TParam2=0) const
Sends a message (msg) to a specified window or windows.
Definition window.cpp:3288
virtual void SetupWindow()
Performs setup following creation of an associated MS-Windows window.
Definition window.cpp:2575
void EvChar(uint key, uint repeatCount, uint flags)
The default message handler for WM_CHAR.
Definition window.h:3615
bool ModifyExStyle(uint32 offBits, uint32 onBits, uint swpFlags=0)
Modifies the style bits of the window.
Definition window.cpp:3599
static HWND GetFocus()
Gets a handle to the window that has the focus.
Definition window.h:2139
HWND THandle
TWindow encapsulates an HWND.
Definition window.h:418
HWND GetHandle() const
Returns the handle of the window.
Definition window.h:2020
int GetWindowTextLength() const
Returns the length, in characters, of the specified window's title.
Definition window.h:2641
ipstream, a specialized input stream derivative of pstream, is the base class for reading (extracting...
Definition objstrm.h:391
#define EV_UDN_DELTAPOS(id, method)
bool method(TNmUpDown&)
Definition commctrl.h:1374
#define _tcscmp
Definition cygwin.h:75
#define _tcscpy
Definition cygwin.h:79
#define AnsiPrev
Definition cygwin.h:62
#define AnsiNext
Definition cygwin.h:61
#define _tcslen
Definition cygwin.h:74
#define _tcsicmp
Definition cygwin.h:76
#define _T(x)
Definition cygwin.h:51
#define _tcsspn
Definition cygwin.h:81
#define _istalnum
Definition cygwin.h:72
#define WM_CHILDINVALID
Definition dispatch.h:4104
Definition of class TEdit.
#define DEFINE_RESPONSE_TABLE1(cls, base)
Macro to define a response table for a class with one base.
Definition eventhan.h:492
#define IMPLEMENT_STREAMABLE1(cls, base1)
Definition objstrm.h:1725
TRequireOption GetRequired() const
Returns the requirement option for the edit control.
Definition edit.h:763
void SetValidator(TValidator *validator)
Sets a new validator for this control, can be 0. Cleans up the old validator.
Definition edit.cpp:1081
bool DeleteSubText(int startPos, int endPos)
Deletes the text between the starting and ending positions specified by startPos and endPos,...
Definition edit.cpp:838
auto CanClose() -> bool override
Checks to see if all child windows can be closed before closing the current window.
Definition edit.cpp:432
void CmPasteEnable(TCommandEnabler &commandHandler)
This function is called for the Paste menu item to determine whether or not the item is enabled.
Definition edit.cpp:455
bool DeleteSelection()
Deletes the currently selected text, and returns false if no text is selected.
Definition edit.cpp:819
TRequireOption
Definition edit.h:161
void EvChildInvalid(HWND)
Handler for input validation message sent by parent.
Definition edit.cpp:403
void EvSetFocus(HWND hWndLostFocus)
Handle the set focus message and make sure the anti-oscillation flag is cleared.
Definition edit.cpp:365
void SetMemHandle(HLOCAL localMem)
Sets the memory handle for the edit control's buffer.
Definition edit.h:629
bool EvUpDown(TNmUpDown &)
Handles up-down messages from an up-down control and adjusts contents if there is a validator to help...
Definition edit.cpp:382
void ValidatorError()
Handles validation errors that occur as a result of validating the edit control.
Definition edit.cpp:412
virtual void LimitText(int)
Limit the amount of new text that can be entered in the edit control.
Definition edit.h:611
bool DeleteLine(int lineNumber)
Deletes the text in the line specified by lineNumber in a multiline edit control.
Definition edit.cpp:854
void EvChar(uint key, uint repeatCount, uint flags)
Validates Self whenever a character is entered.
Definition edit.cpp:214
void EvKillFocus(HWND hWndGetFocus)
Validates this whenever the focus is about to be lost.
Definition edit.cpp:330
virtual tstring GetTextRange(const TRange &) const
Retrieves a specified range of text from the edit control.
Definition edit.cpp:910
HLOCAL GetMemHandle() const
Return the memory handle for the edit control's buffer.
Definition edit.h:620
void SetupWindow() override
Definition edit.cpp:1000
void ENErrSpace()
EN_ERRSPACE.
Definition edit.cpp:166
auto GetWindowClassName() -> TWindowClassName override
Return name of predefined Windows edit class.
Definition edit.cpp:990
bool IsValid(bool reportErr=false)
Always returns true if the TEdit object does not have an associated TValidator object (i....
Definition edit.cpp:1019
void CmModEnable(TCommandEnabler &commandHandler)
This function is called for the Undo menu item to determine whether or not the item is enabled.
Definition edit.cpp:476
void EvKeyDown(uint key, uint repeatCount, uint flags)
EvKeyDown translates the virtual key code into a movement.
Definition edit.cpp:285
void UnlockBuffer(LPCTSTR buffer, bool updateHandle=false)
Unlock the edit control's buffer locked by LockBuffer.
Definition edit.cpp:604
virtual int GetLineFromPos(int charPos) const
Return the line number associated with character index "CharPos".
Definition edit.h:472
bool IsRequired() const
Returns true if a value is required for the edit control.
Definition edit.h:771
int GetLineLength(int lineNumber) const
Return the length of line number "lineNumber".
Definition edit.cpp:494
auto Transfer(void *buffer, TTransferDirection) -> uint override
Transfers state information for TEdit controls.
Definition edit.cpp:1103
uint EvGetDlgCode(const MSG *)
Responds to WM_GETDLGCODE messages that are sent to a dialog box associated with a control.
Definition edit.cpp:193
virtual void GetSubText(TCHAR *textBuf, int startPos, int endPos) const
Deprecated. Use GetTextRange instead.
Definition edit.cpp:887
void CmSelectEnable(TCommandEnabler &commandHandler)
This function is called for Cut/Copy/Delete menu items to determine whether or not the item is enable...
Definition edit.cpp:442
bool IsModified() const
Returns true if the user has changed the text in the edit control.
Definition edit.h:418
TCHAR * LockBuffer(uint newSize=0)
Lock and unlock this edit control's buffer.
Definition edit.cpp:571
~TEdit() override
Destructor for a TEdit control.
Definition edit.cpp:154
int GetNumLines() const
Return the number of lines in the associated edit control.
Definition edit.h:409
void Clear() override
Override TStatic virtual member functions.
Definition edit.cpp:421
void CmCharsEnable(TCommandEnabler &commandHandler)
This function is called for the Clear menu item to determine whether or not the item is enabled.
Definition edit.cpp:466
virtual int Search(int startPos, LPCTSTR text, bool caseSensitive=false, bool wholeWord=false, bool up=false)
searches for and selects the given text and returns the offset of the text or -1 if the text is not f...
Definition edit.cpp:746
int GetLineIndex(int lineNumber) const
In a multiline edit control, GetLineIndex returns the number of characters that appear before the lin...
Definition edit.h:483
virtual bool SetSelection(int startPos, int endPos)
Select the characters in the range "startPos .. endPos".
Definition edit.h:430
TRange GetSelection() const
Functional style overload.
Definition edit.cpp:979
TEdit(TWindow *parent, int id, LPCTSTR text, int x, int y, int w, int h, uint textLimit=0, bool multiline=false, TModule *=nullptr)
Constructs an edit control object with a parent window (parent).
Definition edit.cpp:100
bool GetLine(TCHAR *str, int strSize, int lineNumber) const
Return the text of line number "lineNumber" (0-terminated)
Definition edit.cpp:511
@ roNonBlank
Definition edit.h:161
@ roNone
Definition edit.h:161
@ voTransfer
Option to perform conversion & transfer.
Definition validate.h:39
@ voOnAppend
Option to only validate input on appending.
Definition validate.h:43
TTransferDirection
The TTransferDirection enum describes the constants that the transfer function uses to determine how ...
Definition window.h:92
@ tdSetData
Set data from the buffer into the window.
Definition window.h:94
Object Windows Library (OWLNext Core)
Definition animctrl.h:22
EV_WM_CHILDINVALID
Definition edit.cpp:86
EV_WM_CHAR
Definition checklst.cpp:196
EV_WM_KILLFOCUS
Definition edit.cpp:85
EV_WM_KEYDOWN
Definition edit.cpp:82
TWindow * GetWindowPtr(HWND, const TApplication *)
Raw function to retrieve a TWindow pointer given an HWND from the a given app, or any app (app==0).
Definition window.cpp:1557
char tchar
Definition defs.h:77
LPARAM TParam2
Second parameter type.
Definition dispatch.h:55
tstring CopyText(int size, TGetText get_text)
Copies text from a C-string (null-terminated character array) into a string object,...
Definition defs.h:317
auto GetCommCtrlVersion() -> DWORD
Returns the version number of the Common Control library (ComCtl32.dll).
Definition commctrl.cpp:26
signed short int16
Definition number.h:29
WPARAM TParam1
First parameter type.
Definition dispatch.h:54
OWL_DIAGINFO
Definition animctrl.cpp:14
EV_WM_SETFOCUS
Definition edit.cpp:84
END_RESPONSE_TABLE
Definition button.cpp:26
std::string tstring
Definition defs.h:79
EV_WM_GETDLGCODE
Definition button.cpp:24
unsigned int uint
Definition number.h:25
#define CONST_CAST(targetType, object)
Definition defs.h:273
Definition of class TString, a flexible universal string envelope class.
Represents a half-open range of positions in the edit control, e.g.
Definition edit.h:49
Definition of class TUpDown.
#define EV_COMMAND_ENABLE(id, method)
Response table entry for enabling a command.
Definition windowev.h:193
#define EV_NOTIFY_AT_CHILD(notifyCode, method)
Response table entry for a child ID notification handled at the child.
Definition windowev.h:162
#define EV_COMMAND(id, method)
Response table entry for a menu/accelerator/push button message.
Definition windowev.h:171
#define WS_EX_CLIENTEDGE
Definition wsysinc.h:33