2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these libraries and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
26 * $TOG: XmTextEditor.C /main/13 1998/02/03 10:29:51 mgreess $
28 * RESTRICTED CONFIDENTIAL INFORMATION:
30 * The information in this document is subject to special
31 * restrictions in a confidential disclosure agreement between
32 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
33 * document outside HP, IBM, Sun, USL, SCO, or Univel without
34 * Sun's specific written approval. This document and all copies
35 * and derivative works thereof must be returned or destroyed at
38 * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
43 #include <EUSCompat.h>
48 #if defined(NEED_MMAP_WRAPPER)
52 #include <sys/types.h>
55 #if defined(NEED_MMAP_WRAPPER)
66 #include "XmTextEditor.h"
70 XmTextEditor::XmTextEditor(
72 DtMailEditor *owner_of_editor
76 my_owner = owner_of_editor;
82 _modified_text = NULL;
83 _modified_text_buflen = 0;
84 begin_ins_bracket = NULL;
86 end_ins_bracket = NULL;
87 _auto_show_cursor = FALSE;
88 text_already_selected = FALSE;
91 XmTextEditor::~XmTextEditor()
99 if(_modified_text->ptr) {
100 free(_modified_text->ptr);
101 _modified_text->ptr = NULL;
103 free(_modified_text);
104 _modified_text = NULL;
106 if (NULL != indent_str)
107 free((void*) indent_str);
111 XmTextEditor::initialize()
119 DtMail::Session * d_session = theRoamApp.session()->session();
120 DtMail::MailRc * mailrc = d_session->mailRc(error);
123 mailrc->getValue(error, "popuplines", &value);
125 value = strdup("24");
127 rows = (short) strtol(value, NULL, 10);
131 // If toolcols is set, overwrite the column width with "toolcols" value.
132 // Otherwise, default resource value will be used.
134 mailrc->getValue(error, "toolcols", &value);
136 cols = (short) strtol(value, NULL, 10);
137 XtSetArg(args[n], XmNcolumns, cols); n++;
143 * MB_CUR_MAX == 1 : SingleByteLanguage
144 * MB_CUR_MAX > 1 : MultiByteLanguage
146 if ( MB_CUR_MAX == 1 )
153 XtSetArg(args[n], XmNeditable, FALSE); n++;
154 XtSetArg(args[n], XmNrows, 24); n++;
155 if ( MB_CUR_MAX == 1 ) {
156 XtSetArg(args[n], XmNcolumns, 80); n++;
158 XtSetArg(args[n], XmNcolumns, 40); n++;
161 _w = XmCreateScrolledText(my_parent, "Text", args, n );
163 update_display_from_props();
165 XtAddEventHandler(XtParent(_w), ButtonPressMask,
166 FALSE, MenuButtonHandler,
171 XmTextEditor::set_contents(
172 const char *contents,
173 const unsigned long len
176 if (contents[len - 1] == 0) {
177 XmTextSetString(_w, (char *)contents);
180 this->my_owner->needBuf(&_buffer, &_buf_len, len + 1);
181 this->my_owner->stripCRLF(&_buffer, contents, len);
182 XmTextSetString(_w, _buffer);
187 XmTextEditor::set_contents(const char * path)
193 XmTextEditor::get_contents()
195 return(XmTextGetString(_w));
199 XmTextEditor::append_to_contents(
200 const char *contents,
201 const unsigned long len
205 if (contents[len - 1] == 0) {
206 XmTextInsert( _w, XmTextGetLastPosition( _w ),
210 // Not null terminated, and most likely has crlf instead of lf.
212 this->my_owner->needBuf(&_buffer, &_buf_len, len + 1);
213 this->my_owner->stripCRLF(&_buffer, contents, len);
214 XmTextInsert(_w, XmTextGetLastPosition(_w), _buffer);
219 XmTextEditor::append_to_contents(const char * path)
221 loadFile(path, (const int) XmTextGetLastPosition(_w));
225 XmTextEditor::append_at_cursor(
226 const char *contents,
227 const unsigned long len
230 if (contents[len - 1] == 0) {
233 XmTextGetInsertionPosition(_w),
238 // Not null terminated, and most likely has crlf instead of lf.
240 this->my_owner->needBuf(&_buffer, &_buf_len, len + 1);
241 this->my_owner->stripCRLF(&_buffer, contents, len);
244 XmTextGetInsertionPosition(_w),
250 XmTextEditor::append_at_cursor(const char * path)
252 loadFile(path, (const int)XmTextGetInsertionPosition(_w));
256 XmTextEditor::clear_contents()
259 XmTextSetString(_w, "");
264 XmTextEditor::get_text_widget()
270 XmTextEditor::get_text_foreground()
282 XmTextEditor::get_text_background()
293 XmTextEditor::get_text_fontList()
304 XmTextEditor::get_text_width()
315 XmTextEditor::get_editor()
321 XmTextEditor::set_editable(
325 XmTextSetEditable( _w, bval);
327 // If not editable, turn off the cursor?
328 XtVaSetValues(_w, XmNcursorPositionVisible, bval, NULL);
333 XmTextEditor::get_columns()
336 XtVaGetValues(_w, XmNcolumns, &ncolumns, NULL);
342 XmTextEditor::get_rows()
345 XtVaGetValues(_w, XmNrows, &nrows, NULL);
350 XmTextEditor::set_columns(int ncolumns)
352 XtVaSetValues(_w, XmNcolumns, ncolumns, NULL);
357 XmTextEditor::set_rows(int nrows)
359 XtVaSetValues(_w, XmNrows, nrows, NULL);
364 // TOGO XmTextEditor::set_container(
368 // TOGO // Extract text and display?
372 // TOGO XmTextEditor::get_container()
374 // TOGO return(NULL);
378 XmTextEditor::auto_show_cursor_off()
380 // Get the original value of XmNautoShowCursorPosition
382 XmNautoShowCursorPosition, &_auto_show_cursor,
385 // Set it to false so we don't scroll with the cursor.
387 XmNautoShowCursorPosition, FALSE,
392 XmTextEditor::auto_show_cursor_restore()
394 // Restore the original value of XmNautoShowCursorPosition.
396 XmNautoShowCursorPosition, _auto_show_cursor,
401 XmTextEditor::set_to_top()
404 XmTextShowPosition(_w, 0);
405 XmTextSetInsertionPosition(_w, 0);
410 XmTextEditor::set_to_bottom()
412 XmTextSetInsertionPosition( _w, XmTextGetLastPosition(_w) );
417 XmTextEditor::focus_callback(
424 XmTextEditor *obj=(XmTextEditor *) clientData;
426 obj->obtained_focus();
429 #endif /* DEAD_WOOD */
432 XmTextEditor::obtained_focus()
434 // If there is text already selected, then the highlighted
435 // text is unhighlighted when the widget gets the focus
436 // next. Need to disable the parent's menu items now.
438 if (XmTextGetSelection(_w) != NULL) {
439 text_already_selected = TRUE;
442 if (text_already_selected)
443 this->text_unselected();
447 XmTextEditor::text_selected_callback(
454 XmTextEditor *obj=(XmTextEditor *) clientData;
456 obj->text_selected();
461 XmTextEditor::text_unselected_callback(
468 // XmTextEditor *obj=(XmTextEditor *) clientData;
470 // obj->text_unselected();
475 XmTextEditor::text_selected()
477 if (!text_already_selected) {
478 text_already_selected = TRUE;
479 my_owner->owner()->text_selected();
484 XmTextEditor::text_unselected()
486 text_already_selected = FALSE;
487 my_owner->owner()->text_unselected();
491 XmTextEditor::no_text()
493 char *text = get_contents();;
494 int text_len = strlen(text);
497 for ( int k = 0; k < text_len; k++ ) {
498 if ( isgraph(text[k]) ) {
508 XmTextEditor::undo_edit()
510 // This is to be consistent with DtEditor.
511 // Do nothing since Motif XmText does not support this.
515 XmTextEditor::set_word_wrap(Boolean)
517 // This is to be consistent with DtEditor.
518 // Do nothing since Motif XmText does not support this.
522 XmTextEditor::find_change()
524 // This is to be consistent with DtEditor.
525 // Do nothing since Motif XmText does not support this.
529 XmTextEditor::spell()
531 // This is to be consistent with DtEditor.
532 // Do nothing since Motif XmText does not support this.
536 XmTextEditor::format()
538 // This is to be consistent with DtEditor.
539 // Do nothing since Motif XmText does not support this.
543 XmTextEditor::cut_selection()
545 // Shouldn't really use CurrentTime
546 XmTextCut( _w, CurrentTime );
550 XmTextEditor::copy_selection()
552 // Shouldn't really use CurrentTime
553 XmTextCopy( _w, CurrentTime );
557 XmTextEditor::paste_from_clipboard()
563 XmTextEditor::paste_special_from_clipboard(Editor::InsertFormat format)
568 cd.insert_format = format;
570 XtAddCallback(_w, XmNmodifyVerifyCallback,
571 modify_verify_callback, (XtPointer)&cd);
575 XtRemoveCallback(_w, XmNmodifyVerifyCallback,
576 modify_verify_callback, (XtPointer)&cd);
580 // Removes the selection and leaves the resulting white space.
582 XmTextEditor::clear_selection()
584 // Shouldn't really use CurrentTime
585 // XmTextClearSelection( _w, CurrentTime );
587 // BUG in XmTextClearSelection. Selection is not cleared. Only the cursor
588 // is advanced to the last selected position. Therefore need the following
591 XmTextPosition left, right;
593 if ( XmTextGetSelectionPosition( _w, &left, &right ) ) {
594 char *sel = XmTextGetSelection( _w );
595 // NOTE: Modifying buffer returned by XmTextGetSelection.
596 // Future Motif implementation might return read only buffer.
598 memset( sel, ' ', strlen(sel) );
599 // XmTextInsert( _w, left, sel );
600 XmTextReplace( _w, left, right, sel );
606 // Removes the selection and compresses the resulting white space.
608 XmTextEditor::delete_selection()
614 XmTextEditor::select_all()
616 XmTextSetSelection( _w, 0, XmTextGetLastPosition(_w), CurrentTime );
620 XmTextEditor::disable_redisplay(void)
622 XmTextDisableRedisplay(_w);
626 XmTextEditor::enable_redisplay(void)
628 XmTextEnableRedisplay(_w);
632 XmTextEditor::loadFile(const char * path, const int pos)
634 int fd = open(path, O_RDONLY);
640 if (fstat(fd, &info) < 0) {
645 int page_size = (int)sysconf(_SC_PAGESIZE);
646 size_t map_size = (size_t)(info.st_size +
647 (page_size - (info.st_size % page_size)));
650 map = (char *) mmap(0, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
652 if (map == (char *)-1) {
653 // We could not map it for some reason. Let's just read it into
654 // _buffer and pass it to XmText.
656 this->my_owner->needBuf(&_buffer, &_buf_len, info.st_size + 1);
657 if (read(fd, _buffer, (unsigned int) info.st_size) < 0) {
661 _buffer[info.st_size] = 0;
662 XmTextInsert(_w, pos, _buffer);
665 // We now have a mapped file. XmText wants a zero terminated
666 // buffer. We get luck with mmap because unless the file is
667 // an even page size, we will have some zero fill bytes that
668 // are legal to access.
670 // Of course in the case of an even page size file we must
671 // copy the buffer, terminate it and then give it to XmText.
673 if (info.st_size < map_size) {
674 XmTextInsert(_w, pos, map);
677 this->my_owner->needBuf(&_buffer, &_buf_len, info.st_size + 1);
678 this->my_owner->stripCRLF(&_buffer, map, info.st_size);
679 XmTextInsert(_w, pos, _buffer);
681 munmap(map, map_size);
688 XmTextEditor::modify_verify_callback(
689 Widget , XtPointer client, XtPointer call_data)
691 PSClientData *cd = (PSClientData *)client;
692 XmTextVerifyCallbackStruct *modify_info =
693 (XmTextVerifyCallbackStruct *)call_data;
695 // Make sure we are being called programmatically
696 if(modify_info->event != (XEvent *)NULL)
699 cd->obj->modifyPasteData(modify_info, cd->insert_format);
703 * This fucntion modifies the pasted data
704 * with an indent prefix before each new line or brackets it.
708 XmTextEditor::modifyPasteData(
709 XmTextVerifyCallbackStruct *modify_info,
710 Editor::InsertFormat insert_format)
712 // The toolkit does not use this any more, this must be weird stuff.
713 if(modify_info->text->format == XmFMT_16_BIT)
716 if(_modified_text == NULL)
717 _modified_text = (XmTextBlockRec *)calloc(1,sizeof(XmTextBlockRec));
719 char *sp = modify_info->text->ptr; // source pointer to the insert string
720 int length = modify_info->text->length; // length does not include '\0' char
721 char *maxsp = sp + length; // maxmimum source ptr
723 // Allocate memory rounded off to the nearest BUFINC
724 size_t size_req = (size_t)(((length/BUFINC)+1)*BUFINC);
725 if((_modified_text_buflen < size_req) ||
726 ((_modified_text_buflen > XmTextEditor::MAXBUFSZ) &&
727 (size_req < XmTextEditor::MAXBUFSZ)) )
728 reallocPasteBuf(size_req);
730 if(_modified_text->ptr == NULL)
731 return; // No memory available
733 switch( insert_format) {
739 // Get the indent prefix string
740 DtMail::Session *m_session =
741 theRoamApp.session()->session();
742 m_session->mailRc(error)->getValue(error,
743 "indentprefix", &indent_str);
744 if ( error.isSet() || !indent_str)
745 indent_str = strdup("> ");
747 size_t indlen = strlen(indent_str);
749 // Copy the src buf into dest, inserting indent before '\n'
752 // Make sure there is enough space
753 // for an indent prefix, one char and a terminating '\0'
754 if(!((ip+indlen+2) < _modified_text_buflen) ) {
755 size_req = (size_t)((((_modified_text_buflen +
756 indlen+2)/BUFINC)+1)*BUFINC);
757 reallocPasteBuf(size_req);
758 if(_modified_text->ptr == NULL)
759 return; // No memory available
762 // Copy the indent string at the beginning
764 memcpy(_modified_text->ptr, indent_str, indlen);
768 // Copy the next byte and check for new line
769 _modified_text->ptr[ip++] = *sp++;
770 if(*(sp-1) == '\n') {
771 memcpy(&_modified_text->ptr[ip], indent_str, indlen);
776 _modified_text->ptr[ip] = '\0'; // terminate with a null char
777 _modified_text->length = ip; // Do not include '\0' char in len
783 if( !begin_ins_bracket)
784 begin_ins_bracket = GETMSG(DT_catd, 1, 199,
785 "\n------------- Begin Included Message -------------\n");
787 end_ins_bracket = GETMSG(DT_catd, 1, 200,
788 "\n------------- End Included Message -------------\n");
790 size_t begin_len = strlen(begin_ins_bracket);
791 size_t end_len = strlen(end_ins_bracket);
793 // Make sure there is enough space
794 if((size_req = length + begin_len + end_len + 1) >
795 _modified_text_buflen) {
796 size_req = (size_t) ((((size_req)/BUFINC)+1)*BUFINC);
797 reallocPasteBuf(size_req);
800 if(_modified_text->ptr == NULL)
803 strcpy(_modified_text->ptr, begin_ins_bracket);
804 strncat(_modified_text->ptr,sp,length);
805 strcat(_modified_text->ptr, end_ins_bracket);
806 _modified_text->length = end_len + begin_len + length;
813 _modified_text->format = modify_info->text->format;
815 // Stuff the modified text block ptr in the return call data
816 modify_info->text = _modified_text;
820 XmTextEditor::MenuButtonHandler(
826 XmTextEditor *obj = (XmTextEditor *)cd;
828 if(event->xany.type != ButtonPress)
831 XButtonEvent *be = (XButtonEvent *)event;
833 if(be->button == Button3)
834 obj->my_owner->owner()->postTextPopup(event);