home *** CD-ROM | disk | FTP | other *** search
/ Tools / WinSN5.0Ver.iso / NETSCAP.50 / WIN1998.ZIP / ns / cmd / xfe / src / TextEditorView.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-04-08  |  15.4 KB  |  513 lines

  1. /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
  2.  *
  3.  * The contents of this file are subject to the Netscape Public License
  4.  * Version 1.0 (the "NPL"); you may not use this file except in
  5.  * compliance with the NPL.  You may obtain a copy of the NPL at
  6.  * http://www.mozilla.org/NPL/
  7.  *
  8.  * Software distributed under the NPL is distributed on an "AS IS" basis,
  9.  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
  10.  * for the specific language governing rights and limitations under the
  11.  * NPL.
  12.  *
  13.  * The Initial Developer of this code under the NPL is Netscape
  14.  * Communications Corporation.  Portions created by Netscape are
  15.  * Copyright (C) 1998 Netscape Communications Corporation.  All Rights
  16.  * Reserved.
  17.  */
  18. /* 
  19.    TextEditorView.h - anything that has a text editable area in it. 
  20.    Crreated: Dora Hsu <dora@netscape.com>, Sept-30-96.
  21.  */
  22.  
  23.  
  24.  
  25. #include "TextEditorView.h"
  26. #include "SpellHandler.h"
  27. #include <Xm/Text.h>
  28. #include "libi18n.h"
  29. #include "felocale.h"
  30. #include "xfe.h" // for CONTEXT_DATA
  31. #include "Xfe/Xfe.h"
  32.  
  33. #ifdef DEBUG_editor
  34. #define XDEBUG(x) x
  35. #else
  36. #define XDEBUG(x)
  37. #endif
  38.  
  39. extern "C" void fe_mail_text_modify_cb (Widget, XtPointer, XtPointer);
  40. extern "C"  void fe_HackTranslations (MWContext *, Widget);
  41.  
  42. extern "C" XtPointer fe_GetFont(MWContext *context, int sizeNum, int fontmask);
  43. extern "C"
  44. unsigned char * fe_ConvertToLocaleEncoding(int16 charset, unsigned char *str);
  45.  
  46.  
  47. MenuSpec XFE_TextEditorView::popupmenu_spec[] = {
  48.   { xfeCmdCut,                  PUSHBUTTON },
  49.   { xfeCmdCopy,                 PUSHBUTTON },
  50.   { xfeCmdPaste,                PUSHBUTTON },
  51.   { xfeCmdPasteAsQuoted,        PUSHBUTTON },
  52.   MENU_SEPARATOR,
  53.   { xfeCmdQuoteOriginalText,          PUSHBUTTON },
  54.   {NULL}
  55. };
  56.  
  57. const char *XFE_TextEditorView::textFocusIn = "XFE_TextEditorView::textFocusIn";
  58.  
  59. XFE_TextEditorView::XFE_TextEditorView(XFE_Component* toplevel_component, 
  60.                        XFE_View *parent_view,
  61.                        MSG_Pane *p,
  62.                        MWContext *context)
  63.   : XFE_MNView(toplevel_component, parent_view, context, p)
  64. {
  65.     m_popup = NULL;
  66. }
  67.  
  68. void
  69. XFE_TextEditorView::createWidgets(Widget parentW, XP_Bool wrap_p)
  70. {
  71.  
  72.   int ac;
  73.   Arg av[20];
  74.   Widget textW;
  75.   MWContext *context = getParent()->getContext();
  76.   XmFontList fontList;
  77.   Widget form;
  78.  
  79.   fontList = (XmFontList)fe_GetFont (context, 3, LO_FONT_FIXED);
  80.   
  81.   form = XmCreateForm(parentW, "plainTextForm", NULL, 0 );
  82.  
  83.   ac = 0;
  84.   XtSetArg(av[ac], XmNtopOffset, 5); ac++;
  85.   XtSetArg (av[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
  86.   XtSetArg (av[ac], XmNfontList, fontList); ac++;
  87.   XtSetArg (av[ac], XmNscrollHorizontal, !wrap_p); ac++;
  88.   XtSetArg (av[ac], XmNwordWrap, wrap_p); ac++;
  89.   XtSetArg (av[ac], XmNtopAttachment, XmATTACH_FORM); ac++;
  90.   XtSetArg (av[ac], XmNleftAttachment, XmATTACH_FORM); ac++;
  91.   XtSetArg (av[ac], XmNbottomAttachment, XmATTACH_FORM); ac++;
  92.   XtSetArg (av[ac], XmNrightAttachment, XmATTACH_FORM); ac++;
  93.   textW = XmCreateScrolledText(parentW, "mailto_bodyText", av, ac);
  94.   XtAddCallback (textW, XmNmodifyVerifyCallback,
  95.                    fe_mail_text_modify_cb, getParent()->getContext());
  96.  
  97.   // NOTE... [ we need this for the ComposeView focus mechanism...
  98.   //
  99.   XtAddCallback(textW, XmNfocusCallback, textFocusCallback, this);
  100.  
  101.   // 
  102.   setBaseWidget(form);
  103.   XtManageChild(textW);
  104.  
  105.   // This is a hack...NEED here...
  106.   // Otherwise, we cannot swap the text widget upon wrap on/off.
  107.   CONTEXT_DATA(m_contextData)->mcBodyText = textW;
  108.  
  109. }
  110.  
  111. void
  112. XFE_TextEditorView::textFocus()
  113. {
  114.     Widget textW = CONTEXT_DATA(m_contextData)->mcBodyText;
  115.  
  116.     getToplevel()->notifyInterested(XFE_TextEditorView::textFocusIn, textW);
  117. }
  118.  
  119. void
  120. XFE_TextEditorView::textFocusCallback(Widget, XtPointer clientData, XtPointer)
  121. {
  122.   XFE_TextEditorView *obj = (XFE_TextEditorView*)clientData;
  123.  
  124.   obj->textFocus();
  125. }
  126.  
  127. void
  128. XFE_TextEditorView::setFont(XmFontList fontList)
  129. {
  130.   int ac;
  131.   Arg av[20];
  132.   Widget textW = CONTEXT_DATA(m_contextData)->mcBodyText;
  133.  
  134.   ac = 0;
  135.   XtSetArg (av[ac], XmNfontList, fontList); ac++;
  136.   XtSetValues(textW, av, ac);
  137.   if (fe_LocaleCharSetID & MULTIBYTE) {
  138.     Dimension columns;
  139.     XtVaGetValues(textW, XmNcolumns, &columns, NULL);
  140.     XtVaSetValues(textW, XmNcolumns, (columns + 1) / 2, NULL);
  141.   }
  142. }
  143.  
  144. void
  145. XFE_TextEditorView::setComposeWrapState(XP_Bool wrap_p)
  146. {
  147.   Boolean old_wrap, new_wrap, old_scroll, new_scroll;
  148.   Widget text, parent, gramp;
  149.   MWContext *context = getParent()->getContext();
  150.  
  151.   XP_ASSERT(context->type == MWContextMessageComposition);
  152.   XP_ASSERT(CONTEXT_DATA(context)->mcBodyText);
  153.  
  154.   text = CONTEXT_DATA(context)->mcBodyText;
  155.   if (!text) return;
  156.  
  157.   parent = XtParent(text);
  158.   gramp = XtParent(parent);
  159.  
  160.   XtVaGetValues(text,
  161.                 XmNwordWrap,         &old_wrap,
  162.                 XmNscrollHorizontal, &old_scroll,
  163.                 0);
  164.  
  165.   new_wrap   = wrap_p;
  166.   new_scroll = !wrap_p;
  167.   CONTEXT_DATA (context)->compose_wrap_lines_p = wrap_p;
  168.  
  169.   if (new_wrap == old_wrap &&
  170.       new_scroll == old_scroll)
  171.     return;
  172.  
  173.   {
  174.     String body = 0;
  175.     XmTextPosition cursor = 0;
  176.     unsigned char top = 0, bot = 0, left = 0, right = 0;
  177.     Widget topw = 0, botw = 0, leftw = 0, rightw = 0;
  178.     Arg av [20];
  179.     int ac = 0;
  180.     XmFontList font_list = 0;
  181.  
  182.     /* #### warning much of this is cloned from mozilla.c
  183.        (fe_create_composition_widgets) */
  184.  
  185.     XtVaGetValues (text,
  186.                    XmNcursorPosition, &cursor,
  187.                    XmNfontList, &font_list,
  188.                    0);
  189.     body = fe_GetTextField(text);
  190.     XtVaGetValues (parent,
  191.                    XmNtopAttachment, &top,      XmNtopWidget, &topw,
  192.                    XmNbottomAttachment, &bot,   XmNbottomWidget, &botw,
  193.                    XmNleftAttachment, &left,    XmNleftWidget, &leftw,
  194.                    XmNrightAttachment, &right,  XmNrightWidget, &rightw,
  195.                    0);
  196.  
  197.     XtUnmanageChild(parent);
  198.     XtDestroyWidget(parent);
  199.     CONTEXT_DATA(context)->mcBodyText = text = parent = 0;
  200.  
  201.     XtSetArg (av[ac], XmNeditable, True); ac++;
  202.     XtSetArg (av[ac], XmNcursorPositionVisible, True); ac++;
  203.     XtSetArg (av[ac], XmNeditMode, XmMULTI_LINE_EDIT); ac++;
  204.  
  205.     XtSetArg (av[ac], XmNscrollVertical,   TRUE); ac++;
  206.     XtSetArg (av[ac], XmNscrollHorizontal, new_scroll); ac++;
  207.     XtSetArg (av[ac], XmNwordWrap,         new_wrap); ac++;
  208.  
  209.     XtSetArg (av[ac], XmNfontList, font_list); ac++;
  210.  
  211.     text = XmCreateScrolledText (gramp, "mailto_bodyText", av, ac);
  212.     parent = XtParent(text);
  213.     // This is really a hack since we changed the widget in the 
  214.     // middle of displaying
  215.     fe_HackTranslations(m_contextData, text);
  216.  
  217.     if (fe_LocaleCharSetID & MULTIBYTE) {
  218.       Dimension columns;
  219.       XtVaGetValues(text, XmNcolumns, &columns, NULL);
  220.       XtVaSetValues(text, XmNcolumns, (columns + 1) / 2, NULL);
  221.     }
  222.  
  223.  
  224.     /* Warning -- this assumes no widgets are attached to this one
  225.        (which is the normal state of affairs, since this is the widget
  226.        that should grow.) */
  227.     XtVaSetValues (parent,
  228.                    XmNtopAttachment,    top,   XmNtopWidget,    topw,
  229.                    XmNbottomAttachment, bot,   XmNbottomWidget, botw,
  230.                    XmNleftAttachment,   left,  XmNleftWidget,   leftw,
  231.                    XmNrightAttachment,  right, XmNrightWidget,  rightw,
  232.                    0);
  233.     XtVaSetValues (text,
  234.                    XmNfontList, font_list,
  235.                    XmNcursorPosition, cursor,
  236.                    XmNwordWrap, new_wrap,
  237.                    0);
  238.     fe_SetTextField(text, (body ? body : ""));
  239.     if (body) free(body);
  240.  
  241.     /* Put this callback back so that the "you haven't typed anything do
  242.        you really want to send?" hack still works with this new text widget
  243.        #### cloned from dialogs.c (FE_InitializeMailCompositionContext)
  244.      */
  245.     XtAddCallback (text, XmNmodifyVerifyCallback,
  246.                    fe_mail_text_modify_cb, context);
  247.  
  248.     // NOTE... [ we need this for the ComposeView focus mechanism...
  249.     //
  250.     XtAddCallback(text, XmNfocusCallback, textFocusCallback, this);
  251.  
  252.     CONTEXT_DATA(context)->mcBodyText = text;
  253.     XtManageChild(text);
  254.  
  255.     /* just in case it didn't take... */
  256.     XtVaSetValues (text, XmNcursorPosition, cursor, 0);
  257.  
  258.     /* Move focus back there. */
  259.     XmProcessTraversal (text, XmTRAVERSE_CURRENT);
  260.   }
  261. }
  262.  
  263. void
  264. XFE_TextEditorView::doCommand(CommandType cmd, void */*calldata*/, XFE_CommandInfo* info)
  265. {
  266. XDEBUG( printf ("in XFE_TextEditorView::doCommand(%s)\n", Command::getString(cmd));)
  267.  
  268.  Widget destW = XmGetDestination(XtDisplay(getBaseWidget()));
  269.  Widget focusW= XmGetFocusWidget(getBaseWidget());
  270.  
  271.  if ( (destW == CONTEXT_DATA(m_contextData)->mcBodyText ||
  272.        focusW == CONTEXT_DATA(m_contextData)->mcBodyText))
  273.  {
  274.    // Now we are sure the focus is in the text area, 
  275.    // We should perform those commands that are operable in the area
  276.  
  277.    if  (cmd == xfeCmdDelete)
  278.    {
  279.     XEvent *event = info->event;
  280.     XtCallActionProc (CONTEXT_DATA(m_contextData)->mcBodyText, "delete-next-character", event, NULL, 0 );
  281.    }
  282.    else if ( cmd == xfeCmdSelectAll )
  283.    {
  284.     Widget text = CONTEXT_DATA(m_contextData)->mcBodyText;
  285.         XmTextSetSelection(text, 0, XmTextGetLastPosition(text),
  286.                                         info->event->xkey.time);
  287.    }
  288.    else if ( cmd == xfeCmdSpellCheck ) {
  289.        xfe_TextSpellCheck(m_contextData);
  290.    }
  291. #if 0
  292.    else if ( cmd == xfeCmdFindInObject ) 
  293.    {
  294.       // Future work here
  295.       return;
  296.     }
  297.     else if ( cmd == xfeCmdFindAgain )
  298.     {
  299.        // Future work here
  300.        return;
  301.     }
  302. #endif
  303.   }
  304.  
  305. #if 0
  306. //On XFE Compose Window, we don't do Popup anymore...as 4.x Spec indicated.
  307. // There are problem to deal with popup when view swaps...
  308. // This is a XFE framework problem...
  309.   if ( cmd == xfeCmdShowPopup )
  310.   {
  311.         // May need to find out if it's an HTML view or not
  312.        XEvent *event = info->event;
  313.  
  314.        if (m_popup)
  315.        delete m_popup;
  316.  
  317.        m_popup = new XFE_PopupMenu( (XFE_Frame *) getToplevel(),
  318.         XfeAncestorFindApplicationShell(getToplevel()->getBaseWidget()));
  319.  
  320.        m_popup->addMenuSpec(popupmenu_spec);
  321.        m_popup->position (event);
  322.        m_popup->show();
  323.   }
  324. #endif
  325. }
  326.  
  327.  
  328.  
  329.  
  330. Boolean
  331. XFE_TextEditorView::isCommandEnabled(CommandType cmd, void */*calldata*/, XFE_CommandInfo*)
  332. {
  333. XDEBUG( printf ("in XFE_TextEditorView::isCommandEnabled(%s)\n", Command::getString(cmd));)
  334.  
  335.  Widget destW = XmGetDestination(XtDisplay(getBaseWidget()));
  336.  Widget focusW= XmGetFocusWidget(getBaseWidget());
  337.  
  338.  if ( cmd == xfeCmdShowPopup )
  339.      return True;
  340.  
  341.  else if (cmd == xfeCmdSpellCheck)
  342.  {
  343.      return xfe_SpellCheckerAvailable(m_contextData);
  344.  }
  345.  
  346.  else if ( (destW == CONTEXT_DATA(m_contextData)->mcBodyText ||
  347.             focusW == CONTEXT_DATA(m_contextData)->mcBodyText))
  348.  {
  349.      // Now we are sure the focus is in the mcBodyText Area, 
  350.      // we should turn on/off commands accordingly for this area
  351.  
  352.      if ( (cmd == xfeCmdDelete) ||
  353.           (cmd == xfeCmdSelectAll) 
  354.     )
  355.     return True;
  356.  }
  357.  
  358. XDEBUG( printf ("leaving XFE_TextEditorView::isCommandEnabled()\n");)
  359.   return False;
  360. }
  361.  
  362. Boolean
  363. XFE_TextEditorView::handlesCommand(CommandType command, void */*calldata*/, XFE_CommandInfo*)
  364. {
  365. XDEBUG( printf ("in XFE_TextEditorView::handlesCommand(%s)\n", Command::getString(command));)
  366.  
  367.  Widget destW = XmGetDestination(XtDisplay(getBaseWidget()));
  368.  Widget focusW= XmGetFocusWidget(getBaseWidget());
  369.  
  370.   if (command == xfeCmdGetNewMessages
  371.       || command == xfeCmdAddNewsgroup
  372.       || command == xfeCmdDelete
  373.       || command == xfeCmdShowPopup
  374.       || command == xfeCmdSpellCheck
  375.       || command == xfeCmdDelete
  376.       || command == xfeCmdSelectAll )
  377.  {
  378.     return True;
  379.  }
  380.  
  381. XDEBUG( printf ("leaving XFE_TextEditorView::handlesCommand(%s)\n", Command::getString(command));)
  382.   return False;
  383. }
  384.  
  385. char*
  386. XFE_TextEditorView::getPlainText()
  387. {
  388.   // This method suppose to get the text message in the widget
  389.   // and return in a char string block
  390.   return NULL;
  391. }
  392.  
  393. // ---- These methods might need to move up to be XFE_EDITABLE ----------
  394.  
  395. void
  396. XFE_TextEditorView::insertMessageCompositionText(
  397.                 const char* text, XP_Bool leaveCursorAtBeginning, 
  398.                 XP_Bool /*isHTML*/ )
  399. {
  400.  
  401.   MWContext* context = getParent()->getContext();
  402.   XmTextPosition pos = 0, newpos = 0;
  403.   unsigned char *loc;
  404.   Widget bodyTextW= CONTEXT_DATA(m_contextData)->mcBodyText;
  405.  
  406.   XtRemoveCallback(bodyTextW, XmNmodifyVerifyCallback,
  407.                    fe_mail_text_modify_cb, getParent()->getContext());
  408.         
  409.  
  410.   XtVaGetValues(bodyTextW, XmNcursorPosition, &pos, 0);
  411.   loc = fe_ConvertToLocaleEncoding(INTL_DefaultWinCharSetID(context),
  412.                                    (unsigned char *) text);
  413.   XmTextInsert(bodyTextW, pos, (char*) loc);
  414.   if (((char *) loc) != text) {
  415.     XP_FREE(loc);
  416.   }
  417.   XtVaGetValues(bodyTextW, XmNcursorPosition, &newpos, 0);
  418.   if (leaveCursorAtBeginning) {
  419.     XtVaSetValues(bodyTextW, XmNcursorPosition, pos, 0);
  420.   }
  421.   else if (pos == newpos) {
  422.     /* On some motif (eg. AIX), text insertion point is not moved after
  423.      * inserted text. We depend on that here.
  424.      *
  425.      * WARNING: XXX I18N watch. The strlen might not be the right i18n way.
  426.      */
  427.     newpos = pos+strlen(text);
  428.     XtVaSetValues(bodyTextW, XmNcursorPosition, newpos, 0);
  429.   }
  430.   XtAddCallback (bodyTextW, XmNmodifyVerifyCallback,
  431.                    fe_mail_text_modify_cb, getParent()->getContext());
  432. }
  433.  
  434. void
  435. XFE_TextEditorView::getMessageBody(
  436.         char **pBody, uint32 *body_size, 
  437.         MSG_FontCode **font_changes)
  438. {
  439.   MWContext *context = getParent()->getContext();
  440.   Dimension columns = 0;
  441.   char *loc;
  442.   unsigned char *tmp;
  443.   Widget bodyTextW= CONTEXT_DATA(m_contextData)->mcBodyText;
  444.  
  445.   *pBody = 0;
  446.   loc = 0;
  447.   tmp = 0;
  448.   XtVaGetValues (bodyTextW, XmNvalue, &loc, XmNcolumns, &columns, 0);
  449.   if (fe_LocaleCharSetID & MULTIBYTE) {
  450.     columns *= 2;
  451.   }
  452.   if (loc) {
  453.     tmp = fe_ConvertFromLocaleEncoding(INTL_DefaultWinCharSetID(context),
  454.                                        (unsigned char *) loc);
  455.   }
  456.   if (tmp) {
  457.  
  458. #ifdef WRAP_EDITOR_TO_WINDOW_WIDTH  /* Old way: always wrap to window width */
  459.  
  460.     if (columns <= 0) columns = 79;
  461.     *pBody = (char *) XP_WordWrap(INTL_DefaultWinCharSetID(context), tmp,
  462.                                  columns, 1 /* look for '>' */);
  463.  
  464. #else /* New way: obey the ``Wrap Lines to the new length specified by user'' toggle. */
  465.  
  466.     if (CONTEXT_DATA(context)->compose_wrap_lines_p)
  467.       {
  468.     if (fe_globalPrefs.msg_wrap_length >0)
  469.         columns = fe_globalPrefs.msg_wrap_length;
  470.     else columns = 72;
  471.         *pBody = (char *) XP_WordWrap(INTL_DefaultWinCharSetID(context), tmp,
  472.                                      columns, 1 /* look for '>' */);
  473.       }
  474.     else
  475.       {
  476.         /* Else, don't wrap it at all. */
  477.         *pBody = (char*)tmp;
  478.         tmp = 0;
  479.       }
  480. #endif /* New way. */
  481.  
  482.     if (loc != (char *) tmp) {
  483.       XP_FREE(tmp);
  484.     }
  485.   }
  486.   *body_size = (*pBody ? strlen(*pBody) : 0);
  487.   *font_changes = 0;
  488. }
  489.  
  490. void
  491. XFE_TextEditorView::doneWithMessageBody(char* pBody)
  492. {
  493.   Widget bodyTextW= CONTEXT_DATA(m_contextData)->mcBodyText;
  494.   char *loc;
  495.  
  496.   XtVaGetValues(bodyTextW, XmNvalue, &loc, 0);
  497.   if (pBody != loc) {
  498.     XP_FREE(pBody);
  499.   }
  500. }
  501.  
  502. Boolean
  503. XFE_TextEditorView::isModified()
  504. {
  505.  
  506.   return (!(CONTEXT_DATA(m_contextData)->mcCitedAndUnedited) && 
  507.     CONTEXT_DATA(m_contextData)->mcEdited);
  508. }
  509.  
  510.  
  511.  
  512.  
  513.