OWLNext    7.0
Borland's Object Windows Library for the modern age
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
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