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)));
651 // Need the (char *) for compile to work in ALL cases ... for the
652 // POSIX "mmap" is (void *). Also, this version of mmap does NOT
653 // allow requested length to be greater than the file size ...
654 // in contradiction to the documentation (don't round up).
655 map = (char *) mmap(0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
657 map = (char *) mmap(0, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
660 if (map == (char *)-1) {
661 // We could not map it for some reason. Let's just read it into
662 // _buffer and pass it to XmText.
664 this->my_owner->needBuf(&_buffer, &_buf_len, info.st_size + 1);
665 if (read(fd, _buffer, (unsigned int) info.st_size) < 0) {
669 _buffer[info.st_size] = 0;
670 XmTextInsert(_w, pos, _buffer);
673 // We now have a mapped file. XmText wants a zero terminated
674 // buffer. We get luck with mmap because unless the file is
675 // an even page size, we will have some zero fill bytes that
676 // are legal to access.
678 // Of course in the case of an even page size file we must
679 // copy the buffer, terminate it and then give it to XmText.
681 if (info.st_size < map_size) {
682 XmTextInsert(_w, pos, map);
685 this->my_owner->needBuf(&_buffer, &_buf_len, info.st_size + 1);
686 this->my_owner->stripCRLF(&_buffer, map, info.st_size);
687 XmTextInsert(_w, pos, _buffer);
689 munmap(map, map_size);
696 XmTextEditor::modify_verify_callback(
697 Widget , XtPointer client, XtPointer call_data)
699 PSClientData *cd = (PSClientData *)client;
700 XmTextVerifyCallbackStruct *modify_info =
701 (XmTextVerifyCallbackStruct *)call_data;
703 // Make sure we are being called programmatically
704 if(modify_info->event != (XEvent *)NULL)
707 cd->obj->modifyPasteData(modify_info, cd->insert_format);
711 * This fucntion modifies the pasted data
712 * with an indent prefix before each new line or brackets it.
716 XmTextEditor::modifyPasteData(
717 XmTextVerifyCallbackStruct *modify_info,
718 Editor::InsertFormat insert_format)
720 // The toolkit does not use this any more, this must be weird stuff.
721 if(modify_info->text->format == XmFMT_16_BIT)
724 if(_modified_text == NULL)
725 _modified_text = (XmTextBlockRec *)calloc(1,sizeof(XmTextBlockRec));
727 char *sp = modify_info->text->ptr; // source pointer to the insert string
728 int length = modify_info->text->length; // length does not include '\0' char
729 char *maxsp = sp + length; // maxmimum source ptr
731 // Allocate memory rounded off to the nearest BUFINC
732 size_t size_req = (size_t)(((length/BUFINC)+1)*BUFINC);
733 if((_modified_text_buflen < size_req) ||
734 ((_modified_text_buflen > XmTextEditor::MAXBUFSZ) &&
735 (size_req < XmTextEditor::MAXBUFSZ)) )
736 reallocPasteBuf(size_req);
738 if(_modified_text->ptr == NULL)
739 return; // No memory available
741 switch( insert_format) {
747 // Get the indent prefix string
748 DtMail::Session *m_session =
749 theRoamApp.session()->session();
750 m_session->mailRc(error)->getValue(error,
751 "indentprefix", &indent_str);
752 if ( error.isSet() || !indent_str)
753 indent_str = strdup("> ");
755 size_t indlen = strlen(indent_str);
757 // Copy the src buf into dest, inserting indent before '\n'
760 // Make sure there is enough space
761 // for an indent prefix, one char and a terminating '\0'
762 if(!((ip+indlen+2) < _modified_text_buflen) ) {
763 size_req = (size_t)((((_modified_text_buflen +
764 indlen+2)/BUFINC)+1)*BUFINC);
765 reallocPasteBuf(size_req);
766 if(_modified_text->ptr == NULL)
767 return; // No memory available
770 // Copy the indent string at the beginning
772 memcpy(_modified_text->ptr, indent_str, indlen);
776 // Copy the next byte and check for new line
777 _modified_text->ptr[ip++] = *sp++;
778 if(*(sp-1) == '\n') {
779 memcpy(&_modified_text->ptr[ip], indent_str, indlen);
784 _modified_text->ptr[ip] = '\0'; // terminate with a null char
785 _modified_text->length = ip; // Do not include '\0' char in len
791 if( !begin_ins_bracket)
792 begin_ins_bracket = GETMSG(DT_catd, 1, 199,
793 "\n------------- Begin Included Message -------------\n");
795 end_ins_bracket = GETMSG(DT_catd, 1, 200,
796 "\n------------- End Included Message -------------\n");
798 size_t begin_len = strlen(begin_ins_bracket);
799 size_t end_len = strlen(end_ins_bracket);
801 // Make sure there is enough space
802 if((size_req = length + begin_len + end_len + 1) >
803 _modified_text_buflen) {
804 size_req = (size_t) ((((size_req)/BUFINC)+1)*BUFINC);
805 reallocPasteBuf(size_req);
808 if(_modified_text->ptr == NULL)
811 strcpy(_modified_text->ptr, begin_ins_bracket);
812 strncat(_modified_text->ptr,sp,length);
813 strcat(_modified_text->ptr, end_ins_bracket);
814 _modified_text->length = end_len + begin_len + length;
821 _modified_text->format = modify_info->text->format;
823 // Stuff the modified text block ptr in the return call data
824 modify_info->text = _modified_text;
828 XmTextEditor::MenuButtonHandler(
834 XmTextEditor *obj = (XmTextEditor *)cd;
836 if(event->xany.type != ButtonPress)
839 XButtonEvent *be = (XButtonEvent *)event;
841 if(be->button == Button3)
842 obj->my_owner->owner()->postTextPopup(event);