mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 12:37:37 +00:00
2180 lines
58 KiB
C++
2180 lines
58 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
|
*
|
|
* The contents of this file are subject to the Netscape Public License
|
|
* Version 1.0 (the "NPL"); you may not use this file except in
|
|
* compliance with the NPL. You may obtain a copy of the NPL at
|
|
* http://www.mozilla.org/NPL/
|
|
*
|
|
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
|
* for the specific language governing rights and limitations under the
|
|
* NPL.
|
|
*
|
|
* The Initial Developer of this code under the NPL is Netscape
|
|
* Communications Corporation. Portions created by Netscape are
|
|
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
|
* Reserved.
|
|
*/
|
|
/*
|
|
AddressOutliner.cpp -- Object wrapper around outline widget hack.
|
|
Created: Dora Hsu <dora@netscape.com>, Sept-30-96.
|
|
*/
|
|
|
|
|
|
|
|
#include "AddressOutliner.h"
|
|
|
|
#include "xp_core.h"
|
|
#include "ComposeView.h"
|
|
#include "ComposeFolderView.h"
|
|
#include "AddressFolderView.h"
|
|
#include "PopupMenu.h"
|
|
|
|
#if defined(USE_ABCOM)
|
|
#include "Frame.h"
|
|
#endif /* USE_ABCOM */
|
|
|
|
#include "xfe.h"
|
|
|
|
#include <Xfe/Xfe.h>
|
|
|
|
#include <Xm/TextF.h>
|
|
#include "felocale.h"
|
|
extern XtAppContext fe_XtAppContext;
|
|
|
|
#ifdef DEBUG_dora
|
|
#define XDEBUG(x) x
|
|
#else
|
|
#define XDEBUG(x)
|
|
#endif
|
|
|
|
extern int MSG_TotalHeaderCount();
|
|
extern MSG_HEADER_SET MSG_HeaderValue( int pos );
|
|
|
|
extern "C"
|
|
{
|
|
|
|
XP_List* FE_GetDirServers();
|
|
ABook* fe_GetABook(MWContext *context);
|
|
|
|
static void KeyIn(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *nparam);
|
|
|
|
static void TableTraverse(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *nparam);
|
|
|
|
static void FieldTraverse(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *nparam);
|
|
}
|
|
|
|
extern "C" char* xfe_ExpandForNameCompletion(char *pString,
|
|
ABook *pAddrBook,
|
|
DIR_Server *pDirServer);
|
|
|
|
#if defined(USE_ABCOM)
|
|
/* C API
|
|
*/
|
|
extern "C" XFE_ABComplPickerDlg*
|
|
fe_showComplPickerDlg(Widget toplevel,
|
|
MWContext *context,
|
|
MSG_Pane *pane,
|
|
MWContext *pickerContext,
|
|
NCPickerExitFunc func,
|
|
void *callData);
|
|
|
|
#endif /* USE_ABCOM */
|
|
|
|
const char *XFE_AddressOutliner::textFocusIn = "XFE_AddressOutliner::textFocusIn";
|
|
const char *XFE_AddressOutliner::typeFocusIn = "XFE_AddressOutliner::typeFocusIn";
|
|
const char *XFE_AddressOutliner::tabPrev = "XFE_AddressOutliner::tabPrev";
|
|
const char *XFE_AddressOutliner::tabNext = "XFE_AddressOutliner::tabNext";
|
|
|
|
// Customized Traversal Actions
|
|
|
|
static XtActionsRec actions[] =
|
|
{ {"TableTraverse", TableTraverse },
|
|
{"FieldTraverse", FieldTraverse },
|
|
{"KeyIn", KeyIn }};
|
|
|
|
// XFE_AddressOutliner Constructor -----------------------------------------
|
|
|
|
XFE_AddressOutliner::XFE_AddressOutliner(
|
|
const char *name,
|
|
XFE_MNListView *parent_view,
|
|
MAddressable *addressable_view,
|
|
Widget widget_parent,
|
|
Boolean constantSize,
|
|
int numcolumns,
|
|
int *column_widths,
|
|
char *pos_prefname) :
|
|
XFE_Outliner(name, parent_view, parent_view->getToplevel(),
|
|
widget_parent,
|
|
constantSize, False,
|
|
numcolumns, numcolumns, column_widths, pos_prefname )
|
|
{
|
|
Widget baseWidget;
|
|
XmFontList fontList;
|
|
Pixel fg, bg;
|
|
EventMask event_mask = FocusChangeMask|ButtonPressMask | ButtonReleaseMask;
|
|
|
|
m_displayrows = 4; /* same default number of rows as windows */
|
|
m_parentView = parent_view;
|
|
m_addressable = addressable_view;
|
|
m_popup = NULL;
|
|
m_focusRow = 0;
|
|
m_focusCol = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT;
|
|
m_cursorPos = 0;
|
|
m_inPopup = False;
|
|
m_lastFocus = NULL; /* Obselete ?! - dh */
|
|
m_textTimer = 0;
|
|
#if defined(USE_ABCOM)
|
|
m_pickerPane = 0;
|
|
XFE_Frame *f = (XFE_Frame *) parent_view->getToplevel();
|
|
XP_ASSERT(f);
|
|
m_pickerContext =
|
|
XFE_ABComplPickerDlg::cloneCntxtNcreatePane(f->getContext(),
|
|
&m_pickerPane);
|
|
m_pickerDlg = 0;
|
|
|
|
m_rtnIsPicker = False;
|
|
#endif /* USE_ABCOM */
|
|
|
|
#if !defined(USE_ABCOM)
|
|
// get the list of directory servers & address books
|
|
XP_List *pDirectories=FE_GetDirServers();
|
|
XP_ASSERT(pDirectories);
|
|
|
|
DIR_GetComposeNameCompletionAddressBook(pDirectories, &m_pCompleteServer);
|
|
|
|
m_pAddrBook = fe_GetABook(0);
|
|
#endif /* USE_ABCOM */
|
|
|
|
// Add actions
|
|
XtAppAddActions( fe_XtAppContext, actions, 3);
|
|
|
|
XtVaGetValues(m_widget, XmNfontList, &fontList,
|
|
XmNforeground, &fg,
|
|
XmNbackground, &bg, 0 );
|
|
|
|
m_typeWidget = XtVaCreateWidget("addressText",
|
|
xmTextFieldWidgetClass, m_widget,
|
|
XmNfontList, fontList,
|
|
XmNforeground, fg,
|
|
XmNbackground, bg,
|
|
XmNuserData, this,
|
|
XmNcursorPositionVisible, False,
|
|
XmNeditable, False,
|
|
XmNmarginHeight, 0,
|
|
XmNmarginWidth, 3,
|
|
XmNshadowThickness, 0,
|
|
XmNhighlightThickness, 2,
|
|
XmNx, 0,
|
|
XmNy, 0,
|
|
XmNwidth, 40,
|
|
XmNheight, 40,
|
|
0 );
|
|
XmDropSiteUnregister(m_typeWidget); // prevent conflict with attachment dropsite
|
|
|
|
m_textWidget = XtVaCreateWidget("addressText",
|
|
xmTextFieldWidgetClass, m_widget,
|
|
XmNblinkRate, 200,
|
|
XmNcursorPositionVisible, True,
|
|
XmNtraversalOn, True,
|
|
XmNeditable, True,
|
|
XmNforeground, fg,
|
|
XmNbackground, bg,
|
|
XmNfontList, fontList,
|
|
XmNuserData, this,
|
|
XmNmarginHeight, 0,
|
|
XmNmarginWidth, 3,
|
|
XmNshadowThickness, 0,
|
|
XmNhighlightThickness, 2,
|
|
XmNx, 0,
|
|
XmNy, 0,
|
|
XmNwidth, 40,
|
|
XmNheight, 40,
|
|
0);
|
|
XtVaSetValues(m_widget,
|
|
XmNuserData, this,
|
|
XmNhighlightRowMode, False,
|
|
XmNselectionPolicy, XmSELECT_NONE,
|
|
XmNvisibleRows, m_displayrows,
|
|
XmNcellMarginLeft, 1,
|
|
XmNcellMarginRight, 1,
|
|
XmNcellRightBorderType, XmBORDER_DASH,
|
|
XmNcellBottomBorderType, XmBORDER_DASH,
|
|
XtVaTypedArg, XmNcellBackground, XmRString, "white", 6,
|
|
XtVaTypedArg, XmNcellRightBorderColor, XmRString, "Gray60", 7,
|
|
XtVaTypedArg, XmNcellBottomBorderColor, XmRString, "Gray60", 7,
|
|
XmNcellDefaults, True,
|
|
XmNcellAlignment, XmALIGNMENT_LEFT,
|
|
0);
|
|
XmDropSiteUnregister(m_textWidget); // prevent conflict with attachment dropsite
|
|
|
|
XmProcessTraversal(m_widget, XmTRAVERSE_CURRENT);
|
|
int total = 0;
|
|
|
|
if (m_addressable)
|
|
total = ((XFE_AddressFolderView*)m_addressable)->getTotalData();
|
|
|
|
change(0,0 ,total+1 );
|
|
|
|
//MapText(0);
|
|
|
|
getToplevel()->registerInterest(XFE_Component::afterRealizeCallback,
|
|
this,
|
|
(XFE_FunctionNotification)afterRealizeWidget_cb);
|
|
// Translations will be installed in the afterRealize routine,
|
|
// so that they will override XFE_Frame::hackTranslations.
|
|
|
|
baseWidget = m_parentView->getParent()->getBaseWidget();
|
|
|
|
XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
|
|
|
|
XtAddCallback(m_widget, XmNscrollCallback, scrollCallback, this);
|
|
XtAddCallback(m_textWidget, XmNactivateCallback, textActivateCallback, this);
|
|
|
|
XtAddCallback(m_typeWidget, XmNfocusCallback, typeFocusCallback, this);
|
|
XtAddCallback(m_textWidget, XmNfocusCallback, textFocusCallback, this);
|
|
|
|
XtAddCallback(m_typeWidget, XmNlosingFocusCallback, textLosingFocusCallback, this);
|
|
XtAddCallback(m_textWidget, XmNlosingFocusCallback, textLosingFocusCallback, this);
|
|
XtAddCallback(m_textWidget, XmNmodifyVerifyCallback, textModifyCallback, this);
|
|
|
|
// Insert our own event handler to the head of the list
|
|
// XFE_Component::m_widget is the grid widget
|
|
XtInsertEventHandler(m_widget,
|
|
event_mask,
|
|
False,
|
|
eventHandler, this, XtListHead);
|
|
// Add Interests
|
|
|
|
m_parentView->getToplevel()->registerInterest(XFE_AddressFolderView::tabNext, this,
|
|
(XFE_FunctionNotification)tabToGrid_cb);
|
|
|
|
m_parentView->getParent()->getToplevel()->registerInterest(XFE_ComposeView::tabBeforeSubject, this,
|
|
(XFE_FunctionNotification)tabToGrid_cb);
|
|
|
|
setMultiSelectAllowed(True);
|
|
m_firstSelected = -1;
|
|
m_lastSelected = -1;
|
|
}
|
|
|
|
// Default Constructor
|
|
XFE_AddressOutliner::XFE_AddressOutliner()
|
|
{
|
|
}
|
|
|
|
// Destructor
|
|
XFE_AddressOutliner::~XFE_AddressOutliner()
|
|
{
|
|
#if defined(USE_ABCOM)
|
|
if (m_pickerPane) {
|
|
MSG_SetFEData(m_pickerPane, 0);
|
|
AB_ClosePane(m_pickerPane);
|
|
}/* if */
|
|
if (m_pickerDlg) {
|
|
delete m_pickerDlg;
|
|
m_pickerDlg = 0;
|
|
}/* if */
|
|
#endif /* USE_ABCOM */
|
|
|
|
}
|
|
|
|
// Install local translations -- this needs to be after realize time,
|
|
// otherwise uparrow and downarrow will be overridden by XFE_Frame.
|
|
XFE_CALLBACK_DEFN(XFE_AddressOutliner,
|
|
afterRealizeWidget)(XFE_NotificationCenter *, void *, void*)
|
|
{
|
|
XtOverrideTranslations(m_textWidget, fe_globalData.editing_translations);
|
|
XtOverrideTranslations(m_textWidget, fe_globalData.single_line_editing_translations);
|
|
XtOverrideTranslations(m_textWidget, fe_globalData.address_outliner_traverse_translations);
|
|
|
|
XtOverrideTranslations(m_typeWidget, fe_globalData.address_outliner_key_translations);
|
|
|
|
// shift focus to the first text field in the outliner if we
|
|
// don't already have a recipient:
|
|
Boolean has_recip = False;
|
|
|
|
// Only "To" or "Newsgroup" counts as recipient (not Bcc, Reply-To, etc.)
|
|
int total = getTotalLines();
|
|
int i;
|
|
for (i=0; i<total; ++i)
|
|
{
|
|
char* type = GetCellValue(i,
|
|
XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE);
|
|
if (type && (!XP_STRCMP(type, "To:") || !XP_STRCMP(type, "Newsgroup:")))
|
|
{
|
|
has_recip = True;
|
|
delete [] type;
|
|
break;
|
|
}
|
|
if (type)
|
|
delete [] type;
|
|
}
|
|
m_focusRow = total-1;
|
|
|
|
if (!has_recip)
|
|
{
|
|
m_focusCol = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT;
|
|
PlaceText(m_focusRow, m_focusCol);
|
|
// PlaceText() is supposed to set the focus into the current field,
|
|
// but it doesn't always. We need to be sure:
|
|
XmLGridSetFocus(m_widget, m_focusRow, m_focusCol);
|
|
}
|
|
}
|
|
|
|
// Popup callback (for To: Cc: Followup: etc)
|
|
void
|
|
XFE_AddressOutliner::popupCallback(Widget w, XtPointer clientData, XtPointer)
|
|
{
|
|
XFE_AddressOutliner * obj = (XFE_AddressOutliner*) clientData;
|
|
XmString xmstr;
|
|
|
|
XtVaGetValues(w,XmNlabelString,&xmstr,NULL);
|
|
|
|
if (xmstr)
|
|
{
|
|
String str = NULL;
|
|
|
|
XmStringGetLtoR(xmstr,XmFONTLIST_DEFAULT_TAG,&str);
|
|
|
|
if (str)
|
|
{
|
|
obj->selectedMenu(str);
|
|
|
|
XtFree(str);
|
|
}
|
|
|
|
XmStringFree(xmstr);
|
|
}
|
|
}
|
|
|
|
// Static Methods for traverse actions
|
|
void
|
|
XFE_AddressOutliner::fieldTraverse(
|
|
Widget /*w*/,
|
|
XEvent* /*event*/,
|
|
String* /*params*/,
|
|
Cardinal* /*nparam*/)
|
|
{
|
|
//XmLGridGetFocus(m_widget, &row, &col, &focus);
|
|
PlaceText(m_focusRow,m_focusCol);
|
|
if ( XtIsManaged(m_textWidget) )
|
|
XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
|
|
else if (XtIsManaged(m_typeWidget) )
|
|
XmProcessTraversal(m_typeWidget, XmTRAVERSE_CURRENT);
|
|
}
|
|
|
|
|
|
void
|
|
XFE_AddressOutliner::keyIn(
|
|
Widget /*w*/,
|
|
XEvent * /*event*/,
|
|
String *params,
|
|
Cardinal *nparam)
|
|
{
|
|
XrmQuark q;
|
|
static int keyIn_quarksValid = 0;
|
|
static XrmQuark qTo, qReply, qNewsgroup, qFollowup, qCc, qBcc;
|
|
|
|
int row, col;
|
|
Widget grid;
|
|
grid = m_widget;
|
|
|
|
if (*nparam != 1)
|
|
return;
|
|
if (!keyIn_quarksValid)
|
|
{
|
|
qTo = XrmStringToQuark(XFE_AddressFolderView::TO);
|
|
qReply = XrmStringToQuark(XFE_AddressFolderView::REPLY);
|
|
qFollowup = XrmStringToQuark(XFE_AddressFolderView::FOLLOWUP);
|
|
qNewsgroup = XrmStringToQuark(XFE_AddressFolderView::NEWSGROUP);
|
|
qCc = XrmStringToQuark(XFE_AddressFolderView::CC);
|
|
qBcc = XrmStringToQuark(XFE_AddressFolderView::BCC);
|
|
keyIn_quarksValid = 1;
|
|
|
|
}
|
|
|
|
q = XrmStringToQuark(params[0] );
|
|
|
|
col = m_focusCol;
|
|
row = m_focusRow;
|
|
|
|
if (col== XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
|
|
col = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE;
|
|
|
|
if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE )
|
|
{
|
|
if ( q == qTo )
|
|
{
|
|
XDEBUG(printf("*KEY IN TO * invalidate Line caused by %d\n", row);)
|
|
setTypeHeader(row, MSG_TO_HEADER_MASK);
|
|
}
|
|
else if ( q == qReply)
|
|
{
|
|
XDEBUG(printf("*KEY IN Reply * invalidate Line caused by %d\n", row);)
|
|
setTypeHeader(row, MSG_REPLY_TO_HEADER_MASK);
|
|
}
|
|
else if ( q == qNewsgroup)
|
|
{
|
|
XDEBUG(printf("*KEY IN Newsgroup * invalidate Line caused by %d\n", row);)
|
|
setTypeHeader(row, MSG_NEWSGROUPS_HEADER_MASK);
|
|
}
|
|
else if ( q == qFollowup)
|
|
{
|
|
XDEBUG(printf("*KEY IN Followup * invalidate Line caused by %d\n", row);)
|
|
setTypeHeader(row, MSG_FOLLOWUP_TO_HEADER_MASK);
|
|
}
|
|
else if (q == qCc)
|
|
{
|
|
XDEBUG(printf("*KEY IN CC * invalidate Line caused by %d\n", row);)
|
|
setTypeHeader(row, MSG_CC_HEADER_MASK);
|
|
}
|
|
else if ( q == qBcc)
|
|
{
|
|
XDEBUG(printf("*KEY IN BCC * invalidate Line caused by %d\n", row);)
|
|
setTypeHeader(row, MSG_BCC_HEADER_MASK);
|
|
}
|
|
else
|
|
{
|
|
XDEBUG(printf("*Invalide Key In value at %d\n", row);)
|
|
XP_ASSERT(0);
|
|
}
|
|
} /* COLUMN_TYPE */
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::tableTraverse(
|
|
Widget /*w*/,
|
|
XEvent * event,
|
|
String * params,
|
|
Cardinal* nparam)
|
|
|
|
{
|
|
XrmQuark q;
|
|
static int quarksValid = 0;
|
|
static XrmQuark qLEFT, qRIGHT;
|
|
static XrmQuark qINSERT, qDELETE, qBACKSPACE;
|
|
static XrmQuark qNEXT, qPREVIOUS;
|
|
static XrmQuark qHOME, qEND, qUP, qDOWN;
|
|
|
|
Widget grid;
|
|
int row, col;
|
|
grid = m_widget;
|
|
|
|
if (*nparam != 1)
|
|
return;
|
|
if (!quarksValid)
|
|
{
|
|
qINSERT = XrmStringToQuark("INSERT");
|
|
qDELETE = XrmStringToQuark("DELETE");
|
|
qBACKSPACE = XrmStringToQuark("BACKSPACE");
|
|
qEND = XrmStringToQuark("END");
|
|
qHOME = XrmStringToQuark("HOME");
|
|
qUP = XrmStringToQuark("UP");
|
|
qDOWN = XrmStringToQuark("DOWN");
|
|
qLEFT = XrmStringToQuark("LEFT");
|
|
qRIGHT = XrmStringToQuark("RIGHT");
|
|
qNEXT = XrmStringToQuark("NEXT");
|
|
qPREVIOUS = XrmStringToQuark("PREVIOUS");
|
|
quarksValid = 1;
|
|
|
|
}
|
|
q = XrmStringToQuark(params[0] );
|
|
|
|
row = m_focusRow;
|
|
col = m_focusCol;
|
|
|
|
|
|
if ( q == qINSERT)
|
|
doInsert( row,col);
|
|
else if ( q == qDELETE )
|
|
doDelete(row, col, event);
|
|
else if ( q == qBACKSPACE )
|
|
doBackSpace(row, col, event);
|
|
else if ( q == qEND)
|
|
doEnd(row, col);
|
|
else if ( q == qHOME)
|
|
doHome(row, col);
|
|
else if ( q == qUP )
|
|
doUp(row, col);
|
|
else if ( q == qDOWN )
|
|
doDown(row, col);
|
|
else if ( q == qLEFT )
|
|
doLeft(row, col);
|
|
else if ( q == qRIGHT)
|
|
doRight(row, col);
|
|
else if ( q == qNEXT)
|
|
doNext(row, col);
|
|
else if ( q == qPREVIOUS)
|
|
doPrevious(row, col);
|
|
else
|
|
XP_ASSERT(0);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::selectedMenu(char *name)
|
|
{
|
|
static Cardinal num = 1;
|
|
char *keyInStr = NULL;
|
|
|
|
m_inPopup= False;
|
|
if ( name[0] == 'T')
|
|
{
|
|
keyInStr = XP_STRDUP(XFE_AddressFolderView::TO);
|
|
}
|
|
else if ( name[0] == 'C')
|
|
{
|
|
keyInStr = XP_STRDUP(XFE_AddressFolderView::CC);
|
|
}
|
|
else if ( name[0] == 'B')
|
|
{
|
|
keyInStr = XP_STRDUP(XFE_AddressFolderView::BCC);
|
|
}
|
|
else if ( name[0] == 'R' )
|
|
{
|
|
keyInStr = XP_STRDUP(XFE_AddressFolderView::REPLY);
|
|
}
|
|
else if ( name[0] == 'N' )
|
|
{
|
|
keyInStr = XP_STRDUP(XFE_AddressFolderView::NEWSGROUP);
|
|
}
|
|
else if ( name[0] == 'F' )
|
|
{
|
|
keyInStr = XP_STRDUP(XFE_AddressFolderView::FOLLOWUP);
|
|
}
|
|
else XP_ASSERT(0);
|
|
|
|
keyIn(m_typeWidget, NULL, &keyInStr, &num);
|
|
XP_FREE(keyInStr);
|
|
|
|
// Make sure the popup menu is not posted
|
|
if (XfeIsAlive(m_popup))
|
|
{
|
|
XtUnmanageChild(m_popup);
|
|
}
|
|
|
|
XtAddCallback(m_typeWidget,
|
|
XmNlosingFocusCallback, textLosingFocusCallback, this);
|
|
}
|
|
|
|
// XFE_AddressOutliner ---------- Protected ---------------------
|
|
|
|
// NONE
|
|
|
|
// XFE_AddressOutliner ---------- Private ---------------------
|
|
|
|
|
|
void
|
|
XFE_AddressOutliner::MapText(int row)
|
|
{
|
|
int total;
|
|
|
|
total = getTotalLines();
|
|
|
|
if ( row >= total )
|
|
change(row, total,total+1 );
|
|
|
|
PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT, False);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::PlaceText(int row, int col, Boolean doUpdate)
|
|
{
|
|
#if defined(DEBUG_tao)
|
|
printf("\nXFE_AddressOutliner::PlaceText:row=%d, col=%d, update=%d,m_focusRow=%d, m_focusCol=%d\n",
|
|
row, col, doUpdate, m_focusRow, m_focusCol);
|
|
#endif
|
|
XRectangle rect;
|
|
Boolean removed = False;
|
|
|
|
|
|
//XtVaGetValues(m_textWidget, XmNcursorPosition, &cursorPos, 0);
|
|
|
|
if( XtIsManaged(m_textWidget) && doUpdate ) {
|
|
(void) updateAddresses();
|
|
|
|
XtRemoveCallback(m_textWidget,
|
|
XmNlosingFocusCallback, textLosingFocusCallback, this);
|
|
removed = True;
|
|
}
|
|
if ( XtIsManaged(m_textWidget) ) XtUnmanageChild(m_textWidget);
|
|
|
|
if ( XtIsManaged(m_typeWidget) ) XtUnmanageChild(m_typeWidget);
|
|
|
|
// UPDATE FOCUS CELL CURSOR POSITION & ROW & COL
|
|
m_focusRow= row;
|
|
m_focusCol= col;
|
|
|
|
makeVisible(row);
|
|
|
|
//XtVaSetValues(m_widget, XmNscrollRow, row, NULL);
|
|
|
|
XmLGridRowColumnToXY( m_widget, XmCONTENT, row, XmCONTENT, col, False, &rect);
|
|
|
|
//fe_SetTextFieldAndCallBack(m_textWidget, NULL);
|
|
|
|
if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
|
|
{
|
|
char *str;
|
|
XtVaSetValues( m_textWidget, XmNx, rect.x,
|
|
XmNy, rect.y, XmNwidth, rect.width,
|
|
XmNheight, rect.height, 0);
|
|
|
|
str = GetCellValue(row, col);
|
|
|
|
// Force an update may not be necessary
|
|
XmUpdateDisplay(m_widget);
|
|
|
|
fe_SetTextFieldAndCallBack(m_textWidget, str);
|
|
|
|
if ( str )
|
|
/* allocated by new
|
|
*/
|
|
delete str;
|
|
|
|
XmUpdateDisplay(m_textWidget);
|
|
XmTextFieldShowPosition( m_textWidget, m_cursorPos);
|
|
// Set insertion pos before managing child, otherwise
|
|
// cruft sometimes appears at beginning of line (SGI bug?):
|
|
XmTextFieldSetInsertionPosition( m_textWidget, m_cursorPos);
|
|
XtManageChild(m_textWidget);
|
|
XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
|
|
}
|
|
else if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE)
|
|
{
|
|
char *str;
|
|
XtVaSetValues( m_typeWidget, XmNx, rect.x,
|
|
XmNy, rect.y, XmNwidth, rect.width,
|
|
XmNheight, rect.height, 0);
|
|
str = GetCellValue(row, col);
|
|
|
|
fe_SetTextFieldAndCallBack(m_typeWidget, str);
|
|
if ( str ) XtFree(str);
|
|
|
|
XtManageChild(m_typeWidget);
|
|
XmProcessTraversal(m_typeWidget, XmTRAVERSE_CURRENT);
|
|
}
|
|
XmLGridSetFocus(m_widget, m_focusRow, m_focusCol);
|
|
if ( removed )
|
|
XtAddCallback(m_textWidget,
|
|
XmNlosingFocusCallback, textLosingFocusCallback, this);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::textFocus()
|
|
{
|
|
m_parentView->getToplevel()->notifyInterested(XFE_AddressOutliner::textFocusIn, m_textWidget);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::typeFocus()
|
|
{
|
|
m_parentView->getToplevel()->notifyInterested(XFE_AddressOutliner::typeFocusIn, m_typeWidget);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::textLosingFocus(XtPointer /* callData*/ )
|
|
{
|
|
#if 0
|
|
int oldrow = m_focusRow;
|
|
int oldcol = m_focusCol;
|
|
|
|
XmTextPosition oldcurs = XmTextFieldGetInsertionPosition(m_textWidget);
|
|
|
|
updateAddresses();
|
|
invalidate(); // redraw all grid elements
|
|
|
|
XmTextPosition lastpos = XmTextFieldGetLastPosition(m_textWidget);
|
|
m_cursorPos = (oldcurs > lastpos ? lastpos : oldcurs);
|
|
m_focusRow = oldrow;
|
|
m_focusCol = oldcol;
|
|
XmLGridSetFocus(m_widget, m_focusRow, m_focusCol);
|
|
XmTextFieldSetInsertionPosition(m_textWidget, m_cursorPos);
|
|
#endif
|
|
// To do: When we lose focus, we also lose the black highlight
|
|
// around the active text widget. This is the place to fix that.
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::textactivate(XtPointer /* callData */)
|
|
{
|
|
#if defined(DEBUG_tao) && defined(USE_ABCOM)
|
|
printf("\nXFE_AddressOutliner::textactivate, m_rtnIsPicker=%d\n",
|
|
m_rtnIsPicker);
|
|
#endif /* DEBUG_tao */
|
|
int oldrow = m_focusRow;
|
|
int count = getTotalLines();
|
|
|
|
// Don't do anything if there's nothing in the text field:
|
|
if (XmTextFieldGetInsertionPosition(m_textWidget) <= 0)
|
|
return;
|
|
|
|
#if defined(USE_ABCOM)
|
|
if (m_rtnIsPicker) {
|
|
/* pop up picker
|
|
*/
|
|
if (m_pickerDlg) {
|
|
m_pickerDlg->show();
|
|
m_pickerDlg->selectItem(1);
|
|
}/* if */
|
|
return;
|
|
}/* if m_rtnIsPicker */
|
|
#endif
|
|
|
|
//textLosingFocus(0);
|
|
updateAddresses();
|
|
|
|
count = getTotalLines() - count;
|
|
int curline = m_focusRow + count;
|
|
|
|
Boolean insertNewLine = !m_addressable->hasDataAt(curline+1);
|
|
if ( insertNewLine )
|
|
{
|
|
selectLine(-1);
|
|
m_addressable->insertNewDataAfter(curline);
|
|
}
|
|
|
|
MapText(m_focusRow + count + 1);
|
|
m_focusRow = oldrow + count + 1;
|
|
|
|
// As per the spec (don't blame me for the design!):
|
|
// increment the Type field of the next line to the next
|
|
// addressing mode, e.g. if this is To, make it Cc --
|
|
// but only if there were multiple comma-separated names typed in.
|
|
if ( insertNewLine && count > 0 )
|
|
{
|
|
// Make it stop at Bcc:
|
|
int headerPos = 0;
|
|
MSG_HEADER_SET mask;
|
|
if ( headerPos == MSG_TotalHeaderCount()-1 )
|
|
mask = MSG_HeaderValue(0);
|
|
else mask = MSG_HeaderValue(++headerPos);
|
|
const char* header = MSG_HeaderMaskToString((MSG_HEADER_SET)mask);
|
|
if (!XP_STRNCMP(header, "To", 2) || !XP_STRNCMP(header, "Cc", 2))
|
|
doDown(m_focusRow,
|
|
XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE);
|
|
}
|
|
}
|
|
|
|
char*
|
|
XFE_AddressOutliner::getLastEnterredName(char* str, int* comma_pos, int* len, Boolean *moreRecipients)
|
|
{
|
|
char *pSubstring = NULL;
|
|
char *string = NULL;
|
|
char *substring = NULL;
|
|
*len = 0;
|
|
*comma_pos = 0;
|
|
|
|
*moreRecipients = False;
|
|
|
|
if ( str && strlen(str) > 0 )
|
|
{
|
|
string = strdup(str);
|
|
|
|
// Returns the pointer to the first occurances of ','
|
|
substring = strrchr(string, ',');
|
|
if (substring && strlen(substring) > 1)
|
|
{
|
|
pSubstring = (char*)XP_CALLOC(strlen(substring)+1, sizeof(char));
|
|
strcpy( pSubstring, substring+1);
|
|
*len = strlen(pSubstring) ;
|
|
*comma_pos = strlen(str) - *len;
|
|
*moreRecipients = True;
|
|
}
|
|
else if (!substring)
|
|
{
|
|
pSubstring = (char*)XP_CALLOC(strlen(string)+1, sizeof(char));
|
|
strcpy( pSubstring, string);
|
|
*len = strlen(pSubstring) ;
|
|
}
|
|
else {
|
|
*comma_pos = strlen(string);
|
|
*moreRecipients = True;
|
|
}
|
|
free(string);
|
|
}
|
|
else
|
|
{
|
|
*len = 0;
|
|
*comma_pos = 0;
|
|
}
|
|
return pSubstring;
|
|
}
|
|
|
|
static void
|
|
text_timer_func(XtPointer closure, XtIntervalId *)
|
|
{
|
|
XFE_AddressOutliner* ao = (XFE_AddressOutliner*)closure;
|
|
if (ao)
|
|
ao->processInput();
|
|
}
|
|
|
|
// This is the routine that looks for name completion.
|
|
void
|
|
XFE_AddressOutliner::processInput()
|
|
{
|
|
m_textTimer = 0; // Make sure the timer is clear
|
|
|
|
char* textStr = fe_GetTextField(m_textWidget);
|
|
|
|
XmTextPosition lastPos = XmTextFieldGetLastPosition(m_textWidget);
|
|
XmTextPosition insertPos = XmTextFieldGetInsertionPosition(m_textWidget);
|
|
|
|
// if we're not at the end of the string, then we're done;
|
|
// no need for name completion:
|
|
if (insertPos < lastPos || textStr == 0)
|
|
return;
|
|
|
|
char* curName = XP_STRRCHR(textStr, ',');
|
|
if (curName != 0)
|
|
++curName;
|
|
// also need to skip past whitespace
|
|
else
|
|
curName = textStr;
|
|
|
|
#if defined(USE_ABCOM)
|
|
m_lastPos = lastPos;
|
|
m_curName = curName;
|
|
m_textStr = textStr;
|
|
|
|
if (!m_pickerDlg) {
|
|
XFE_Frame *f = (XFE_Frame *) m_parentView->getToplevel();
|
|
XP_ASSERT(f);
|
|
m_pickerDlg =
|
|
fe_showComplPickerDlg(f->getBaseWidget(),
|
|
f->getContext(),
|
|
m_pickerPane,
|
|
m_pickerContext,
|
|
&nameCPickerExitFunc,
|
|
this);
|
|
}/* if */
|
|
|
|
int error =
|
|
AB_NameCompletionSearch(m_pickerPane,
|
|
(const char *) curName,
|
|
&nameCompletionExitFunc,
|
|
#ifdef FE_IMPLEMENTS_VISIBLE_NC
|
|
True, // for now
|
|
#endif
|
|
(void *) this);
|
|
#else
|
|
char* completeName = nameCompletion(curName);
|
|
if (completeName)
|
|
{
|
|
char* buf = (char*)XP_CALLOC((size_t)lastPos
|
|
+ XP_STRLEN(completeName) + 1,
|
|
sizeof (char));
|
|
if (curName != textStr)
|
|
{
|
|
strncpy(buf, textStr, curName - textStr);
|
|
XP_STRCAT(buf, completeName);
|
|
}
|
|
else
|
|
XP_STRCPY(buf, completeName);
|
|
|
|
// Probably would be better to set all these
|
|
// with a single XtSetValues command and avoid
|
|
// having to worry about the callback from SetString.
|
|
fe_SetTextFieldAndCallBack(m_textWidget, buf);
|
|
XmTextFieldSetSelection(m_textWidget, lastPos,
|
|
XmTextFieldGetLastPosition(m_textWidget),
|
|
XtLastTimestampProcessed(XtDisplay(m_textWidget)));
|
|
XmTextFieldSetInsertionPosition(m_textWidget, lastPos);
|
|
XP_FREE(completeName);
|
|
XP_FREE(buf);
|
|
}
|
|
XtFree(textStr);
|
|
#endif /* USE_ABCOM */
|
|
}
|
|
|
|
#if defined(USE_ABCOM)
|
|
void
|
|
XFE_AddressOutliner::nameCPickerExitFunc(void *clientData, void *callData)
|
|
{
|
|
XFE_AddressOutliner *obj = (XFE_AddressOutliner *) callData;
|
|
obj->nameCPickerCB(clientData);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::nameCPickerCB(void *clientData)
|
|
{
|
|
AB_NameCompletionCookie *cookie = (AB_NameCompletionCookie *) clientData;
|
|
|
|
/* reset the flag
|
|
*/
|
|
m_rtnIsPicker = False;
|
|
|
|
char *completeName = AB_GetNameCompletionDisplayString(cookie);
|
|
if (completeName && XP_STRLEN(completeName)) {
|
|
m_lastPos = XP_STRLEN(completeName);
|
|
fillNameCompletionStr(completeName);
|
|
textactivate(NULL);
|
|
XP_FREE(completeName);
|
|
}/* if */
|
|
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::fillNameCompletionStr(char *completeName)
|
|
{
|
|
char* buf = (char*)XP_CALLOC((size_t)m_lastPos
|
|
+ XP_STRLEN(completeName) + 1,
|
|
sizeof (char));
|
|
if (m_curName != m_textStr) {
|
|
strncpy(buf, m_textStr, m_curName - m_textStr);
|
|
XP_STRCAT(buf, completeName);
|
|
}
|
|
else
|
|
XP_STRCPY(buf, completeName);
|
|
|
|
// Probably would be better to set all these
|
|
// with a single XtSetValues command and avoid
|
|
// having to worry about the callback from SetString.
|
|
fe_SetTextFieldAndCallBack(m_textWidget, buf);
|
|
XmTextFieldSetSelection(m_textWidget, m_lastPos,
|
|
XmTextFieldGetLastPosition(m_textWidget),
|
|
XtLastTimestampProcessed(XtDisplay(m_textWidget)));
|
|
XmTextFieldSetInsertionPosition(m_textWidget, m_lastPos);
|
|
XmUpdateDisplay(m_textWidget);
|
|
XP_FREE(buf);
|
|
}
|
|
|
|
int
|
|
XFE_AddressOutliner::nameCompletionExitFunc(AB_NameCompletionCookie *cookie,
|
|
int numResults,
|
|
void *FEcookie)
|
|
{
|
|
XFE_AddressOutliner *obj = (XFE_AddressOutliner *) FEcookie;
|
|
return obj->nameCompletionCB(cookie, numResults);
|
|
}
|
|
|
|
int
|
|
XFE_AddressOutliner::nameCompletionCB(AB_NameCompletionCookie *cookie,
|
|
int numResults)
|
|
{
|
|
#if defined(DEBUG_tao)
|
|
printf("\nnameCompletionCB,numResults=%d\n", numResults);
|
|
#endif
|
|
XP_ASSERT(m_pickerPane && m_pickerContext);
|
|
if (numResults > 1) {
|
|
/* set the flag
|
|
*/
|
|
m_rtnIsPicker = True;
|
|
|
|
/* 1. assemble the hint
|
|
*/
|
|
AB_AttribID attrib = AB_attribDisplayName;
|
|
AB_ColumnInfo *cInfo =
|
|
AB_GetColumnInfoForPane(m_pickerPane,
|
|
(AB_ColumnID) 1);
|
|
if (cInfo) {
|
|
attrib = cInfo->attribID;
|
|
AB_FreeColumnInfo(cInfo);
|
|
|
|
AB_AttributeValue *value = 0;
|
|
int error =
|
|
AB_GetEntryAttributeForPane(m_pickerPane,
|
|
0,
|
|
attrib, &value);
|
|
char a_line[1024];
|
|
a_line[0] = '\0';
|
|
XP_SAFE_SPRINTF(a_line, sizeof(a_line),
|
|
"%s <multiple matches found>",
|
|
EMPTY_STRVAL(value)?m_curName:value->u.string);
|
|
fillNameCompletionStr(a_line);
|
|
AB_FreeEntryAttributeValue(value);
|
|
}/* if */
|
|
}/* if */
|
|
else if (numResults == 1){
|
|
char *completeName = AB_GetNameCompletionDisplayString(cookie);
|
|
if (completeName && XP_STRLEN(completeName)) {
|
|
fillNameCompletionStr(completeName);
|
|
XP_FREE(completeName);
|
|
}/* if */
|
|
|
|
}/* else */
|
|
return numResults;
|
|
}
|
|
#endif /* USE_ABCOM */
|
|
|
|
void
|
|
XFE_AddressOutliner::textmodify(Widget, XtPointer callData)
|
|
{
|
|
char *pCompleteName = NULL;
|
|
XmTextVerifyCallbackStruct *cbs;
|
|
char *pName = NULL;
|
|
char *pCurrString = NULL;
|
|
int len;
|
|
int comma_pos, length;
|
|
char *pNewName = NULL;
|
|
Boolean moreRecipients;
|
|
XmTextPosition lastpos = 0;
|
|
|
|
cbs = (XmTextVerifyCallbackStruct *)callData;
|
|
|
|
if (m_lastSelected > -1) // there's a multiple selection
|
|
{
|
|
// Do nothing unless this is backspace or delete
|
|
if (cbs->text->ptr != NULL)
|
|
return;
|
|
|
|
deleteRows(m_firstSelected, m_lastSelected);
|
|
return;
|
|
}
|
|
|
|
// If one line is selected, deselect once we start typing:
|
|
else if (m_firstSelected > -1)
|
|
selectLine(-1);
|
|
|
|
if ( cbs->text->length == 1 )
|
|
{
|
|
pCurrString = fe_GetTextField(m_textWidget);
|
|
lastpos = XmTextFieldGetLastPosition(m_textWidget);
|
|
XmTextPosition left, right;
|
|
if (XmTextFieldGetSelectionPosition(m_textWidget, &left, &right)
|
|
&& lastpos <= right)
|
|
lastpos = left;
|
|
|
|
if ( cbs->currInsert < lastpos )
|
|
{
|
|
XtFree(pCurrString);
|
|
pCurrString = NULL;
|
|
cbs->doit = True;
|
|
}
|
|
if ( pCurrString )
|
|
{
|
|
XmTextPosition insertPos;
|
|
|
|
// We only want to match the part of pCurrString the user
|
|
// actually entered, not the part matched from the addrbook:
|
|
char* enteredString = (char*)XP_CALLOC(lastpos+1, sizeof(char));
|
|
strncpy(enteredString, pCurrString, lastpos);
|
|
pNewName = getLastEnterredName(enteredString, &comma_pos, &length,
|
|
&moreRecipients);
|
|
XP_FREE(enteredString);
|
|
len = length + cbs->text->length + 1;
|
|
pName = (char*)XP_CALLOC(len, sizeof(char));
|
|
|
|
// If the field was empt before, it's easy:
|
|
if ( cbs->currInsert == 0 || (moreRecipients && length == 0))
|
|
{
|
|
strcpy(pName, cbs->text->ptr);
|
|
insertPos = 0;
|
|
}
|
|
else if ( length > 0 )
|
|
{
|
|
XmTextPosition left, right;
|
|
if (!XmTextFieldGetSelectionPosition(m_textWidget,
|
|
&left, &right))
|
|
left = cbs->currInsert;
|
|
// "left", not cbs->currInsert, is really the insert position.
|
|
|
|
if (!moreRecipients)
|
|
strncpy(pName, pCurrString, (size_t)left);
|
|
else
|
|
strncpy(pName, pNewName,
|
|
(unsigned int)(cbs->currInsert - comma_pos));
|
|
|
|
strcat(pName, cbs->text->ptr);
|
|
|
|
// Now reset the timer -- when it runs out we'll try
|
|
// name completion, rather than doing it on every char:
|
|
if (m_textTimer)
|
|
XtRemoveTimeOut(m_textTimer);
|
|
m_textTimer = XtAppAddTimeOut(fe_XtAppContext, 650,
|
|
text_timer_func, this);
|
|
pCompleteName = 0;
|
|
|
|
insertPos = left;
|
|
}
|
|
|
|
cbs->doit = True;
|
|
XP_FREE (pName);
|
|
}
|
|
else
|
|
{
|
|
cbs->doit = True;
|
|
}
|
|
XtFree(pCurrString);
|
|
}
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::textmotion(XtPointer callData)
|
|
{
|
|
XmTextVerifyCallbackStruct *cbs;
|
|
|
|
|
|
cbs = (XmTextVerifyCallbackStruct *)callData;
|
|
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::scroll(XtPointer)
|
|
{
|
|
selectLine(-1);
|
|
|
|
// If we keep the child managed, then the Outliner will try to
|
|
// scroll back to keep the last focused row visible (makeVisible).
|
|
// We can either unmanage the text widget (so nothing has focus)
|
|
// or guess where to shift the focus upon scrolling.
|
|
XtUnmanageChild(m_textWidget);
|
|
|
|
#if 0
|
|
int focus_r, focus_c;
|
|
Boolean focusIn;
|
|
XRectangle rect;
|
|
XtUnmanageChild(m_textWidget);
|
|
XmLGridGetFocus(m_widget, &focus_r, &focus_c, &focusIn);
|
|
if ( XmLGridRowIsVisible(m_widget, focus_r) )
|
|
{
|
|
XmLGridRowColumnToXY( m_widget, XmCONTENT,
|
|
focus_r, XmCONTENT, 2, False, &rect);
|
|
XtVaSetValues( m_textWidget, XmNx, rect.x,
|
|
XmNy, rect.y, XmNwidth, rect.width,
|
|
XmNheight, rect.height, 0);
|
|
XtManageChild(m_textWidget);
|
|
XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::handleEvent(XEvent *event, Boolean *c)
|
|
{
|
|
int x = event->xbutton.x;
|
|
int y = event->xbutton.y;
|
|
unsigned char rowtype;
|
|
unsigned char coltype;
|
|
int row, column;
|
|
static int press_row=0, press_col = 0;
|
|
// only handles button clicks for now. See outline.c:ButtonEvent for details.
|
|
*c = True;
|
|
switch (event->type)
|
|
{
|
|
case KeyPress:
|
|
XDEBUG(printf("KeyPressMask...\n");)
|
|
selectLine(-1);
|
|
break;
|
|
case FocusOut:
|
|
XDEBUG(printf("Focus out Mask...\n");)
|
|
break;
|
|
case FocusIn:
|
|
XDEBUG(printf("Focus In Mask...\n");)
|
|
*c = False;
|
|
//XmLGridGetFocus(m_widget, &row, &column, &focus);
|
|
if ( m_focusCol == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT ) {
|
|
XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
|
|
}
|
|
break;
|
|
case EnterNotify: // Enter Grid Widget and Leave the text widget
|
|
XDEBUG(printf("Enter Notify-Detail-%d\n", ((XCrossingEvent*)event)->detail);)
|
|
/***************************************************************/
|
|
// This is a HACK, we rely on details to give us more info
|
|
// about the crossing events.
|
|
|
|
// Here are some traces. But, details might be skipped if
|
|
// cursor pointer moves too fast. Aack.. it's X... dh
|
|
|
|
// Leave from Grid to Outside Grid, details = NotifyAncestor(0)
|
|
// From Outsidget Gri enter to Grid, details = NotifyAncestor
|
|
|
|
// Leave from Grid to Text Widget, details = NotifyInferior(2)
|
|
// Enter to Grid from Text Widget, details = NotifyInferior
|
|
/***************************************************************/
|
|
|
|
// Only when one actually enter to the grid widget
|
|
// from outside the grid widget.
|
|
if ( ((XCrossingEvent*)event)->detail == NotifyAncestor ) onEnter();
|
|
break;
|
|
case LeaveNotify:
|
|
// Don't do anthing now
|
|
break;
|
|
case MotionNotify:
|
|
XDEBUG(printf("Motion Notify..........\n");)
|
|
break;
|
|
case ButtonPress:
|
|
// Always ignore btn3. Btn3 is for popups. - dp
|
|
*c = False;
|
|
if (event->xbutton.button == 3) break;
|
|
XDEBUG(printf("Button Press....\n");)
|
|
|
|
if (XmLGridXYToRowColumn(m_widget, x, y,
|
|
&rowtype, &row, &coltype, &column) >= 0)
|
|
{
|
|
m_inPopup = False;
|
|
if (rowtype == XmHEADING)
|
|
{
|
|
// let microline handle the resizing of rows.
|
|
if (XmLGridPosIsResize(m_widget, x, y))
|
|
{
|
|
*c = True;
|
|
return;
|
|
}
|
|
}
|
|
else if ( column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_ICON )
|
|
{
|
|
|
|
// If it's a shift-click, we need to do multi selection,
|
|
// otherwise select it exclusively:
|
|
if ((event->xbutton.state & ShiftMask) != 0 && m_firstSelected >= 0)
|
|
extendSelection(row);
|
|
else
|
|
selectLine(row);
|
|
|
|
*c = True;
|
|
return;
|
|
}
|
|
else if (column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE
|
|
|| column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_BTN)
|
|
m_inPopup = True;
|
|
else if ( column > 0 )
|
|
{
|
|
press_row = row;
|
|
press_col = column;
|
|
}
|
|
|
|
// We had a click somewhere other than the icon, so clear selection:
|
|
selectLine(-1);
|
|
|
|
if ( m_inPopup )
|
|
{
|
|
*c = False;
|
|
|
|
XtRemoveCallback(m_typeWidget,
|
|
XmNlosingFocusCallback, textLosingFocusCallback, this);
|
|
// This call to PlaceText sets the focus into the type field,
|
|
// which allows changing the type via keyboard but has the
|
|
// unfortunate side effect that we can't pull down a menu
|
|
// from this widget a second time. But that's arguably better
|
|
// than never allowing keyboard-based changes ...
|
|
// ToDo: place a similar event handler on the m_typeWidget.
|
|
PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE);
|
|
if ( m_popup == NULL )
|
|
{
|
|
int i;
|
|
|
|
m_popup = XFE_PopupMenu::CreatePopupMenu(FE_GetToplevelWidget(),
|
|
"AddressOutlinerPopup",
|
|
NULL,0);
|
|
|
|
XtVaSetValues(m_popup,XmNmenuPost,"<Btn1Down>",NULL);
|
|
|
|
int count = MSG_TotalHeaderCount();
|
|
|
|
for ( i = 0; i < count; i++ )
|
|
{
|
|
char *maskStr = XP_STRDUP(MSG_HeaderMaskToString(MSG_HeaderValue(i)));
|
|
|
|
XmString xmstr = XmStringCreate(maskStr,
|
|
XmFONTLIST_DEFAULT_TAG);
|
|
|
|
Widget item = XtVaCreateManagedWidget("PopupItem",
|
|
xmPushButtonWidgetClass,
|
|
m_popup,
|
|
XmNlabelString, xmstr,
|
|
NULL);
|
|
|
|
XmStringFree(xmstr);
|
|
|
|
XtAddCallback(item,XmNactivateCallback,popupCallback,this);
|
|
|
|
XP_FREE(maskStr);
|
|
}
|
|
}
|
|
|
|
Position x_root, y_root;
|
|
XRectangle rect;
|
|
XButtonPressedEvent press_event;
|
|
XmLGridRowColumnToXY(m_widget,
|
|
XmCONTENT, row,
|
|
XmCONTENT, 0,
|
|
True,
|
|
&rect);
|
|
XtTranslateCoords(m_widget, 0,0, &x_root, &y_root);
|
|
|
|
press_event.x_root = x_root+rect.x;
|
|
press_event.y_root = y_root+rect.y + rect.height;
|
|
|
|
// Position and post the popup menu
|
|
XmMenuPosition(m_popup,(XButtonPressedEvent *) &press_event);
|
|
XtManageChild(m_popup);
|
|
}
|
|
}
|
|
break;
|
|
case ButtonRelease:
|
|
*c = False;
|
|
|
|
if (event->xbutton.button == 3) break;
|
|
if (XmLGridXYToRowColumn(m_widget, x, y,
|
|
&rowtype, &row, &coltype, &column) >= 0)
|
|
{
|
|
if (rowtype == XmHEADING)
|
|
{
|
|
// let microline handle the resizing of rows.
|
|
if (XmLGridPosIsResize(m_widget, x, y))
|
|
{
|
|
*c = True;
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (row == press_row && column == press_col )
|
|
{
|
|
if ( column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_ICON )
|
|
*c = True;
|
|
else if ( column > 0 )
|
|
{
|
|
PlaceText(row, column);
|
|
|
|
// Translate mouse event coordinate to the text field char pos:
|
|
if (column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT)
|
|
{
|
|
Position x_grid, y_grid; // root pos of grid origin
|
|
Position x_text, y_text; // root pos of textf origin
|
|
XtTranslateCoords(m_widget, 0,0, &x_grid, &y_grid);
|
|
XtTranslateCoords(m_textWidget, 0,0, &x_text, &y_text);
|
|
|
|
XmTextFieldSetCursorPosition(m_textWidget,
|
|
XmTextFieldXYToPos(m_textWidget,
|
|
x + x_grid - x_text,
|
|
y + y_grid - y_text));
|
|
XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
|
|
}
|
|
}
|
|
else *c = False;
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::selectLine(int row)
|
|
{
|
|
Pixel bg;
|
|
|
|
Time time = XtLastTimestampProcessed(XtDisplay(m_textWidget));
|
|
XmTextFieldClearSelection(m_textWidget, time);
|
|
|
|
XmLGridDeselectAllRows(getBaseWidget(), False);
|
|
|
|
if (row < 0) // clear selection
|
|
{
|
|
XmLGridRow rowp = XmLGridGetRow(m_widget, XmCONTENT, 0);
|
|
XmLGridColumn colp = XmLGridGetColumn(m_widget, XmCONTENT, 0);
|
|
XtVaGetValues(m_widget,
|
|
XmNrowPtr, rowp,
|
|
XmNcolumnPtr, colp,
|
|
XmNcellBackground,&bg,
|
|
NULL);
|
|
XmTextFieldClearSelection(m_textWidget, time);
|
|
XtVaSetValues(m_textWidget, XmNbackground, bg, 0 );
|
|
m_firstSelected = m_lastSelected = -1;
|
|
return;
|
|
}
|
|
|
|
// highlight everything in the text field
|
|
PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
|
|
XmTextPosition last = XmTextFieldGetLastPosition(m_textWidget);
|
|
XmTextFieldSetSelection(m_textWidget, 0, last, time);
|
|
XmTextFieldSetCursorPosition(m_textWidget, 0);
|
|
|
|
XmLGridSelectRow(getBaseWidget(), row, False);
|
|
|
|
XtVaGetValues(m_widget,
|
|
XmNselectBackground, &bg,
|
|
NULL);
|
|
XtVaSetValues(m_textWidget, XmNbackground, bg, 0 );
|
|
|
|
m_firstSelected = row;
|
|
m_lastSelected = -1;
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::extendSelection(int row)
|
|
{
|
|
Time time = XtLastTimestampProcessed(XtDisplay(m_textWidget));
|
|
|
|
// XmLGridSelectRow() may overwrite the selected text,
|
|
// so make sure nothing is selected:
|
|
XmTextFieldClearSelection(m_textWidget, time);
|
|
|
|
XmLGridDeselectAllRows(getBaseWidget(), False);
|
|
|
|
if (m_lastSelected < 0) // only one selected item previously
|
|
{
|
|
if (row < m_firstSelected)
|
|
{
|
|
m_lastSelected = m_firstSelected;
|
|
m_firstSelected = row;
|
|
}
|
|
else
|
|
m_lastSelected = row;
|
|
}
|
|
else if (row < m_firstSelected)
|
|
m_firstSelected = row;
|
|
else /* if (row > m_lastSelected) */
|
|
m_lastSelected = row;
|
|
|
|
// Select everything in the text field -- not because we
|
|
// really want to, but because it will force the text field
|
|
// to pass both backspace and delete through to textmodify.
|
|
// What a total hack!
|
|
// Worse, if the text field is blank, we can't select it at all! :-(
|
|
XmTextPosition last = XmTextFieldGetLastPosition(m_textWidget);
|
|
#ifdef notdef
|
|
// This PlaceText causes lines to be deleted from the outliner
|
|
// if the last line is blank!
|
|
// It's not clear why it was needed, anyway.
|
|
PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
|
|
#endif
|
|
XmTextFieldSetSelection(m_textWidget, 0, last, time);
|
|
XmTextFieldSetCursorPosition(m_textWidget, 0);
|
|
|
|
int i;
|
|
for (i = m_firstSelected; i <= m_lastSelected; ++i)
|
|
XmLGridSelectRow(getBaseWidget(), i, False);
|
|
|
|
Pixel bg;
|
|
XtVaGetValues(m_widget,
|
|
XmNselectBackground, &bg,
|
|
NULL);
|
|
XtVaSetValues(m_textWidget, XmNbackground, bg, 0 );
|
|
}
|
|
|
|
|
|
/* Caller has to free this return value */
|
|
char *
|
|
XFE_AddressOutliner::GetCellValue(int row, int col)
|
|
{
|
|
XmString xmStr = 0;
|
|
XmLGridRow rowp;
|
|
XmLGridColumn colp;
|
|
char *str;
|
|
Pixel bg;
|
|
|
|
|
|
m_addressable->getDataAt(row, col, &str);
|
|
rowp = XmLGridGetRow(m_widget, XmCONTENT, row);
|
|
colp = XmLGridGetColumn(m_widget, XmCONTENT, col);
|
|
|
|
XtVaGetValues(m_widget,
|
|
XmNrowPtr, rowp,
|
|
XmNcolumnPtr, colp,
|
|
XmNcellString, &xmStr,
|
|
XmNcellBackground,&bg,
|
|
NULL);
|
|
XtVaSetValues(m_textWidget, XmNbackground, bg, 0 );
|
|
XtVaSetValues(m_typeWidget, XmNbackground, bg, 0 );
|
|
return str;
|
|
}
|
|
|
|
//
|
|
// This routine returns malloced memory which should be freed with XtFree()
|
|
//
|
|
static char*
|
|
getUnhighlightedText(Widget textW)
|
|
{
|
|
XmTextPosition left, right;
|
|
char* textStr = fe_GetTextField(textW);
|
|
if (XmTextFieldGetSelectionPosition(textW, &left,&right))
|
|
textStr[left] = 0;
|
|
return textStr;
|
|
}
|
|
|
|
int
|
|
XFE_AddressOutliner::updateAddresses()
|
|
{
|
|
int totalAddresses = 1;
|
|
|
|
int focus_r, focus_c;
|
|
|
|
char *textStr;
|
|
int total = getTotalLines();
|
|
|
|
//XmLGridGetFocus(m_widget, &focus_r, &focus_c, &focusIn);
|
|
|
|
focus_r = m_focusRow;
|
|
focus_c = m_focusCol;
|
|
|
|
if ( focus_c == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
|
|
{
|
|
textStr = getUnhighlightedText(m_textWidget);
|
|
|
|
setAddress(focus_r, (char*)textStr, True);
|
|
XtFree(textStr);
|
|
totalAddresses = getTotalLines();
|
|
totalAddresses = totalAddresses - total + 1; // Include current line
|
|
|
|
// Reset the value of the text field in case it has changed
|
|
// from plural to singular:
|
|
char* str = GetCellValue(m_focusRow,
|
|
XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
|
|
if (str)
|
|
{
|
|
// Only update the string if it changed
|
|
// (so we don't change the X selection unnecessesarily)
|
|
char* curstr = fe_GetTextField(m_textWidget);
|
|
if (!curstr || XP_STRCMP(curstr, str))
|
|
fe_SetTextFieldAndCallBack(m_textWidget, str);
|
|
delete [] str;
|
|
if (curstr)
|
|
XtFree(curstr);
|
|
}
|
|
|
|
XtVaGetValues(m_textWidget, XmNcursorPosition, &m_cursorPos, 0);
|
|
}
|
|
return totalAddresses;
|
|
}
|
|
|
|
|
|
// XFE_AddressOutliner -------- Private ------ static functions -----------
|
|
|
|
XFE_CALLBACK_DEFN(XFE_AddressOutliner, tabToGrid)(XFE_NotificationCenter*, void*, void*)
|
|
{
|
|
if ( m_textWidget && XtIsManaged(m_textWidget))
|
|
XmProcessTraversal(m_textWidget, XmTRAVERSE_CURRENT);
|
|
else if ( m_typeWidget && XtIsManaged(m_typeWidget))
|
|
XmProcessTraversal(m_typeWidget, XmTRAVERSE_CURRENT);
|
|
}
|
|
|
|
|
|
void
|
|
XFE_AddressOutliner::textFocusCallback(Widget, XtPointer clientData, XtPointer)
|
|
{
|
|
XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
|
|
|
|
|
|
obj->textFocus();
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::typeFocusCallback(Widget, XtPointer clientData, XtPointer)
|
|
{
|
|
XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
|
|
|
|
|
|
obj->typeFocus();
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::textLosingFocusCallback(Widget, XtPointer clientData, XtPointer callData)
|
|
{
|
|
XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
|
|
obj->textLosingFocus(callData);
|
|
}
|
|
void
|
|
XFE_AddressOutliner::textActivateCallback(Widget, XtPointer clientData, XtPointer callData)
|
|
{
|
|
XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
|
|
obj->textactivate(callData);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::textMotionCallback(Widget, XtPointer clientData, XtPointer callData)
|
|
{
|
|
XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
|
|
obj->textmotion(callData);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::textModifyCallback(Widget w, XtPointer clientData, XtPointer callData)
|
|
{
|
|
XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
|
|
obj->textmodify(w, callData);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::scrollCallback(Widget, XtPointer clientData, XtPointer callData)
|
|
{
|
|
XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
|
|
obj->scroll(callData);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::eventHandler(Widget, XtPointer clientData, XEvent *event, Boolean *cont)
|
|
{
|
|
XFE_AddressOutliner *obj = (XFE_AddressOutliner*)clientData;
|
|
obj->handleEvent(event, cont);
|
|
}
|
|
|
|
char *
|
|
XFE_AddressOutliner::nameCompletion(char *pString)
|
|
{
|
|
#if defined(USE_ABCOM)
|
|
return 0;
|
|
#else
|
|
return xfe_ExpandForNameCompletion(pString, m_pAddrBook, m_pCompleteServer);
|
|
#endif
|
|
}
|
|
|
|
//---------------------------- Static Functions for action table
|
|
static void FieldTraverse(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *nparam)
|
|
|
|
{
|
|
|
|
XtPointer client;
|
|
XFE_AddressOutliner *obj ;
|
|
|
|
XtVaGetValues( w, XmNuserData, &client, 0);
|
|
obj = (XFE_AddressOutliner *) client;
|
|
obj->fieldTraverse(w, event, params, nparam);
|
|
|
|
}
|
|
|
|
static void KeyIn(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *nparam)
|
|
{
|
|
XtPointer client;
|
|
XFE_AddressOutliner *obj ;
|
|
|
|
XtVaGetValues( w, XmNuserData, &client, 0);
|
|
|
|
obj = (XFE_AddressOutliner *) client;
|
|
obj->keyIn(w, event, params, nparam);
|
|
}
|
|
|
|
static void TableTraverse(
|
|
Widget w,
|
|
XEvent *event,
|
|
String *params,
|
|
Cardinal *nparam)
|
|
{
|
|
XtPointer client;
|
|
XFE_AddressOutliner *obj ;
|
|
|
|
XtVaGetValues( w, XmNuserData, &client, 0);
|
|
|
|
obj = (XFE_AddressOutliner *) client;
|
|
obj->tableTraverse(w, event, params, nparam);
|
|
}
|
|
|
|
//----------- Address Book stuff here ------------
|
|
|
|
extern "C" char * xfe_ExpandForNameCompletion(char * pString,
|
|
ABook *pAddrBook,
|
|
DIR_Server *pDirServer)
|
|
{
|
|
#if !defined(MOZ_NEWADDR)
|
|
|
|
ABID entryID;
|
|
ABID field;
|
|
char *pName = XP_STRDUP(pString);
|
|
|
|
#if defined(DEBUG_tao)
|
|
printf("\n xfe_ExpandForNameCompletion");
|
|
#endif
|
|
|
|
XP_ASSERT(pAddrBook);
|
|
XP_ASSERT(pDirServer);
|
|
AB_GetIDForNameCompletion(
|
|
pAddrBook,
|
|
pDirServer,
|
|
&entryID,&field,(const char*)pName);
|
|
|
|
XP_FREE(pName);
|
|
|
|
if (entryID != (unsigned long)-1)
|
|
{
|
|
if ( field == ABNickname )
|
|
{
|
|
/* abdefn.h:const int kMaxFullNameLength = 256;
|
|
*/
|
|
char szNickname[kMaxFullNameLength+1];
|
|
szNickname[0] = '\0';
|
|
AB_GetNickname(
|
|
pDirServer,
|
|
pAddrBook, entryID, szNickname);
|
|
if (strlen(szNickname))
|
|
return strdup(szNickname);
|
|
}
|
|
else if ( field == ABFullName )
|
|
{
|
|
char *szFullname;
|
|
szFullname = (char*)XP_CALLOC(kMaxFullNameLength+1, sizeof(char));
|
|
szFullname[0] = '\0';
|
|
AB_GetFullName(pDirServer,
|
|
pAddrBook,
|
|
entryID,
|
|
szFullname);
|
|
if (szFullname && strlen(szFullname))
|
|
{
|
|
return szFullname;
|
|
}
|
|
|
|
}
|
|
}
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
// New Communication methods with parent view
|
|
|
|
void
|
|
XFE_AddressOutliner::setTypeHeader(int row, MSG_HEADER_SET header, Boolean redisplay)
|
|
{
|
|
const char *type = MSG_HeaderMaskToString(header);
|
|
m_focusRow = row;
|
|
|
|
// Set Data
|
|
m_addressable->setHeader(row, header);
|
|
|
|
// Update the Type Field Display
|
|
|
|
if ( redisplay ) invalidateLine(row); // Should be invalidateCell
|
|
if ( type )
|
|
{
|
|
fe_SetTextFieldAndCallBack(m_typeWidget, (char*)type );
|
|
XmTextFieldSetHighlight(m_typeWidget, 0,
|
|
strlen(type), XmHIGHLIGHT_SELECTED);
|
|
}
|
|
else XP_ASSERT(0);
|
|
}
|
|
|
|
|
|
|
|
void
|
|
XFE_AddressOutliner::setAddress(int row,
|
|
char *pAddressStr, Boolean redisplay)
|
|
{
|
|
int oldCount = getTotalLines();
|
|
int newReceipients = 1;
|
|
|
|
m_focusRow = row;
|
|
|
|
newReceipients = m_addressable->setReceipient(row, pAddressStr);
|
|
if ( newReceipients > 1 )
|
|
{
|
|
change(m_focusRow, oldCount, oldCount+newReceipients-1);
|
|
}
|
|
else if (redisplay)
|
|
{
|
|
invalidate();
|
|
}
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::doInsert(int row, int /* col */)
|
|
{
|
|
|
|
(void)updateAddresses();
|
|
m_addressable->insertNewDataAfter(row);
|
|
m_cursorPos = 0;
|
|
MapText(row+1);
|
|
invalidate();
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::doDelete(int row, int col, XEvent *event)
|
|
{
|
|
XmTextPosition cpos;
|
|
XmTextPosition pos, newPos;
|
|
char *textStr;
|
|
Boolean deleterow = False;
|
|
|
|
if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT)
|
|
{
|
|
XtVaGetValues(m_textWidget, XmNcursorPosition, &cpos, 0);
|
|
pos = XmTextFieldGetLastPosition(m_textWidget);
|
|
|
|
if (pos ==0 && cpos== 0 && row+1 == getTotalLines() ) deleterow = False;
|
|
else if (pos ==0 && cpos== 0) deleterow = True;
|
|
else if ( pos == cpos ) deleterow = False;
|
|
else if (pos > 0)
|
|
{
|
|
// Hack text widget action
|
|
XtCallActionProc(m_textWidget, "delete-next-character", event,
|
|
NULL, 0 );
|
|
newPos = XmTextFieldGetLastPosition(m_textWidget);
|
|
textStr = fe_GetTextField(m_textWidget);
|
|
|
|
if (newPos == pos && newPos == 0 ) deleterow = True;
|
|
else{
|
|
setAddress(row, textStr, False);
|
|
invalidateLine(row);
|
|
}
|
|
XtFree(textStr);
|
|
} /* pos > 0 */
|
|
} /* col = */
|
|
|
|
if (deleterow
|
|
|| col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE)
|
|
deleteRow(row, col);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::doBackSpace(int row, int col, XEvent *event)
|
|
{
|
|
XmTextPosition cpos;
|
|
XmTextPosition pos;
|
|
Boolean deleterow = False;
|
|
|
|
if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT)
|
|
{
|
|
XtVaGetValues(m_textWidget, XmNcursorPosition, &cpos, 0);
|
|
pos = XmTextFieldGetLastPosition(m_textWidget);
|
|
|
|
if (pos == 0 && cpos == 0 )
|
|
deleterow = True;
|
|
else if (pos > 0)
|
|
{
|
|
// Hack text widget action
|
|
XtCallActionProc(m_textWidget, "delete-previous-character",
|
|
event, NULL, 0 );
|
|
} /* pos > 0 */
|
|
} /* col = */
|
|
|
|
if (deleterow
|
|
|| col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE)
|
|
{
|
|
deleteRow(row, col);
|
|
|
|
// shift focus to end of previous row
|
|
if ( row > 0 ) {
|
|
PlaceText(row-1,
|
|
XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
|
|
m_cursorPos = XmTextFieldGetLastPosition(m_textWidget);
|
|
XmTextFieldSetInsertionPosition(m_textWidget, m_cursorPos);
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::deleteRow(int row, int col)
|
|
{
|
|
selectLine(-1);
|
|
|
|
if ( getTotalLines() == 1)
|
|
{
|
|
m_cursorPos= 0;
|
|
setAddress(row, NULL, False);
|
|
setTypeHeader(row, MSG_TO_HEADER_MASK, False);
|
|
invalidateLine(row);
|
|
|
|
PlaceText(0,XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT, False );
|
|
}
|
|
else
|
|
{
|
|
//m_cursorPos = 0;
|
|
if (row >= 0 && m_addressable->removeDataAt(row) )
|
|
{
|
|
XtRemoveCallback(m_textWidget, XmNlosingFocusCallback,
|
|
textLosingFocusCallback, this);
|
|
int total = getTotalLines();
|
|
if ( total > row+1)
|
|
{
|
|
change(row, total, total-1);
|
|
PlaceText(row, col, False);
|
|
}
|
|
else
|
|
{
|
|
change(row, total, total-1);
|
|
PlaceText(row-1, col, False);
|
|
}
|
|
XtAddCallback(m_textWidget, XmNlosingFocusCallback,
|
|
textLosingFocusCallback, this);
|
|
m_cursorPos = 0;
|
|
XmTextFieldSetCursorPosition(m_textWidget, 0);
|
|
}
|
|
col = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT;
|
|
}
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::deleteRows(int startrow, int endrow)
|
|
{
|
|
selectLine(-1);
|
|
|
|
XtUnmanageChild(m_textWidget);
|
|
|
|
if (endrow >= getTotalLines()-1)
|
|
endrow = getTotalLines()-1;
|
|
|
|
for (int i = endrow; i >= startrow; --i)
|
|
m_addressable->removeDataAt(i);
|
|
|
|
// Make sure we have at least one row:
|
|
Boolean deletedAll = False;
|
|
if (startrow == 0 && endrow == getTotalLines()-1)
|
|
{
|
|
startrow = 1;
|
|
deletedAll = True;
|
|
}
|
|
change(startrow, endrow-startrow+1, getTotalLines()-endrow+startrow-1);
|
|
|
|
// Should get the text widget managed again ...
|
|
|
|
if (deletedAll)
|
|
{
|
|
PlaceText(0, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
|
|
fe_SetTextFieldAndCallBack(m_textWidget, "");
|
|
}
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::doEnd(int row, int col)
|
|
{
|
|
if (col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT)
|
|
{
|
|
m_cursorPos = XmTextFieldGetLastPosition(m_textWidget);
|
|
XmTextFieldSetCursorPosition(m_textWidget, m_cursorPos);
|
|
}
|
|
else
|
|
{
|
|
row = getTotalLines();
|
|
col = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT;
|
|
PlaceText(row, col);
|
|
}
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::doHome(int row, int col)
|
|
{
|
|
if (col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT)
|
|
{
|
|
XmTextFieldSetCursorPosition(m_textWidget, (XmTextPosition)0);
|
|
}
|
|
else
|
|
{
|
|
row = 0; col = 1;
|
|
PlaceText(row, col);
|
|
}
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::doUp(int row, int col)
|
|
{
|
|
const char *header;
|
|
int headerPos = 0;
|
|
MSG_HEADER_SET mask;
|
|
|
|
if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
|
|
{
|
|
if ( row > 0 ) row--;
|
|
PlaceText(row,XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
|
|
}
|
|
else
|
|
{
|
|
static Cardinal doUp_num = 1;
|
|
char *headerStr;
|
|
|
|
headerPos = m_addressable->getHeader(row);
|
|
|
|
if ( headerPos == 0 )
|
|
mask = MSG_HeaderValue(MSG_TotalHeaderCount()-1);
|
|
else mask = MSG_HeaderValue(--headerPos);
|
|
|
|
header = MSG_HeaderMaskToString((MSG_HEADER_SET)mask);
|
|
|
|
headerStr = XP_STRDUP(header);
|
|
keyIn( m_typeWidget, NULL, &headerStr, &doUp_num );
|
|
XP_FREE(headerStr);
|
|
}
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::doDown(int row, int col)
|
|
{
|
|
const char *header;
|
|
MSG_HEADER_SET mask;
|
|
int headerPos;
|
|
|
|
if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
|
|
{
|
|
updateAddresses();
|
|
|
|
if ( row+1 < getTotalLines() )
|
|
{
|
|
row++;
|
|
}
|
|
PlaceText(row,
|
|
XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT, False);
|
|
}
|
|
else
|
|
{
|
|
static Cardinal doDown_num = 1;
|
|
char *headerStr;
|
|
headerPos = m_addressable->getHeader(row);
|
|
|
|
if ( headerPos == MSG_TotalHeaderCount()-1 )
|
|
mask = MSG_HeaderValue(0);
|
|
else mask = MSG_HeaderValue(++headerPos);
|
|
|
|
header = MSG_HeaderMaskToString((MSG_HEADER_SET)mask);
|
|
|
|
headerStr = XP_STRDUP(header);
|
|
keyIn( m_typeWidget, NULL, &headerStr, &doDown_num );
|
|
XP_FREE(headerStr);
|
|
}
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::doLeft(int row, int col)
|
|
{
|
|
XmTextPosition pos;
|
|
|
|
if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
|
|
{
|
|
pos = XmTextFieldGetInsertionPosition(m_textWidget);
|
|
if ( pos == 0 )
|
|
PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE);
|
|
else
|
|
{
|
|
m_cursorPos = pos-1;
|
|
XmTextFieldSetInsertionPosition(m_textWidget, m_cursorPos);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
XFE_AddressOutliner::doRight(int row, int col)
|
|
{
|
|
XmTextPosition pos;
|
|
XmTextPosition lastpos;
|
|
|
|
if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE )
|
|
{
|
|
PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
|
|
XmTextFieldSetInsertionPosition(m_textWidget, 0 );
|
|
}
|
|
else if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
|
|
{
|
|
lastpos = XmTextFieldGetLastPosition(m_textWidget);
|
|
pos = XmTextFieldGetInsertionPosition(m_textWidget);
|
|
if ( pos < lastpos )
|
|
{
|
|
m_cursorPos = pos+1;
|
|
XmTextFieldSetInsertionPosition(m_textWidget, m_cursorPos);
|
|
}
|
|
else if ( row+1 < getTotalLines() )
|
|
PlaceText(row+1, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE);
|
|
else
|
|
PlaceText(row, XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT);
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::doNext(int row, int col)
|
|
{
|
|
updateAddresses();
|
|
|
|
if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
|
|
{
|
|
if ( row+1 == getTotalLines() )
|
|
{
|
|
// Register Action
|
|
|
|
XtUnmanageChild(m_textWidget);
|
|
XtUnmanageChild(m_typeWidget);
|
|
m_parentView->getToplevel()->notifyInterested(XFE_AddressOutliner::tabNext, this);
|
|
invalidate();
|
|
return;
|
|
}
|
|
else if ( row < getTotalLines() ) row++;
|
|
col = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE;
|
|
}
|
|
else
|
|
col= XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT;
|
|
PlaceText(row, col, False);
|
|
}
|
|
|
|
|
|
void
|
|
XFE_AddressOutliner::doPrevious(int row, int col)
|
|
{
|
|
updateAddresses();
|
|
|
|
if ( col == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE )
|
|
{
|
|
if ( row == 0 )
|
|
{
|
|
m_parentView->getToplevel()->notifyInterested(XFE_AddressOutliner::tabPrev, this);
|
|
return;
|
|
}
|
|
else
|
|
row --;
|
|
col = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT;
|
|
}
|
|
else col = XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE;
|
|
PlaceText(row, col, False);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::onLeave()
|
|
{
|
|
XtVaGetValues(m_textWidget, XmNcursorPosition, &m_cursorPos, 0);
|
|
XtUnmanageChild(m_textWidget);
|
|
XtUnmanageChild(m_typeWidget);
|
|
|
|
updateAddresses();
|
|
invalidate();
|
|
|
|
XmLGridSetFocus(m_widget, m_focusRow, m_focusCol);
|
|
XmUpdateDisplay(m_widget);
|
|
if ( m_lastFocus )
|
|
XmProcessTraversal(m_lastFocus, XmTRAVERSE_CURRENT);
|
|
else
|
|
m_parentView->getToplevel()->notifyInterested(XFE_AddressOutliner::tabNext, this);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::onEnter()
|
|
{
|
|
int row, column;
|
|
Widget base;
|
|
|
|
base = m_parentView->getParent()->getParent()->getBaseWidget();
|
|
row = m_focusRow;
|
|
column = m_focusCol;
|
|
|
|
if ( XtIsManaged(m_textWidget) || XtIsManaged(m_typeWidget) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if ( column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_RECEIPIENT )
|
|
{
|
|
// Value has been updated on Leave. No need to update it again
|
|
PlaceText(row, column, False );
|
|
}
|
|
else if ( column == XFE_AddressFolderView::ADDRESS_OUTLINER_COLUMN_TYPE)
|
|
{
|
|
XtManageChild(m_typeWidget);
|
|
XmProcessTraversal(m_typeWidget, XmTRAVERSE_CURRENT);
|
|
}
|
|
// m_parentView->getToplevel()->notifyInterested(XFE_AddressFolderView::tabNext, this);
|
|
}
|
|
|
|
void
|
|
XFE_AddressOutliner::fillText(char *text)
|
|
{
|
|
if (m_textWidget && text)
|
|
fe_SetTextFieldAndCallBack(m_textWidget, text);
|
|
}
|
|
|
|
|
|
|