4 * $TOG: XmTextEditor.C /main/13 1998/02/03 10:29:51 mgreess $
6 * RESTRICTED CONFIDENTIAL INFORMATION:
8 * The information in this document is subject to special
9 * restrictions in a confidential disclosure agreement between
10 * HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
11 * document outside HP, IBM, Sun, USL, SCO, or Univel without
12 * Sun's specific written approval. This document and all copies
13 * and derivative works thereof must be returned or destroyed at
16 * Copyright 1993 Sun Microsystems, Inc. All rights reserved.
21 #include <EUSCompat.h>
26 #if defined(NEED_MMAP_WRAPPER)
30 #include <sys/types.h>
33 #if defined(NEED_MMAP_WRAPPER)
44 #include "XmTextEditor.h"
48 XmTextEditor::XmTextEditor(
50 DtMailEditor *owner_of_editor
54 my_owner = owner_of_editor;
60 _modified_text = NULL;
61 _modified_text_buflen = 0;
62 begin_ins_bracket = NULL;
64 end_ins_bracket = NULL;
65 _auto_show_cursor = FALSE;
66 text_already_selected = FALSE;
69 XmTextEditor::~XmTextEditor()
77 if(_modified_text->ptr) {
78 free(_modified_text->ptr);
79 _modified_text->ptr = NULL;
82 _modified_text = NULL;
84 if (NULL != indent_str)
85 free((void*) indent_str);
89 XmTextEditor::initialize()
97 DtMail::Session * d_session = theRoamApp.session()->session();
98 DtMail::MailRc * mailrc = d_session->mailRc(error);
101 mailrc->getValue(error, "popuplines", &value);
103 value = strdup("24");
105 rows = (short) strtol(value, NULL, 10);
109 // If toolcols is set, overwrite the column width with "toolcols" value.
110 // Otherwise, default resource value will be used.
112 mailrc->getValue(error, "toolcols", &value);
114 cols = (short) strtol(value, NULL, 10);
115 XtSetArg(args[n], XmNcolumns, cols); n++;
121 * MB_CUR_MAX == 1 : SingleByteLanguage
122 * MB_CUR_MAX > 1 : MultiByteLanguage
124 if ( MB_CUR_MAX == 1 )
131 XtSetArg(args[n], XmNeditable, FALSE); n++;
132 XtSetArg(args[n], XmNrows, 24); n++;
133 if ( MB_CUR_MAX == 1 ) {
134 XtSetArg(args[n], XmNcolumns, 80); n++;
136 XtSetArg(args[n], XmNcolumns, 40); n++;
139 _w = XmCreateScrolledText(my_parent, "Text", args, n );
141 update_display_from_props();
143 XtAddEventHandler(XtParent(_w), ButtonPressMask,
144 FALSE, MenuButtonHandler,
149 XmTextEditor::set_contents(
150 const char *contents,
151 const unsigned long len
154 if (contents[len - 1] == 0) {
155 XmTextSetString(_w, (char *)contents);
158 this->my_owner->needBuf(&_buffer, &_buf_len, len + 1);
159 this->my_owner->stripCRLF(&_buffer, contents, len);
160 XmTextSetString(_w, _buffer);
165 XmTextEditor::set_contents(const char * path)
171 XmTextEditor::get_contents()
173 return(XmTextGetString(_w));
177 XmTextEditor::append_to_contents(
178 const char *contents,
179 const unsigned long len
183 if (contents[len - 1] == 0) {
184 XmTextInsert( _w, XmTextGetLastPosition( _w ),
188 // Not null terminated, and most likely has crlf instead of lf.
190 this->my_owner->needBuf(&_buffer, &_buf_len, len + 1);
191 this->my_owner->stripCRLF(&_buffer, contents, len);
192 XmTextInsert(_w, XmTextGetLastPosition(_w), _buffer);
197 XmTextEditor::append_to_contents(const char * path)
199 loadFile(path, (const int) XmTextGetLastPosition(_w));
203 XmTextEditor::append_at_cursor(
204 const char *contents,
205 const unsigned long len
208 if (contents[len - 1] == 0) {
211 XmTextGetInsertionPosition(_w),
216 // Not null terminated, and most likely has crlf instead of lf.
218 this->my_owner->needBuf(&_buffer, &_buf_len, len + 1);
219 this->my_owner->stripCRLF(&_buffer, contents, len);
222 XmTextGetInsertionPosition(_w),
228 XmTextEditor::append_at_cursor(const char * path)
230 loadFile(path, (const int)XmTextGetInsertionPosition(_w));
234 XmTextEditor::clear_contents()
237 XmTextSetString(_w, "");
242 XmTextEditor::get_text_widget()
248 XmTextEditor::get_text_foreground()
260 XmTextEditor::get_text_background()
271 XmTextEditor::get_text_fontList()
282 XmTextEditor::get_text_width()
293 XmTextEditor::get_editor()
299 XmTextEditor::set_editable(
303 XmTextSetEditable( _w, bval);
305 // If not editable, turn off the cursor?
306 XtVaSetValues(_w, XmNcursorPositionVisible, bval, NULL);
311 XmTextEditor::get_columns()
314 XtVaGetValues(_w, XmNcolumns, &ncolumns, NULL);
320 XmTextEditor::get_rows()
323 XtVaGetValues(_w, XmNrows, &nrows, NULL);
328 XmTextEditor::set_columns(int ncolumns)
330 XtVaSetValues(_w, XmNcolumns, ncolumns, NULL);
335 XmTextEditor::set_rows(int nrows)
337 XtVaSetValues(_w, XmNrows, nrows, NULL);
342 // TOGO XmTextEditor::set_container(
346 // TOGO // Extract text and display?
350 // TOGO XmTextEditor::get_container()
352 // TOGO return(NULL);
356 XmTextEditor::auto_show_cursor_off()
358 // Get the original value of XmNautoShowCursorPosition
360 XmNautoShowCursorPosition, &_auto_show_cursor,
363 // Set it to false so we don't scroll with the cursor.
365 XmNautoShowCursorPosition, FALSE,
370 XmTextEditor::auto_show_cursor_restore()
372 // Restore the original value of XmNautoShowCursorPosition.
374 XmNautoShowCursorPosition, _auto_show_cursor,
379 XmTextEditor::set_to_top()
382 XmTextShowPosition(_w, 0);
383 XmTextSetInsertionPosition(_w, 0);
388 XmTextEditor::set_to_bottom()
390 XmTextSetInsertionPosition( _w, XmTextGetLastPosition(_w) );
395 XmTextEditor::focus_callback(
402 XmTextEditor *obj=(XmTextEditor *) clientData;
404 obj->obtained_focus();
407 #endif /* DEAD_WOOD */
410 XmTextEditor::obtained_focus()
412 // If there is text already selected, then the highlighted
413 // text is unhighlighted when the widget gets the focus
414 // next. Need to disable the parent's menu items now.
416 if (XmTextGetSelection(_w) != NULL) {
417 text_already_selected = TRUE;
420 if (text_already_selected)
421 this->text_unselected();
425 XmTextEditor::text_selected_callback(
432 XmTextEditor *obj=(XmTextEditor *) clientData;
434 obj->text_selected();
439 XmTextEditor::text_unselected_callback(
446 // XmTextEditor *obj=(XmTextEditor *) clientData;
448 // obj->text_unselected();
453 XmTextEditor::text_selected()
455 if (!text_already_selected) {
456 text_already_selected = TRUE;
457 my_owner->owner()->text_selected();
462 XmTextEditor::text_unselected()
464 text_already_selected = FALSE;
465 my_owner->owner()->text_unselected();
469 XmTextEditor::no_text()
471 char *text = get_contents();;
472 int text_len = strlen(text);
475 for ( int k = 0; k < text_len; k++ ) {
476 if ( isgraph(text[k]) ) {
486 XmTextEditor::undo_edit()
488 // This is to be consistent with DtEditor.
489 // Do nothing since Motif XmText does not support this.
493 XmTextEditor::set_word_wrap(Boolean)
495 // This is to be consistent with DtEditor.
496 // Do nothing since Motif XmText does not support this.
500 XmTextEditor::find_change()
502 // This is to be consistent with DtEditor.
503 // Do nothing since Motif XmText does not support this.
507 XmTextEditor::spell()
509 // This is to be consistent with DtEditor.
510 // Do nothing since Motif XmText does not support this.
514 XmTextEditor::format()
516 // This is to be consistent with DtEditor.
517 // Do nothing since Motif XmText does not support this.
521 XmTextEditor::cut_selection()
523 // Shouldn't really use CurrentTime
524 XmTextCut( _w, CurrentTime );
528 XmTextEditor::copy_selection()
530 // Shouldn't really use CurrentTime
531 XmTextCopy( _w, CurrentTime );
535 XmTextEditor::paste_from_clipboard()
541 XmTextEditor::paste_special_from_clipboard(Editor::InsertFormat format)
546 cd.insert_format = format;
548 XtAddCallback(_w, XmNmodifyVerifyCallback,
549 modify_verify_callback, (XtPointer)&cd);
553 XtRemoveCallback(_w, XmNmodifyVerifyCallback,
554 modify_verify_callback, (XtPointer)&cd);
558 // Removes the selection and leaves the resulting white space.
560 XmTextEditor::clear_selection()
562 // Shouldn't really use CurrentTime
563 // XmTextClearSelection( _w, CurrentTime );
565 // BUG in XmTextClearSelection. Selection is not cleared. Only the cursor
566 // is advanced to the last selected position. Therefore need the following
569 XmTextPosition left, right;
571 if ( XmTextGetSelectionPosition( _w, &left, &right ) ) {
572 char *sel = XmTextGetSelection( _w );
573 // NOTE: Modifying buffer returned by XmTextGetSelection.
574 // Future Motif implementation might return read only buffer.
576 memset( sel, ' ', strlen(sel) );
577 // XmTextInsert( _w, left, sel );
578 XmTextReplace( _w, left, right, sel );
584 // Removes the selection and compresses the resulting white space.
586 XmTextEditor::delete_selection()
592 XmTextEditor::select_all()
594 XmTextSetSelection( _w, 0, XmTextGetLastPosition(_w), CurrentTime );
598 XmTextEditor::disable_redisplay(void)
600 XmTextDisableRedisplay(_w);
604 XmTextEditor::enable_redisplay(void)
606 XmTextEnableRedisplay(_w);
610 XmTextEditor::loadFile(const char * path, const int pos)
612 int fd = open(path, O_RDONLY);
618 if (fstat(fd, &info) < 0) {
623 int page_size = (int)sysconf(_SC_PAGESIZE);
624 size_t map_size = (size_t)(info.st_size +
625 (page_size - (info.st_size % page_size)));
629 // Need the (char *) for compile to work in ALL cases ... for the
630 // POSIX "mmap" is (void *). Also, this version of mmap does NOT
631 // allow requested length to be greater than the file size ...
632 // in contradiction to the documentation (don't round up).
633 map = (char *) mmap(0, info.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
635 map = (char *) mmap(0, map_size, PROT_READ, MAP_PRIVATE, fd, 0);
638 if (map == (char *)-1) {
639 // We could not map it for some reason. Let's just read it into
640 // _buffer and pass it to XmText.
642 this->my_owner->needBuf(&_buffer, &_buf_len, info.st_size + 1);
643 if (read(fd, _buffer, (unsigned int) info.st_size) < 0) {
647 _buffer[info.st_size] = 0;
648 XmTextInsert(_w, pos, _buffer);
651 // We now have a mapped file. XmText wants a zero terminated
652 // buffer. We get luck with mmap because unless the file is
653 // an even page size, we will have some zero fill bytes that
654 // are legal to access.
656 // Of course in the case of an even page size file we must
657 // copy the buffer, terminate it and then give it to XmText.
659 if (info.st_size < map_size) {
660 XmTextInsert(_w, pos, map);
663 this->my_owner->needBuf(&_buffer, &_buf_len, info.st_size + 1);
664 this->my_owner->stripCRLF(&_buffer, map, info.st_size);
665 XmTextInsert(_w, pos, _buffer);
667 munmap(map, map_size);
674 XmTextEditor::modify_verify_callback(
675 Widget , XtPointer client, XtPointer call_data)
677 PSClientData *cd = (PSClientData *)client;
678 XmTextVerifyCallbackStruct *modify_info =
679 (XmTextVerifyCallbackStruct *)call_data;
681 // Make sure we are being called programmatically
682 if(modify_info->event != (XEvent *)NULL)
685 cd->obj->modifyPasteData(modify_info, cd->insert_format);
689 * This fucntion modifies the pasted data
690 * with an indent prefix before each new line or brackets it.
694 XmTextEditor::modifyPasteData(
695 XmTextVerifyCallbackStruct *modify_info,
696 Editor::InsertFormat insert_format)
698 // The toolkit does not use this any more, this must be weird stuff.
699 if(modify_info->text->format == XmFMT_16_BIT)
702 if(_modified_text == NULL)
703 _modified_text = (XmTextBlockRec *)calloc(1,sizeof(XmTextBlockRec));
705 char *sp = modify_info->text->ptr; // source pointer to the insert string
706 int length = modify_info->text->length; // length does not include '\0' char
707 char *maxsp = sp + length; // maxmimum source ptr
709 // Allocate memory rounded off to the nearest BUFINC
710 size_t size_req = (size_t)(((length/BUFINC)+1)*BUFINC);
711 if((_modified_text_buflen < size_req) ||
712 ((_modified_text_buflen > XmTextEditor::MAXBUFSZ) &&
713 (size_req < XmTextEditor::MAXBUFSZ)) )
714 reallocPasteBuf(size_req);
716 if(_modified_text->ptr == NULL)
717 return; // No memory available
719 switch( insert_format) {
725 // Get the indent prefix string
726 DtMail::Session *m_session =
727 theRoamApp.session()->session();
728 m_session->mailRc(error)->getValue(error,
729 "indentprefix", &indent_str);
730 if ( error.isSet() || !indent_str)
731 indent_str = strdup("> ");
733 size_t indlen = strlen(indent_str);
735 // Copy the src buf into dest, inserting indent before '\n'
738 // Make sure there is enough space
739 // for an indent prefix, one char and a terminating '\0'
740 if(!((ip+indlen+2) < _modified_text_buflen) ) {
741 size_req = (size_t)((((_modified_text_buflen +
742 indlen+2)/BUFINC)+1)*BUFINC);
743 reallocPasteBuf(size_req);
744 if(_modified_text->ptr == NULL)
745 return; // No memory available
748 // Copy the indent string at the beginning
750 memcpy(_modified_text->ptr, indent_str, indlen);
754 // Copy the next byte and check for new line
755 _modified_text->ptr[ip++] = *sp++;
756 if(*(sp-1) == '\n') {
757 memcpy(&_modified_text->ptr[ip], indent_str, indlen);
762 _modified_text->ptr[ip] = '\0'; // terminate with a null char
763 _modified_text->length = ip; // Do not include '\0' char in len
769 if( !begin_ins_bracket)
770 begin_ins_bracket = GETMSG(DT_catd, 1, 199,
771 "\n------------- Begin Included Message -------------\n");
773 end_ins_bracket = GETMSG(DT_catd, 1, 200,
774 "\n------------- End Included Message -------------\n");
776 size_t begin_len = strlen(begin_ins_bracket);
777 size_t end_len = strlen(end_ins_bracket);
779 // Make sure there is enough space
780 if((size_req = length + begin_len + end_len + 1) >
781 _modified_text_buflen) {
782 size_req = (size_t) ((((size_req)/BUFINC)+1)*BUFINC);
783 reallocPasteBuf(size_req);
786 if(_modified_text->ptr == NULL)
789 strcpy(_modified_text->ptr, begin_ins_bracket);
790 strncat(_modified_text->ptr,sp,length);
791 strcat(_modified_text->ptr, end_ins_bracket);
792 _modified_text->length = end_len + begin_len + length;
799 _modified_text->format = modify_info->text->format;
801 // Stuff the modified text block ptr in the return call data
802 modify_info->text = _modified_text;
806 XmTextEditor::MenuButtonHandler(
812 XmTextEditor *obj = (XmTextEditor *)cd;
814 if(event->xany.type != ButtonPress)
817 XButtonEvent *be = (XButtonEvent *)event;
819 if(be->button == Button3)
820 obj->my_owner->owner()->postTextPopup(event);