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: DtEditor.C /main/11 1998/02/03 10:28:15 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 #ifndef I_HAVE_NO_IDENT
56 #include <X11/IntrinsicP.h>
58 #include <Xm/CutPaste.h>
62 #include "DtEditor.hh"
63 #include "MailMsg.h" // DT_catd defined here
65 CDEM_DtWidgetEditor::CDEM_DtWidgetEditor(
67 DtMailEditor *owner_of_editor
71 my_owner = owner_of_editor;
74 _modified_text = NULL;
75 _modified_text_buflen = 0;
77 begin_ins_bracket = NULL;
79 end_ins_bracket = NULL;
80 _auto_show_cursor = FALSE;
83 _buf_len = (unsigned long) 0;
84 text_already_selected = FALSE;
87 CDEM_DtWidgetEditor::~CDEM_DtWidgetEditor()
90 // No DtEditor API equivalent
91 // Remove the callbacks first.
93 XtRemoveCallback(my_text, DtNtextSelectCallback,
94 &CDEM_DtWidgetEditor::text_selected_callback, this);
95 XtRemoveCallback(my_text, DtNtextDeselectCallback,
96 &CDEM_DtWidgetEditor::text_unselected_callback, this);
97 XtRemoveCallback( my_text, XmNhelpCallback, HelpTexteditCB, this ) ;
99 XtDestroyWidget(my_text);
106 if(_modified_text ) {
107 if(_modified_text->ptr) {
108 free(_modified_text->ptr);
109 _modified_text->ptr = NULL;
111 free(_modified_text);
112 _modified_text = NULL;
114 if (NULL != indent_str)
115 free((void*) indent_str);
119 CDEM_DtWidgetEditor::initialize()
130 DtMail::Session * d_session = theRoamApp.session()->session();
131 DtMail::MailRc * mailrc = d_session->mailRc(error);
133 const char * value = NULL;
134 mailrc->getValue(error, "popuplines", &value);
136 value = strdup("24");
138 rows = strtol(value, NULL, 10);
142 // If toolcols is set, overwrite the column width with "toolcols" value.
143 // Otherwise, default resource value will be used.
145 mailrc->getValue(error, "toolcols", &value);
147 cols = strtol(value, NULL, 10);
148 XtSetArg(args[i], DtNcolumns, cols); i++;
154 * MB_CUR_MAX == 1 : SingleByteLanguage
155 * MB_CUR_MAX > 1 : MultiByteLanguage
157 if ( MB_CUR_MAX == 1 )
162 cols = strtol(value, NULL, 10);
163 XtSetArg(args[i], DtNcolumns, cols); i++;
167 XtSetArg(args[i], DtNeditable, FALSE); i++;
168 XtSetArg(args[i], DtNrows, 24); i++;
169 if ( MB_CUR_MAX == 1 ) {
170 XtSetArg(args[i], DtNcolumns, 80); i++;
172 XtSetArg(args[i], DtNcolumns, 40); i++;
174 XtSetArg(args[i], DtNcursorPositionVisible, FALSE); i++;
176 my_text = DtCreateEditor(my_parent, "Text", args, i);
178 update_display_from_props();
179 XtAddCallback(my_text, DtNtextSelectCallback,
180 &CDEM_DtWidgetEditor::text_selected_callback, this);
181 XtAddCallback(my_text, DtNtextDeselectCallback,
182 &CDEM_DtWidgetEditor::text_unselected_callback, this);
183 XtAddCallback( my_text, XmNhelpCallback, HelpTexteditCB, this ) ;
185 XtAddEventHandler(my_text, ButtonPressMask,
186 FALSE, MenuButtonHandler,
189 XtManageChild(my_text);
195 CDEM_DtWidgetEditor::get_contents()
198 DtEditorErrorCode status;
199 static DtEditorContentRec content;
201 content.type = DtEDITOR_TEXT;
203 // Get the contents with hardCarriageReturns = TRUE and
204 // markContentsAsSaved = TRUE.
207 * If hardCarriageReturns = TRUE, the performace of DtEditorGetContents()
208 * suffers since according to man 3 DtEditorGetContents,
210 * The hardCarriageReturns argument, if set to True, indicates
211 * that the DtEditor widget should replace any soft line feeds
212 * (word wraps) with <newline>s when saving the data. When
213 * hardCarriageReturns is set to False, any line wrapped
214 * because it reaches the right edge of the window is saved as
217 * And current default value of DtNwordWrap is TRUE. See dtmail/Dtmail.
218 * My temporary and non-good solution is
219 * - Change default to False.
220 * - If DtNwordWarp == TRUE,
221 * call DtEditorGetContents(my_text, &content, TRUE, TRUE)
223 * call DtEditorGetContents(my_text, &content, False, TRUE)
224 * This value can be controllable by a resource file or Format menu.
226 * Goofy ? but...................;-(
231 XtSetArg( args[0], DtNwordWrap, &ww );
232 XtGetValues( my_text, args, 1 );
233 status = DtEditorGetContents(my_text, &content, ww, TRUE);
235 return(content.value.string);
239 CDEM_DtWidgetEditor::set_contents(
240 const char *contents,
241 const unsigned long len
244 DtEditorContentRec content;
245 DtEditorErrorCode status;
247 this->my_owner->needBuf(&_buffer, &_buf_len, len + 1);
248 this->my_owner->stripCRLF(&_buffer, contents, len);
250 content.type = DtEDITOR_TEXT;
251 content.value.string = _buffer;
252 status = DtEditorSetContents(my_text, &content);
257 CDEM_DtWidgetEditor::set_contents(
261 DtEditorSetContentsFromFile(my_text, (char *)path);
265 CDEM_DtWidgetEditor::clear_contents()
268 // Doesn't work yet. Work around with setting an empty string...
269 // DtEditorReset(my_text);
271 DtEditorContentRec content;
272 DtEditorErrorCode status;
274 content.type = DtEDITOR_TEXT;
275 content.value.string = NULL;
276 status = DtEditorSetContents(my_text, &content);
281 CDEM_DtWidgetEditor::append_to_contents(
282 const char *contents,
283 const unsigned long len
286 DtEditorContentRec rec;
288 rec.type = DtEDITOR_TEXT;
290 if ( contents[len - 1] == 0 ) {
291 rec.value.string = (char *)contents;
293 this->my_owner->needBuf(&_buffer, &_buf_len, len + 1);
294 this->my_owner->stripCRLF(&_buffer, contents, len);
295 rec.value.string = _buffer;
298 DtEditorInsert(my_text, &rec);
302 CDEM_DtWidgetEditor::append_to_contents(
307 DtEditorAppendFromFile(my_text, (char *)path);
312 CDEM_DtWidgetEditor::append_at_cursor(
316 DtEditorInsertFromFile(my_text, (char *) path);
320 CDEM_DtWidgetEditor::append_at_cursor(
321 const char *contents,
322 const unsigned long len
325 DtEditorContentRec rec;
327 rec.type = DtEDITOR_TEXT;
329 if ( contents[len - 1] == 0 ) {
330 rec.value.string = (char *)contents;
332 this->my_owner->needBuf(&_buffer, &_buf_len, len + 1);
333 this->my_owner->stripCRLF(&_buffer, contents, len);
334 rec.value.string = _buffer;
336 //DtEditorAppend(my_text, &rec);
337 // Fix for the defect 179186 05-25-95
338 // The above API will insert "contents" to the end of the buffer
339 // (appending). It should change to DtEditorInsert which insert
340 // string to the current position (the cursor's position)
341 DtEditorInsert(my_text, &rec);
345 CDEM_DtWidgetEditor::get_text_widget()
347 // We actually need to return the text widget contained
348 // within DtEditor. For now, just return the DtEditor.
354 CDEM_DtWidgetEditor::get_text_foreground()
358 XtVaGetValues(my_text,
359 DtNtextForeground, &fg,
366 // DtEditor returns the bg color of the Form widget, not the
367 // text widget that the Form contains.
368 // This explains why the attachment pane color is that of the scroll bar...
369 // DtEditor needs to return the color of its text widget.
370 // OBTW, DtNtextBackground and DtNtextForeground don't work. They
371 // return uninitialized values
374 CDEM_DtWidgetEditor::get_text_background()
378 XtVaGetValues(my_text,
379 DtNtextBackground, &bg,
386 CDEM_DtWidgetEditor::get_text_fontList()
390 XtVaGetValues(my_text,
391 DtNtextFontList, &fl,
398 CDEM_DtWidgetEditor::get_text_width()
402 XtVaGetValues(my_text,
410 CDEM_DtWidgetEditor::get_editor()
416 CDEM_DtWidgetEditor::get_columns()
419 XtVaGetValues(my_text, DtNcolumns, &ncolumns, NULL);
420 return (int) ncolumns;
425 CDEM_DtWidgetEditor::get_rows()
428 XtVaGetValues(my_text, DtNrows, &nrows, NULL);
433 CDEM_DtWidgetEditor::set_editable(Boolean bval)
435 XtVaSetValues(my_text,
437 DtNcursorPositionVisible, bval,
443 CDEM_DtWidgetEditor::set_columns(int ncolumns)
445 XtVaSetValues(my_text, DtNcolumns, ncolumns, NULL);
450 CDEM_DtWidgetEditor::set_rows(int nrows)
452 XtVaSetValues(my_text, DtNrows, nrows, NULL);
456 CDEM_DtWidgetEditor::undo_edit()
459 DtEditorUndoEdit(my_text);
464 CDEM_DtWidgetEditor::cut_selection()
467 DtEditorCutToClipboard(my_text);
472 CDEM_DtWidgetEditor::copy_selection()
475 DtEditorCopyToClipboard(my_text);
480 CDEM_DtWidgetEditor::paste_from_clipboard()
483 DtEditorPasteFromClipboard(my_text);
488 CDEM_DtWidgetEditor::paste_special_from_clipboard(
489 Editor::InsertFormat format
493 unsigned long length, recvd;
494 char *clipboard_data;
495 Display *dpy = XtDisplayOfObject(my_text);
496 Window window = XtWindowOfObject(my_text);
499 status = XmClipboardInquireLength(dpy, window, "STRING", &length);
500 } while (status == ClipboardLocked);
506 clipboard_data = XtMalloc((unsigned)length);
509 status = XmClipboardRetrieve(
510 dpy, window, "STRING", clipboard_data,
513 } while (status == ClipboardLocked);
515 if (status != ClipboardSuccess || recvd != length) {
518 XtFree(clipboard_data);
522 // Now modify the data such that the necessary formatting occurs
523 // within it. Bracketting will cause a line at the beginning and
524 // end of the data. Indenting will prepend a ">" before each line,
525 // realigning the lines if necessary.
526 // The results are stored in _modified_text so clipboard_data can
527 // be freed immediately after this call.
529 this->modifyData(clipboard_data, (unsigned) length, format);
530 XtFree(clipboard_data);
532 // Now copy the modified data stripped of CRLFs to a buffer.
533 // Put that buffer into the structure appropriate for DtEditor.
535 DtEditorContentRec rec;
537 rec.type = DtEDITOR_TEXT;
539 // Length needs to be reset since the text now contains
540 // new characters that do the necessary formatting.
542 length = _modified_text->length;
544 if ( _modified_text->ptr[(unsigned) length - 1] == 0 ) {
545 rec.value.string = (char *)_modified_text->ptr;
547 this->my_owner->needBuf(
549 (unsigned) length + 1
551 this->my_owner->stripCRLF(
552 &_buffer, _modified_text->ptr,
554 rec.value.string = _buffer;
557 DtEditorInsert(my_text, &rec);
562 CDEM_DtWidgetEditor::clear_selection()
565 DtEditorClearSelection(my_text);
570 CDEM_DtWidgetEditor::delete_selection()
572 DtEditorDeleteSelection(my_text);
576 CDEM_DtWidgetEditor::set_word_wrap(
580 XtVaSetValues(my_text, DtNwordWrap, bval, NULL);
584 CDEM_DtWidgetEditor::set_to_top()
586 XtVaSetValues(my_text,
588 DtNcursorPosition, 0,
594 CDEM_DtWidgetEditor::text_selected_callback(
601 CDEM_DtWidgetEditor *obj=(CDEM_DtWidgetEditor *) clientData;
603 obj->text_selected();
608 CDEM_DtWidgetEditor::text_unselected_callback(
615 CDEM_DtWidgetEditor *obj=(CDEM_DtWidgetEditor *) clientData;
617 obj->text_unselected();
622 CDEM_DtWidgetEditor::text_selected()
625 if (!text_already_selected) {
626 text_already_selected = TRUE;
627 my_owner->owner()->text_selected();
632 CDEM_DtWidgetEditor::text_unselected()
635 my_owner->owner()->text_unselected();
636 text_already_selected = FALSE;
641 CDEM_DtWidgetEditor::find_change()
643 DtEditorInvokeFindChangeDialog(my_text);
647 CDEM_DtWidgetEditor::spell()
649 DtEditorInvokeSpellDialog(my_text);
653 CDEM_DtWidgetEditor::format()
655 DtEditorInvokeFormatDialog(my_text);
659 CDEM_DtWidgetEditor::auto_show_cursor_off()
664 CDEM_DtWidgetEditor::auto_show_cursor_restore()
669 CDEM_DtWidgetEditor::select_all()
671 DtEditorSelectAll(my_text);
675 CDEM_DtWidgetEditor::set_to_bottom()
680 CDEM_DtWidgetEditor::no_text()
682 char *text = get_contents();
683 int text_len = strlen(text);
686 for ( int k = 0; k < text_len; k++ ) {
687 if ( isgraph(text[k]) ) {
698 CDEM_DtWidgetEditor::disable_redisplay()
700 DtEditorDisableRedisplay(my_text);
704 CDEM_DtWidgetEditor::enable_redisplay()
707 DtEditorEnableRedisplay(my_text);
714 * This fucntion modifies the pasted data
715 * with an indent prefix before each new line or brackets it.
719 CDEM_DtWidgetEditor::modifyData(
720 char *sp, // source pointer to the insert string
721 int length, // length does not include '\0' char
722 Editor::InsertFormat insert_format
725 if(_modified_text == NULL)
726 _modified_text = (XmTextBlockRec *)calloc(1,sizeof(XmTextBlockRec));
728 char *maxsp = sp + length; // maxmimum source ptr
730 // Allocate memory rounded off to the nearest BUFINC
731 size_t size_req = (size_t)(((length/BUFINC)+1)*BUFINC);
732 if((_modified_text_buflen < size_req) ||
733 ((_modified_text_buflen > CDEM_DtWidgetEditor::MAXBUFSZ) &&
734 (size_req < CDEM_DtWidgetEditor::MAXBUFSZ)) )
735 reallocPasteBuf(size_req);
737 if(_modified_text->ptr == NULL)
738 return; // No memory available
740 switch( insert_format) {
746 // Get the indent prefix string
747 DtMail::Session *m_session = theRoamApp.session()->session();
748 m_session->mailRc(error)->getValue(error,"indentprefix", &indent_str);
749 if (error.isSet() || NULL == indent_str)
750 indent_str = strdup("> ");
752 size_t indlen = strlen(indent_str);
754 // Copy the src buf into dest, inserting indent before '\n'
757 // Make sure there is enough space
758 // for an indent prefix, one char and a terminating '\0'
759 if(!((ip+indlen+2) < _modified_text_buflen) ) {
760 size_req = (size_t)((((_modified_text_buflen +
761 indlen+2)/BUFINC)+1)*BUFINC);
762 reallocPasteBuf(size_req);
763 if(_modified_text->ptr == NULL)
764 return; // No memory available
767 // Copy the indent string at the beginning
769 memcpy(_modified_text->ptr, indent_str, indlen);
773 // Copy the next byte and check for new line
774 _modified_text->ptr[ip++] = *sp++;
775 if(*(sp-1) == '\n') {
776 memcpy(&_modified_text->ptr[ip], indent_str, indlen);
781 _modified_text->ptr[ip] = '\0'; // terminate with a null char
782 _modified_text->length = ip; // Do not include '\0' char in len
788 if( !begin_ins_bracket)
789 begin_ins_bracket = GETMSG(DT_catd, 1, 201,
790 "\n------------- Begin Included Message -------------\n");
792 end_ins_bracket = GETMSG(DT_catd, 1, 202,
793 "\n------------- End Included Message -------------\n");
795 size_t begin_len = strlen(begin_ins_bracket);
796 size_t end_len = strlen(end_ins_bracket);
798 // Make sure there is enough space
799 if((size_req = length + begin_len + end_len + 1) >
800 _modified_text_buflen) {
801 size_req = (size_t) ((((size_req)/BUFINC)+1)*BUFINC);
802 reallocPasteBuf(size_req);
805 if(_modified_text->ptr == NULL)
808 strcpy(_modified_text->ptr, begin_ins_bracket);
809 strncat(_modified_text->ptr,sp,length);
810 strcat(_modified_text->ptr, end_ins_bracket);
811 _modified_text->length = end_len + begin_len + length;
820 CDEM_DtWidgetEditor::MenuButtonHandler(
826 CDEM_DtWidgetEditor *obj = (CDEM_DtWidgetEditor *)cd;
828 if(event->xany.type != ButtonPress)
831 XButtonEvent *be = (XButtonEvent *)event;
833 if(be->button == Button3)
834 obj->my_owner->owner()->postTextPopup(event);