Files
cdesktop/cde/programs/dtmail/dtmail/DtMailEditor.C
2012-03-10 18:58:32 +00:00

603 lines
14 KiB
C

/*
* CDE - Common Desktop Environment
*
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
*
* These libraries and programs are free software; you can
* redistribute them and/or modify them under the terms of the GNU
* Lesser General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* These libraries and programs are distributed in the hope that
* they will be useful, but WITHOUT ANY WARRANTY; without even the
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
* PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with these librararies and programs; if not, write
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301 USA
*/
/*
*+SNOTICE
*
* $TOG: DtMailEditor.C /main/10 1998/07/24 16:05:41 mgreess $
*
* RESTRICTED CONFIDENTIAL INFORMATION:
*
* The information in this document is subject to special
* restrictions in a confidential disclosure agreement between
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
* document outside HP, IBM, Sun, USL, SCO, or Univel without
* Sun's specific written approval. This document and all copies
* and derivative works thereof must be returned or destroyed at
* Sun's request.
*
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
*
*+ENOTICE
*/
#ifndef I_HAVE_NO_IDENT
#else
#endif
#include <Xm/Form.h>
#include <Xm/SeparatoG.h>
#include <Dt/Dnd.h>
#include "DtMailEditor.hh"
#include "XmTextEditor.h"
#include "AttachArea.h"
#include "Attachment.h"
#ifdef DTEDITOR
#include "DtEditor.hh"
#endif
#include "EUSDebug.hh"
extern "C" {
extern XtPointer _XmStringUngenerate (
XmString string,
XmStringTag tag,
XmTextType tag_type,
XmTextType output_type);
}
#ifndef ABS
#define ABS(x) (((x) > 0) ? (x) : (-(x)))
#endif
#ifndef DRAG_THRESHOLD
#define DRAG_THRESHOLD 4
#endif
DtMailEditor::DtMailEditor(
Widget parent,
AbstractEditorParent *owner
) : UIComponent("DtMailEditor")
{
_myOwner = owner;
// Create a manager widget (say a form) and set it to the private
// variable _container. Parent private instances to this widget.
// Expose only _container externally (for attachment stuff...)
_w = XmCreateForm(parent, "DtMailEditor", NULL, 0);
installDestroyHandler();
#ifdef DTEDITOR
if ( use_XmTextEditor ) {
_myTextEditor = new XmTextEditor(_w, this);
} else {
_myTextEditor = new CDEM_DtWidgetEditor(_w, this);
}
#else
_myTextEditor = new XmTextEditor(_w, this);
#endif
_myAttachArea = new AttachArea(_w, this, "AttachPane");
_showAttachArea = TRUE;
_doingDrag = FALSE;
_separator = NULL;
_msgHandle = NULL;
_dragX = -1;
_dragY = -1;
_editable = FALSE;
}
DtMailEditor::~DtMailEditor()
{
unmanageAttachArea();
delete _myAttachArea;
delete _myTextEditor;
}
void
DtMailEditor::initialize()
{
Widget editor_widget;
_myTextEditor->initialize();
_separator = XtVaCreateManagedWidget("Sep1",
xmSeparatorGadgetClass,
_w,
XmNtopOffset, 1,
XmNbottomOffset, 1,
XmNrightAttachment, XmATTACH_FORM,
XmNleftAttachment, XmATTACH_FORM,
NULL);
// Create an *UNMANAGED* attachArea.
// If the message has an attachment, the DtMailEditor instance
// will receive a manageAttachArea where it will adjust the
// attachments and manage the attachArea accordingly
_myAttachArea->initialize();
attachDropRegister();
if (!_editable)
attachDropDisable();
editor_widget = _myTextEditor->get_editor();
XtVaSetValues(editor_widget,
XmNtopAttachment,XmATTACH_FORM,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, _separator,
XmNrightAttachment,XmATTACH_FORM,
XmNrightOffset, 4,
XmNleftAttachment,XmATTACH_FORM,
XmNleftOffset, 3,
NULL );
XtVaSetValues(_myAttachArea->baseWidget(),
XmNrightAttachment, XmATTACH_FORM,
XmNrightOffset, 3,
XmNleftAttachment, XmATTACH_FORM,
XmNleftOffset, 5,
XmNbottomAttachment, XmATTACH_FORM,
NULL);
XtVaSetValues(_separator,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, _myAttachArea->baseWidget(),
NULL);
// Unmanage the attachArea. If a message has attachments,
// manageAttachArea() will get called by the consumer of this
// class.
this->unmanageAttachArea();
XtManageChild(_w);
}
AbstractEditorParent *
DtMailEditor::owner()
{
return (_myOwner);
}
Editor*
DtMailEditor::textEditor()
{
return(_myTextEditor);
}
AttachArea*
DtMailEditor::attachArea()
{
return(_myAttachArea);
}
Widget
DtMailEditor::container()
{
return(_w);
}
void
DtMailEditor::setEditable(Boolean bval)
{
textEditor()->set_editable(bval);
_editable = bval;
if (_editable)
attachDropEnable();
else
attachDropDisable();
}
void
DtMailEditor::manageAttachArea()
{
if (!_showAttachArea && (_myAttachArea->getIconCount() == 0)) {
return;
}
_myAttachArea->manage();
XtManageChild(_separator);
Widget editor_widget = _myTextEditor->get_editor();
XtVaSetValues(editor_widget,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, _separator,
NULL );
XtVaSetValues(_separator,
XmNbottomAttachment, XmATTACH_WIDGET,
XmNbottomWidget, _myAttachArea->baseWidget(),
NULL);
XtVaSetValues(_myAttachArea->baseWidget(),
XmNbottomAttachment, XmATTACH_FORM,
NULL);
}
void
DtMailEditor::unmanageAttachArea()
{
// Already unmanaged?
if (!XtIsManaged(_myAttachArea->baseWidget())) return;
Widget editor_widget = _myTextEditor->get_editor();
XtVaSetValues(editor_widget,
XmNbottomAttachment, XmATTACH_FORM,
NULL );
_myAttachArea->unmanage();
XtUnmanageChild(_separator);
}
// Initialize _msgHandle
void
DtMailEditor::setMsgHnd(DtMail::Message * msgHandle)
{
_msgHandle = msgHandle;
}
// attachTransferCallback
//
// Handles the transfer of data that is dropped on the attachment list.
// The data is turned into an attachment and appended to the list.
//
void
DtMailEditor::attachTransferCallback(
Widget /* widget */,
XtPointer client_data,
XtPointer call_data)
{
DtDndTransferCallbackStruct *transferInfo =
(DtDndTransferCallbackStruct *) call_data;
DtDndContext *dropData = transferInfo->dropData;
int numItems = dropData->numItems, ii;
DtMailEditor *editor = (DtMailEditor *) client_data;
DtMailEnv mail_error;
DtMailBuffer buf;
char *attachname;
DebugPrintf(3, "In DtMailEditor::attachTransferCallback\n");
// Initialize mail_error.
mail_error.clear();
switch (transferInfo->dropData->protocol) {
case DtDND_FILENAME_TRANSFER:
// Loop through the dropped files and turn each
// into an attachment.
for (ii = 0; ii < numItems; ii++) {
editor->owner()->add_att(dropData->data.files[ii]);
}
break;
case DtDND_BUFFER_TRANSFER:
// Loop through the dropped buffers and turn each
// into an attachment.
for (ii = 0; ii < numItems; ii++) {
buf.buffer = (char *)dropData->data.buffers[ii].bp;
buf.size = (unsigned long)dropData->data.buffers[ii].size;
attachname = dropData->data.buffers[ii].name;
if (!attachname)
attachname = "Untitled";
editor->owner()->add_att(attachname, buf);
}
break;
default:
transferInfo->status = DtDND_FAILURE;
return;
}
}
// attachDropRegister
//
// Register the attachment list to accept drops of buffer and files
//
void
DtMailEditor::attachDropRegister()
{
static XtCallbackRec transferCBRec[] = {
{&DtMailEditor::attachTransferCallback, NULL}, {NULL, NULL} };
// Pass the DtMailEditor object (this) as clientData.
transferCBRec[0].closure = (XtPointer) this;
DtDndVaDropRegister(_myAttachArea->baseWidget(),
DtDND_FILENAME_TRANSFER | DtDND_BUFFER_TRANSFER,
(unsigned char)(XmDROP_COPY), transferCBRec,
DtNtextIsBuffer, TRUE,
NULL);
}
// attachDropEnable
//
// Enable the attachment list for drops by restoring the operation
//
void
DtMailEditor::attachDropEnable()
{
Arg args[1];
XtSetArg(args[0], XmNdropSiteOperations, XmDROP_MOVE | XmDROP_COPY);
XmDropSiteUpdate(_myAttachArea->baseWidget(), args, 1);
}
// attachDropDisable
//
// Disable the attachment list for drops by setting the operation to noop
//
void
DtMailEditor::attachDropDisable()
{
Arg args[1];
XtSetArg(args[0], XmNdropSiteOperations, XmDROP_NOOP);
XmDropSiteUpdate(_myAttachArea->baseWidget(), args, 1);
}
// attachConvertCallback
//
// Provides the selected attachments for the drag
//
void
DtMailEditor::attachConvertCallback(
Widget /* dragContext */,
XtPointer clientData,
XtPointer callData)
{
DtDndConvertCallbackStruct *convertInfo =
(DtDndConvertCallbackStruct *) callData;
DtDndBuffer *buffers = convertInfo->dragData->data.buffers;
DtMailEditor *editor = (DtMailEditor *) clientData;
int numIcons = editor->attachArea()->getIconCount();
Attachment **list = editor->attachArea()->getList();
int ii, current = 0;
char *name = NULL;
XmString str;
DtMailEnv mail_error;
DebugPrintf(3, "In DtMailEditor::attachConvertCallback\n");
switch(convertInfo->reason) {
case DtCR_DND_CONVERT_DATA:
for (ii = 0; ii < numIcons; ii++) {
if (!list[ii]->isDeleted() && list[ii]->isSelected()) {
buffers[current].bp = list[ii]->getContents();
buffers[current].size = (int)list[ii]->getContentsSize();
str = list[ii]->getLabel();
buffers[current].name =
(char *) _XmStringUngenerate(
str, NULL,
XmMULTIBYTE_TEXT, XmMULTIBYTE_TEXT);
XmStringFree(str);
current++;
}
}
break;
case DtCR_DND_CONVERT_DELETE:
editor->attachArea()->deleteSelectedAttachments(mail_error);
break;
default:
convertInfo->status = DtDND_FAILURE;
}
}
// attachDragFinishCallback
//
// Clean up from the convert callback and restore state
//
void
DtMailEditor::attachDragFinishCallback(
Widget /* widget */,
XtPointer clientData,
XtPointer callData)
{
DtDndDragFinishCallbackStruct *finishInfo =
(DtDndDragFinishCallbackStruct *) callData;
DtDndContext *dragData = finishInfo->dragData;
DtMailEditor *editor = (DtMailEditor *) clientData;
int ii;
DebugPrintf(3, "In DtMailEditor::attachDragFinishCallback\n");
editor->setDoingDrag(FALSE);
editor->setDragX(-1);
editor->setDragY(-1);
if (editor->editable())
editor->attachDropEnable();
for (ii = 0; ii < dragData->numItems; ii++) {
XtFree((char *)dragData->data.buffers[ii].name);
}
}
void
DtMailEditor::attachDragStart( Widget widget,
XEvent *event)
{
static XtCallbackRec convertCBRec[] = {
{&DtMailEditor::attachConvertCallback, NULL}, {NULL, NULL} };
static XtCallbackRec dragFinishCBRec[] = {
{&DtMailEditor::attachDragFinishCallback, NULL}, {NULL, NULL} };
int itemCount;
unsigned char operations;
convertCBRec[0].closure = (XtPointer) this;
dragFinishCBRec[0].closure = (XtPointer) this;
attachDropDisable();
// Count the number of items to be dragged.
itemCount = attachArea()->getSelectedIconCount();
setDoingDrag(TRUE);
if (editable()) {
operations = (unsigned char)(XmDROP_COPY | XmDROP_MOVE);
} else {
operations = (unsigned char)(XmDROP_COPY);
}
if (DtDndVaDragStart(widget, event, DtDND_BUFFER_TRANSFER, itemCount,
operations, convertCBRec, dragFinishCBRec,
// DtNsourceIcon, dragIcon,
NULL)
== NULL) {
DebugPrintf(3, "DragStart returned NULL.\n");
}
}
void
DtMailEditor::attachDragMotionHandler(
Widget widget,
XEvent *event)
{
int diffX, diffY;
if (!doingDrag()) {
// If the drag is just starting, set initial button down coordinates.
if (dragX() == -1 && dragY() == -1) {
setDragX(event->xmotion.x);
setDragY(event->xmotion.y);
}
// Find out how far the pointer has moved since the button press.
diffX = dragX() - event->xmotion.x;
diffY = dragY() - event->xmotion.y;
if ((ABS(diffX) >= DRAG_THRESHOLD) ||
(ABS(diffY) >= DRAG_THRESHOLD)) {
attachDragStart(widget, event);
}
}
}
#ifdef notdef
void
DtMailEditor::attachDragSetup()
{
Boolean btn1_transfer;
Widget widget = _myAttachArea->baseWidget();
DebugPrintf(3, "In DtMailEditor::attachDragSetup()\n");
XtAddEventHandler(widget, Button1MotionMask, FALSE,
(XtEventHandler)&DtMailEditor::attachDragMotionHandler,
(XtPointer)this);
XtVaGetValues(
(Widget)XmGetXmDisplay(XtDisplayOfObject(widget)),
"enableBtn1Transfer", &btn1_transfer,
NULL);
if (!btn1_transfer) {
XtAddEventHandler(widget, Button2MotionMask, FALSE,
(XtEventHandler)&DtMailEditor::attachDragMotionHandler,
(XtPointer)this);
}
}
#endif
void
DtMailEditor::stripCRLF(char **buffer, const char * buf, const unsigned long len)
{
char * out = *buffer;
int _len;
for (const char * in = buf; in < (buf + len);) {
_len = mblen( in, MB_CUR_MAX );
if ( _len <= 0 )
break;
if ( ( _len == 1 ) && ( *in == '\r' ) ){
in += 1;
continue;
}
strncpy( out, in, _len );
out += _len, in += _len;
}
*out = 0;
}
void
DtMailEditor::needBuf(char **buffer, unsigned long *buflen, unsigned long newlen)
{
if (newlen > *buflen) {
// Need a bigger buffer.
if (*buffer) {
delete [] *buffer;
}
*buffer = new char[newlen];
*buflen = newlen;
} else {
// Clear buffer content -- get ready for new data
if (*buffer) {
memset(*buffer, 0, (unsigned int)*buflen);
}
}
}
void
DtMailEditor::showAttachArea()
{
_showAttachArea = TRUE;
this->manageAttachArea();
}
void
DtMailEditor::hideAttachArea()
{
_showAttachArea = FALSE;
this->unmanageAttachArea();
}