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: DtMailEditor.C /main/10 1998/07/24 16:05:41 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
48 #include <Xm/SeparatoG.h>
50 #include "DtMailEditor.hh"
51 #include "XmTextEditor.h"
52 #include "AttachArea.h"
53 #include "Attachment.h"
55 #include "DtEditor.hh"
58 #include "EUSDebug.hh"
62 extern XtPointer _XmStringUngenerate (
66 XmTextType output_type);
70 #define ABS(x) (((x) > 0) ? (x) : (-(x)))
73 #ifndef DRAG_THRESHOLD
74 #define DRAG_THRESHOLD 4
77 DtMailEditor::DtMailEditor(
79 AbstractEditorParent *owner
80 ) : UIComponent("DtMailEditor")
84 // Create a manager widget (say a form) and set it to the private
85 // variable _container. Parent private instances to this widget.
86 // Expose only _container externally (for attachment stuff...)
88 _w = XmCreateForm(parent, "DtMailEditor", NULL, 0);
89 installDestroyHandler();
92 if ( use_XmTextEditor ) {
93 _myTextEditor = new XmTextEditor(_w, this);
95 _myTextEditor = new CDEM_DtWidgetEditor(_w, this);
98 _myTextEditor = new XmTextEditor(_w, this);
101 _myAttachArea = new AttachArea(_w, this, "AttachPane");
103 _showAttachArea = TRUE;
114 DtMailEditor::~DtMailEditor()
116 unmanageAttachArea();
117 delete _myAttachArea;
118 delete _myTextEditor;
122 DtMailEditor::initialize()
125 Widget editor_widget;
127 _myTextEditor->initialize();
129 _separator = XtVaCreateManagedWidget("Sep1",
130 xmSeparatorGadgetClass,
134 XmNrightAttachment, XmATTACH_FORM,
135 XmNleftAttachment, XmATTACH_FORM,
138 // Create an *UNMANAGED* attachArea.
139 // If the message has an attachment, the DtMailEditor instance
140 // will receive a manageAttachArea where it will adjust the
141 // attachments and manage the attachArea accordingly
143 _myAttachArea->initialize();
145 attachDropRegister();
149 editor_widget = _myTextEditor->get_editor();
151 XtVaSetValues(editor_widget,
152 XmNtopAttachment,XmATTACH_FORM,
153 XmNbottomAttachment, XmATTACH_WIDGET,
154 XmNbottomWidget, _separator,
155 XmNrightAttachment,XmATTACH_FORM,
157 XmNleftAttachment,XmATTACH_FORM,
161 XtVaSetValues(_myAttachArea->baseWidget(),
162 XmNrightAttachment, XmATTACH_FORM,
164 XmNleftAttachment, XmATTACH_FORM,
166 XmNbottomAttachment, XmATTACH_FORM,
169 XtVaSetValues(_separator,
170 XmNbottomAttachment, XmATTACH_WIDGET,
171 XmNbottomWidget, _myAttachArea->baseWidget(),
174 // Unmanage the attachArea. If a message has attachments,
175 // manageAttachArea() will get called by the consumer of this
178 this->unmanageAttachArea();
184 AbstractEditorParent *
185 DtMailEditor::owner()
191 DtMailEditor::textEditor()
193 return(_myTextEditor);
197 DtMailEditor::attachArea()
199 return(_myAttachArea);
203 DtMailEditor::container()
209 DtMailEditor::setEditable(Boolean bval)
211 textEditor()->set_editable(bval);
220 DtMailEditor::manageAttachArea()
223 if (!_showAttachArea && (_myAttachArea->getIconCount() == 0)) {
227 _myAttachArea->manage();
228 XtManageChild(_separator);
230 Widget editor_widget = _myTextEditor->get_editor();
232 XtVaSetValues(editor_widget,
233 XmNbottomAttachment, XmATTACH_WIDGET,
234 XmNbottomWidget, _separator,
237 XtVaSetValues(_separator,
238 XmNbottomAttachment, XmATTACH_WIDGET,
239 XmNbottomWidget, _myAttachArea->baseWidget(),
242 XtVaSetValues(_myAttachArea->baseWidget(),
243 XmNbottomAttachment, XmATTACH_FORM,
249 DtMailEditor::unmanageAttachArea()
252 // Already unmanaged?
253 if (!XtIsManaged(_myAttachArea->baseWidget())) return;
255 Widget editor_widget = _myTextEditor->get_editor();
257 XtVaSetValues(editor_widget,
258 XmNbottomAttachment, XmATTACH_FORM,
261 _myAttachArea->unmanage();
263 XtUnmanageChild(_separator);
267 // Initialize _msgHandle
269 DtMailEditor::setMsgHnd(DtMail::Message * msgHandle)
271 _msgHandle = msgHandle;
274 // attachTransferCallback
276 // Handles the transfer of data that is dropped on the attachment list.
277 // The data is turned into an attachment and appended to the list.
280 DtMailEditor::attachTransferCallback(
282 XtPointer client_data,
285 DtDndTransferCallbackStruct *transferInfo =
286 (DtDndTransferCallbackStruct *) call_data;
287 DtDndContext *dropData = transferInfo->dropData;
288 int numItems = dropData->numItems, ii;
289 DtMailEditor *editor = (DtMailEditor *) client_data;
290 DtMailEnv mail_error;
294 DebugPrintf(3, "In DtMailEditor::attachTransferCallback\n");
296 // Initialize mail_error.
299 switch (transferInfo->dropData->protocol) {
301 case DtDND_FILENAME_TRANSFER:
303 // Loop through the dropped files and turn each
304 // into an attachment.
306 for (ii = 0; ii < numItems; ii++) {
307 editor->owner()->add_att(dropData->data.files[ii]);
311 case DtDND_BUFFER_TRANSFER:
313 // Loop through the dropped buffers and turn each
314 // into an attachment.
316 for (ii = 0; ii < numItems; ii++) {
318 buf.buffer = (char *)dropData->data.buffers[ii].bp;
319 buf.size = (unsigned long)dropData->data.buffers[ii].size;
320 attachname = dropData->data.buffers[ii].name;
323 attachname = "Untitled";
325 editor->owner()->add_att(attachname, buf);
330 transferInfo->status = DtDND_FAILURE;
336 // attachDropRegister
338 // Register the attachment list to accept drops of buffer and files
341 DtMailEditor::attachDropRegister()
343 static XtCallbackRec transferCBRec[] = {
344 {&DtMailEditor::attachTransferCallback, NULL}, {NULL, NULL} };
346 // Pass the DtMailEditor object (this) as clientData.
347 transferCBRec[0].closure = (XtPointer) this;
349 DtDndVaDropRegister(_myAttachArea->baseWidget(),
350 DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
351 (unsigned char)(XmDROP_COPY), transferCBRec,
352 DtNtextIsBuffer, TRUE,
358 // Enable the attachment list for drops by restoring the operation
361 DtMailEditor::attachDropEnable()
365 XtSetArg(args[0], XmNdropSiteOperations, XmDROP_MOVE | XmDROP_COPY);
366 XmDropSiteUpdate(_myAttachArea->baseWidget(), args, 1);
371 // Disable the attachment list for drops by setting the operation to noop
374 DtMailEditor::attachDropDisable()
378 XtSetArg(args[0], XmNdropSiteOperations, XmDROP_NOOP);
379 XmDropSiteUpdate(_myAttachArea->baseWidget(), args, 1);
382 // attachConvertCallback
384 // Provides the selected attachments for the drag
387 DtMailEditor::attachConvertCallback(
388 Widget /* dragContext */,
389 XtPointer clientData,
392 DtDndConvertCallbackStruct *convertInfo =
393 (DtDndConvertCallbackStruct *) callData;
394 DtDndBuffer *buffers = convertInfo->dragData->data.buffers;
395 DtMailEditor *editor = (DtMailEditor *) clientData;
396 int numIcons = editor->attachArea()->getIconCount();
397 Attachment **list = editor->attachArea()->getList();
401 DtMailEnv mail_error;
404 DebugPrintf(3, "In DtMailEditor::attachConvertCallback\n");
406 switch(convertInfo->reason) {
407 case DtCR_DND_CONVERT_DATA:
408 for (ii = 0; ii < numIcons; ii++) {
409 if (!list[ii]->isDeleted() && list[ii]->isSelected()) {
410 buffers[current].bp = list[ii]->getContents();
411 buffers[current].size = (int)list[ii]->getContentsSize();
412 str = list[ii]->getLabel();
413 buffers[current].name =
414 (char *) _XmStringUngenerate(
416 XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
423 case DtCR_DND_CONVERT_DELETE:
424 editor->attachArea()->deleteSelectedAttachments(mail_error);
428 convertInfo->status = DtDND_FAILURE;
432 // attachDragFinishCallback
434 // Clean up from the convert callback and restore state
437 DtMailEditor::attachDragFinishCallback(
439 XtPointer clientData,
442 DtDndDragFinishCallbackStruct *finishInfo =
443 (DtDndDragFinishCallbackStruct *) callData;
444 DtDndContext *dragData = finishInfo->dragData;
445 DtMailEditor *editor = (DtMailEditor *) clientData;
448 DebugPrintf(3, "In DtMailEditor::attachDragFinishCallback\n");
450 editor->setDoingDrag(FALSE);
451 editor->setDragX(-1);
452 editor->setDragY(-1);
454 if (editor->editable())
455 editor->attachDropEnable();
457 for (ii = 0; ii < dragData->numItems; ii++) {
458 XtFree((char *)dragData->data.buffers[ii].name);
463 DtMailEditor::attachDragStart( Widget widget,
466 static XtCallbackRec convertCBRec[] = {
467 {&DtMailEditor::attachConvertCallback, NULL}, {NULL, NULL} };
468 static XtCallbackRec dragFinishCBRec[] = {
469 {&DtMailEditor::attachDragFinishCallback, NULL}, {NULL, NULL} };
471 unsigned char operations;
473 convertCBRec[0].closure = (XtPointer) this;
474 dragFinishCBRec[0].closure = (XtPointer) this;
478 // Count the number of items to be dragged.
479 itemCount = attachArea()->getSelectedIconCount();
484 operations = (unsigned char)(XmDROP_COPY | XmDROP_MOVE);
486 operations = (unsigned char)(XmDROP_COPY);
489 if (DtDndVaDragStart(widget, event, DtDND_BUFFER_TRANSFER, itemCount,
490 operations, convertCBRec, dragFinishCBRec,
491 // DtNsourceIcon, dragIcon,
495 DebugPrintf(3, "DragStart returned NULL.\n");
500 DtMailEditor::attachDragMotionHandler(
507 // If the drag is just starting, set initial button down coordinates.
508 if (dragX() == -1 && dragY() == -1) {
509 setDragX(event->xmotion.x);
510 setDragY(event->xmotion.y);
513 // Find out how far the pointer has moved since the button press.
514 diffX = dragX() - event->xmotion.x;
515 diffY = dragY() - event->xmotion.y;
517 if ((ABS(diffX) >= DRAG_THRESHOLD) ||
518 (ABS(diffY) >= DRAG_THRESHOLD)) {
519 attachDragStart(widget, event);
526 DtMailEditor::attachDragSetup()
528 Boolean btn1_transfer;
529 Widget widget = _myAttachArea->baseWidget();
531 DebugPrintf(3, "In DtMailEditor::attachDragSetup()\n");
533 XtAddEventHandler(widget, Button1MotionMask, FALSE,
534 (XtEventHandler)&DtMailEditor::attachDragMotionHandler,
538 (Widget)XmGetXmDisplay(XtDisplayOfObject(widget)),
539 "enableBtn1Transfer", &btn1_transfer,
542 if (!btn1_transfer) {
543 XtAddEventHandler(widget, Button2MotionMask, FALSE,
544 (XtEventHandler)&DtMailEditor::attachDragMotionHandler,
551 DtMailEditor::stripCRLF(char **buffer, const char * buf, const unsigned long len)
553 char * out = *buffer;
557 for (const char * in = buf; in < (buf + len);) {
558 _len = mblen( in, MB_CUR_MAX );
561 if ( ( _len == 1 ) && ( *in == '\r' ) ){
565 strncpy( out, in, _len );
566 out += _len, in += _len;
572 DtMailEditor::needBuf(char **buffer, unsigned long *buflen, unsigned long newlen)
574 if (newlen > *buflen) {
575 // Need a bigger buffer.
580 *buffer = new char[newlen];
583 // Clear buffer content -- get ready for new data
585 memset(*buffer, 0, (unsigned int)*buflen);
591 DtMailEditor::showAttachArea()
593 _showAttachArea = TRUE;
594 this->manageAttachArea();
599 DtMailEditor::hideAttachArea()
601 _showAttachArea = FALSE;
602 this->unmanageAttachArea();