Back to index

lightning-sunbird  0.9+nobinonly
mozXMLTerminal.cpp
Go to the documentation of this file.
00001 /* ***** BEGIN LICENSE BLOCK *****
00002  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00003  *
00004  * The contents of this file are subject to the Mozilla Public License Version
00005  * 1.1 (the "License"); you may not use this file except in compliance with
00006  * the License. You may obtain a copy of the License at
00007  * http://www.mozilla.org/MPL/
00008  *
00009  * Software distributed under the License is distributed on an "AS IS" basis,
00010  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00011  * for the specific language governing rights and limitations under the
00012  * License.
00013  *
00014  * The Original Code is XMLterm.
00015  *
00016  * The Initial Developer of the Original Code is
00017  * Ramalingam Saravanan.
00018  * Portions created by the Initial Developer are Copyright (C) 1999
00019  * the Initial Developer. All Rights Reserved.
00020  *
00021  * Contributor(s):
00022  *   Pierre Phaneuf <pp@ludusdesign.com>
00023  *
00024  * Alternatively, the contents of this file may be used under the terms of
00025  * either the GNU General Public License Version 2 or later (the "GPL"), or
00026  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00027  * in which case the provisions of the GPL or the LGPL are applicable instead
00028  * of those above. If you wish to allow use of your version of this file only
00029  * under the terms of either the GPL or the LGPL, and not to allow others to
00030  * use your version of this file under the terms of the MPL, indicate your
00031  * decision by deleting the provisions above and replace them with the notice
00032  * and other provisions required by the GPL or the LGPL. If you do not delete
00033  * the provisions above, a recipient may use your version of this file under
00034  * the terms of any one of the MPL, the GPL or the LGPL.
00035  *
00036  * ***** END LICENSE BLOCK ***** */
00037 
00038 // mozXMLTerminal.cpp: implementation of mozIXMLTerminal interface
00039 // to manage all XMLTerm operations.
00040 // Creates a new mozXMLTermSession object to manage session input/output.
00041 // Creates a mozLineTermAux object to access LineTerm operations.
00042 // Creates key/text/mouse/drag listener objects to handle user events.
00043 
00044 #include "nscore.h"
00045 #include "nspr.h"
00046 
00047 #include "nsCOMPtr.h"
00048 #include "nsString.h"
00049 #include "nsReadableUtils.h"
00050 
00051 #include "nsIDocument.h"
00052 #include "nsIDOMHTMLDocument.h"
00053 #include "nsIDocumentViewer.h"
00054 #include "nsIObserver.h"
00055 #include "nsISelectionController.h"
00056 
00057 #include "nsPresContext.h"
00058 #include "nsICaret.h"
00059 #include "nsRect.h"
00060 #include "nsIURI.h"
00061 #include "nsNetUtil.h"
00062 
00063 #include "nsIDOMEventReceiver.h"
00064 #include "nsIDOMEventListener.h"
00065 
00066 #include "nsIServiceManager.h"
00067 #include "nsXPCOM.h"
00068 #include "nsISupportsPrimitives.h"
00069 
00070 #include "nsWidgetsCID.h"
00071 #include "nsIClipboard.h"
00072 #include "nsITransferable.h"
00073 
00074 #include "nsFont.h"
00075 #include "nsIFontMetrics.h"
00076 #include "nsILookAndFeel.h"
00077 
00078 #include "mozXMLT.h"
00079 #include "mozXMLTermUtils.h"
00080 #include "mozXMLTerminal.h"
00081 
00082 #include "nsIWebNavigation.h"
00083 #include "nsIInterfaceRequestor.h"
00084 #include "nsIInterfaceRequestorUtils.h"
00085 #include "nsIWebProgress.h"
00086 
00088 
00089 static NS_DEFINE_CID(kCClipboardCID,      NS_CLIPBOARD_CID);
00090 static NS_DEFINE_CID(kCTransferableCID,   NS_TRANSFERABLE_CID);
00091 static NS_DEFINE_CID(kLookAndFeelCID,     NS_LOOKANDFEEL_CID);
00092 
00094 // mozXMLTerminal implementation
00096 
00097 NS_IMPL_THREADSAFE_ISUPPORTS4(mozXMLTerminal, 
00098                               mozIXMLTerminal,
00099                               nsIWebProgressListener,
00100                               nsIObserver,
00101                               nsISupportsWeakReference)
00102 
00103 mozXMLTerminal::mozXMLTerminal() :
00104   mInitialized(PR_FALSE),
00105 
00106   mCookie(EmptyString()),
00107 
00108   mCommand(EmptyString()),
00109   mPromptExpr(EmptyString()),
00110 
00111   mInitInput(EmptyString()),
00112 
00113   mXMLTermShell(nsnull),
00114   mDocShell(nsnull),
00115   mPresShell(nsnull),
00116   mDOMDocument(nsnull),
00117 
00118   mXMLTermSession(nsnull),
00119 
00120   mLineTermAux(nsnull),
00121   mNeedsResizing(PR_FALSE),
00122 
00123   mKeyListener(nsnull),
00124   mTextListener(nsnull),
00125   mMouseListener(nsnull),
00126   mDragListener(nsnull)
00127 {
00128 }
00129 
00130 
00131 mozXMLTerminal::~mozXMLTerminal()
00132 {
00133   Finalize();
00134 }
00135 
00136 
00137 NS_IMETHODIMP mozXMLTerminal::GetCurrentEntryNumber(PRInt32 *aNumber)
00138 {
00139   if (!mXMLTermSession)
00140     return NS_ERROR_FAILURE;
00141 
00142   return mXMLTermSession->GetCurrentEntryNumber(aNumber);
00143 }
00144 
00145 
00146 NS_IMETHODIMP mozXMLTerminal::GetHistory(PRInt32 *aHistory)
00147 {
00148   if (!mXMLTermSession)
00149     return NS_ERROR_FAILURE;
00150 
00151   return mXMLTermSession->GetHistory(aHistory);
00152 }
00153 
00154 
00155 NS_IMETHODIMP mozXMLTerminal::SetHistory(PRInt32 aHistory)
00156 {
00157   if (!mXMLTermSession)
00158     return NS_ERROR_FAILURE;
00159 
00160   return mXMLTermSession->SetHistory(aHistory);
00161 }
00162 
00163 NS_IMETHODIMP mozXMLTerminal::GetPrompt(PRUnichar **aPrompt)
00164 {
00165   if (!mXMLTermSession)
00166     return NS_ERROR_FAILURE;
00167 
00168   return mXMLTermSession->GetPrompt(aPrompt);
00169 }
00170 
00171 
00172 NS_IMETHODIMP mozXMLTerminal::SetPrompt(const PRUnichar* aPrompt)
00173 {
00174   if (!mXMLTermSession)
00175     return NS_ERROR_FAILURE;
00176 
00177   return mXMLTermSession->SetPrompt(aPrompt);
00178 }
00179 
00180 
00181 NS_IMETHODIMP mozXMLTerminal::GetKeyIgnore(PRBool* aIgnore)
00182 {
00183   if (!mKeyListener)
00184     return NS_ERROR_FAILURE;
00185 
00186   nsCOMPtr<mozIXMLTermSuspend> suspend= do_QueryInterface(mKeyListener);
00187   if (!suspend)
00188     return NS_ERROR_FAILURE;
00189 
00190   return suspend->GetSuspend(aIgnore);
00191 }
00192 
00193 
00194 NS_IMETHODIMP mozXMLTerminal::SetKeyIgnore(const PRBool aIgnore)
00195 {
00196   if (!mKeyListener)
00197     return NS_ERROR_FAILURE;
00198 
00199   nsCOMPtr<mozIXMLTermSuspend> suspend= do_QueryInterface(mKeyListener);
00200   if (!suspend)
00201     return NS_ERROR_FAILURE;
00202 
00203   return suspend->SetSuspend(aIgnore);
00204 }
00205 
00206 
00207 // Initialize by starting load of Init page for XMLTerm
00208 NS_IMETHODIMP mozXMLTerminal::Init(nsIDocShell* aDocShell,
00209                                    mozIXMLTermShell* aXMLTermShell,
00210                                    const PRUnichar* aURL,
00211                                    const PRUnichar* args)
00212 {
00213   XMLT_LOG(mozXMLTerminal::Init,20,("\n"));
00214 
00215   if (!aDocShell)
00216       return NS_ERROR_NULL_POINTER;
00217 
00218   if (mInitialized)
00219     return NS_ERROR_ALREADY_INITIALIZED;
00220 
00221   // Initialization flag
00222   mInitialized = PR_TRUE;
00223 
00224   // Containing docshell
00225   mDocShell = do_GetWeakReference(aDocShell); // weak ref
00226 
00227   mXMLTermShell = aXMLTermShell;  // containing xmlterm shell; no addref
00228 
00229   nsresult result = NS_OK;
00230 
00231   // NOTE: Need to parse args string!!!
00232   mCommand.SetLength(0);
00233   mPromptExpr.SetLength(0);
00234   mInitInput = args;
00235 
00236   if ((aURL != nsnull) && (*aURL != 0)) {
00237     // Load URL and activate XMLTerm after loading
00238     XMLT_LOG(mozXMLTerminal::Init,22,("setting DocLoaderObs\n"));
00239 
00240     // About to create owning reference to this
00241     nsCOMPtr<nsIWebProgress> progress(do_GetInterface(aDocShell, &result));
00242     if (NS_FAILED(result)) return result;
00243 
00244     result = progress->AddProgressListener((nsIWebProgressListener*)this,
00245                                            nsIWebProgress::NOTIFY_STATE_REQUEST);
00246     if (NS_FAILED(result))
00247       return NS_ERROR_FAILURE;
00248 
00249     XMLT_LOG(mozXMLTerminal::Init,22,("done setting DocLoaderObs\n"));
00250 
00251     // Load initial XMLterm background document
00252     nsCOMPtr<nsIURI> uri;
00253     result = NS_NewURI(getter_AddRefs(uri), nsDependentString(aURL));
00254     if (NS_FAILED(result))
00255       return NS_ERROR_FAILURE;
00256 
00257     result = aDocShell->LoadURI(uri, nsnull, nsIWebNavigation::LOAD_FLAGS_NONE, PR_TRUE);
00258     if (NS_FAILED(result))
00259       return NS_ERROR_FAILURE;
00260 
00261   } else {
00262     // Document already loaded; activate XMLTerm
00263     result = Activate();
00264     if (NS_FAILED(result))
00265       return NS_ERROR_FAILURE;
00266   }
00267 
00268   XMLT_LOG(mozXMLTerminal::Init,21,("exiting\n"));
00269   return result;
00270 }
00271 
00272 
00273 // De-initialize XMLTerminal
00274 NS_IMETHODIMP mozXMLTerminal::Finalize(void)
00275 {
00276   if (!mInitialized)
00277     return NS_OK;
00278 
00279   XMLT_LOG(mozXMLTerminal::Finalize,20,("\n"));
00280 
00281   mInitialized = PR_FALSE;
00282 
00283   if (mXMLTermSession) {
00284     // Finalize XMLTermSession object and delete it (it is not ref. counted)
00285     mXMLTermSession->Finalize();
00286     delete mXMLTermSession;
00287     mXMLTermSession = nsnull;
00288   }
00289 
00290   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryReferent(mDOMDocument);
00291 
00292   if (domDoc) {
00293     // Release any event listeners for the document
00294     nsCOMPtr<nsIDOMEventReceiver> eventReceiver;
00295     nsresult result = domDoc->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(eventReceiver));
00296 
00297     if (NS_SUCCEEDED(result) && eventReceiver) {
00298       if (mKeyListener) {
00299         eventReceiver->RemoveEventListenerByIID(mKeyListener,
00300                                                 NS_GET_IID(nsIDOMKeyListener));
00301         mKeyListener = nsnull;
00302       }
00303 
00304       if (mTextListener) {
00305         eventReceiver->RemoveEventListenerByIID(mTextListener,
00306                                                 NS_GET_IID(nsIDOMTextListener));
00307         mTextListener = nsnull;
00308       }
00309 
00310       if (mMouseListener) {
00311         eventReceiver->RemoveEventListenerByIID(mMouseListener,
00312                                                 NS_GET_IID(nsIDOMMouseListener));
00313         mMouseListener = nsnull;
00314       }
00315 
00316       if (mDragListener) {
00317         eventReceiver->RemoveEventListenerByIID(mDragListener,
00318                                                 NS_GET_IID(nsIDOMDragListener));
00319         mDragListener = nsnull;
00320       }
00321     }
00322   }
00323 
00324   mDOMDocument = nsnull;
00325 
00326   if (mLineTermAux) {
00327     // Finalize and release reference to LineTerm object owned by us
00328     mLineTermAux->CloseAux();
00329     mLineTermAux = nsnull;
00330   }
00331 
00332   mDocShell = nsnull;
00333 
00334   mPresShell = nsnull;
00335   mXMLTermShell = nsnull;
00336 
00337   XMLT_LOG(mozXMLTerminal::Finalize,22,("END\n"));
00338 
00339   return NS_OK;
00340 }
00341 
00342 
00346 NS_IMETHODIMP mozXMLTerminal::Activate(void)
00347 {
00348   nsresult result = NS_OK;
00349 
00350 #if 0
00351   // TEMPORARY: Testing mozIXMLTermStream
00352   nsAutoString streamData(  "<HTML><HEAD><TITLE>Stream Title</TITLE>"
00353                             "<SCRIPT language='JavaScript'>"
00354                             "function clik(){ dump('click\\n');return(false);}"
00355                             "</SCRIPT></HEAD>"
00356                             "<BODY><B>Stream Body "
00357                             "<SPAN STYLE='color: blue' onClick='return clik();'>Clik</SPAN></B><BR>"
00358 "<TABLE WIDTH=720><TR><TD WIDTH=700 BGCOLOR=maroon>&nbsp;</TABLE>"
00359                             "<BR>ABCD<BR>EFGH<BR>JKLM<BR>"
00360                             "</BODY></HTML>" );
00361 
00362   nsCOMPtr<mozIXMLTermStream> stream;
00363   result = NS_NewXMLTermStream(getter_AddRefs(stream));
00364   if (NS_FAILED(result)) {
00365     XMLT_ERROR("mozXMLTerminal::Activate: Failed to create stream\n");
00366     return result;
00367   }
00368 
00369   nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell);
00370   if (!docShell)
00371     return NS_ERROR_FAILURE;
00372 
00373   nsCOMPtr<nsIDOMWindowInternal> outerDOMWindow;
00374   result = mozXMLTermUtils::ConvertDocShellToDOMWindow(docShell,
00375                                               getter_AddRefs(outerDOMWindow));
00376 
00377   if (NS_FAILED(result) || !outerDOMWindow) {
00378     XMLT_ERROR("mozXMLTerminal::Activate: Failed to convert docshell\n");
00379     return NS_ERROR_FAILURE;
00380   }
00381 
00382   result = stream->Open(outerDOMWindow, "iframet", "chrome://dummy",
00383                         "text/html", 800);
00384   if (NS_FAILED(result)) {
00385     XMLT_ERROR("mozXMLTerminal::Activate: Failed to open stream\n");
00386     return result;
00387   }
00388 
00389   result = stream->Write(streamData.get());
00390   if (NS_FAILED(result)) {
00391     XMLT_ERROR("mozXMLTerminal::Activate: Failed to write to stream\n");
00392     return result;
00393   }
00394 
00395   result = stream->Close();
00396   if (NS_FAILED(result)) {
00397     XMLT_ERROR("mozXMLTerminal::Activate: Failed to close stream\n");
00398     return result;
00399   }
00400 
00401 #endif
00402 
00403   XMLT_LOG(mozXMLTerminal::Activate,20,("\n"));
00404 
00405   if (!mInitialized)
00406     return NS_ERROR_NOT_INITIALIZED;
00407 
00408   PR_ASSERT(mDocShell != nsnull);
00409 
00410   if ((mDOMDocument != nsnull) || (mPresShell != nsnull))
00411     return NS_ERROR_FAILURE;
00412 
00413   nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell);
00414   if (!docShell)
00415     return NS_ERROR_FAILURE;
00416 
00417   // Get reference to presentation shell
00418   nsCOMPtr<nsPresContext> presContext;
00419   result = docShell->GetPresContext(getter_AddRefs(presContext));
00420   if (NS_FAILED(result) || !presContext)
00421     return NS_ERROR_FAILURE;
00422 
00423   nsCOMPtr<nsIPresShell> presShell;
00424   result = docShell->GetPresShell(getter_AddRefs(presShell));
00425   if (NS_FAILED(result) || !presShell)
00426     return NS_ERROR_FAILURE;
00427 
00428   // Get reference to DOMDocument
00429   nsIDocument *document = presShell->GetDocument();
00430   if (!document)
00431     return NS_ERROR_FAILURE;
00432 
00433   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(document);
00434   if (!domDoc)
00435     return NS_ERROR_FAILURE;
00436 
00437   // Save weak references to presentation shell and DOMDocument
00438   mPresShell   = do_GetWeakReference(presShell); // weak ref
00439   mDOMDocument = do_GetWeakReference(domDoc);    // weak ref
00440 
00441   // Show caret
00442   ShowCaret();
00443 
00444   // Determine current screen dimensions
00445   PRInt32 nRows, nCols, xPixels, yPixels;
00446   result = ScreenSize(&nRows, &nCols, &xPixels, &yPixels);
00447   if (NS_FAILED(result))
00448     return result;
00449 
00450   // The above call does not return the correct screen dimensions.
00451   // (because rendering is still in progress?)
00452   // As a workaround, explicitly set screen dimensions
00453   nRows = 24;
00454   nCols = 80;
00455   xPixels = 0;
00456   yPixels = 0;
00457 
00458   // Instantiate and initialize XMLTermSession object
00459   mXMLTermSession = new mozXMLTermSession();
00460 
00461   if (!mXMLTermSession) {
00462     return NS_ERROR_OUT_OF_MEMORY;
00463   }
00464 
00465   result = mXMLTermSession->Init(this, presShell, domDoc, nRows, nCols);
00466   if (NS_FAILED(result)) {
00467     XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to initialize XMLTermSession\n");
00468     return NS_ERROR_FAILURE;
00469   }
00470 
00471   // Instantiate LineTerm  
00472   XMLT_LOG(mozXMLTerminal::Activate,22,
00473            ("instantiating lineterm, nRows=%d, nCols=%d\n", nRows, nCols));
00474   mLineTermAux = do_CreateInstance(MOZLINETERM_CONTRACTID, &result);
00475   if (NS_FAILED(result)) {
00476     XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to instantiate LineTermAux\n");
00477     return result;
00478   }
00479 
00480   // Open LineTerm to execute command
00481   // Non-owning reference to this; delete LineTerm before deleting self
00482   PRInt32 options = 0;
00483 
00484   XMLT_LOG(mozXMLTerminal::Activate,22,("Opening LineTerm\n"));
00485   nsCOMPtr<nsIObserver> anObserver = this;
00486 #ifdef NO_CALLBACK
00487   anObserver = nsnull;
00488 #endif
00489   nsAutoString cookie;
00490   result = mLineTermAux->OpenAux(mCommand.get(),
00491                                  mInitInput.get(),
00492                                  mPromptExpr.get(),
00493                                  options, LTERM_DETERMINE_PROCESS,
00494                                  nRows, nCols, xPixels, yPixels,
00495                                  domDoc, anObserver, cookie);
00496 
00497   if (NS_FAILED(result)) {
00498     XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to open LineTermAux\n");
00499     return result;
00500   }
00501   XMLT_LOG(mozXMLTerminal::Activate,22,("Opened LineTerm\n"));
00502 
00503   // Save cookie
00504   mCookie = cookie;
00505 
00506   // Get the DOM event receiver for document
00507   nsCOMPtr<nsIDOMEventReceiver> eventReceiver;
00508   result = domDoc->QueryInterface(NS_GET_IID(nsIDOMEventReceiver),
00509                                         getter_AddRefs(eventReceiver));
00510   if (NS_FAILED(result)) {
00511     XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get DOM receiver\n");
00512     return result;
00513   }
00514 
00515   // Create a key listener
00516   result = NS_NewXMLTermKeyListener(getter_AddRefs(mKeyListener), this);
00517   if (NS_OK != result) {
00518     XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get key listener\n");
00519     return result;
00520   }
00521 
00522   // Register the key listener with the DOM event receiver
00523   result = eventReceiver->AddEventListenerByIID(mKeyListener,
00524                                                 NS_GET_IID(nsIDOMKeyListener));
00525 
00526   if (NS_FAILED(result)) {
00527     XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to register key listener\n");
00528     return result;
00529   }
00530 
00531   // Create a text listener
00532   result = NS_NewXMLTermTextListener(getter_AddRefs(mTextListener), this);
00533   if (NS_OK != result) {
00534     XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get text listener\n");
00535     return result;
00536   }
00537 
00538   // Register the text listener with the DOM event receiver
00539   result = eventReceiver->AddEventListenerByIID(mTextListener,
00540                                                 NS_GET_IID(nsIDOMTextListener));
00541   if (NS_FAILED(result)) {
00542     XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to register text listener\n");
00543     return result;
00544   }
00545 
00546   // Create a mouse listener
00547   result = NS_NewXMLTermMouseListener(getter_AddRefs(mMouseListener), this);
00548   if (NS_OK != result) {
00549     XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get mouse listener\n");
00550     return result;
00551   }
00552 
00553   // Register the mouse listener with the DOM event receiver
00554   result = eventReceiver->AddEventListenerByIID(mMouseListener,
00555                                                 NS_GET_IID(nsIDOMMouseListener));
00556   if (NS_FAILED(result)) {
00557     XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to register mouse listener\n");
00558     return result;
00559   }
00560 
00561   // Create a drag listener
00562   result = NS_NewXMLTermDragListener(getter_AddRefs(mDragListener), this);
00563   if (NS_OK != result) {
00564     XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to get drag listener\n");
00565     return result;
00566   }
00567 
00568   // Register the drag listener with the DOM event receiver
00569   result = eventReceiver->AddEventListenerByIID(mDragListener,
00570                                                 NS_GET_IID(nsIDOMDragListener));
00571   if (NS_FAILED(result)) {
00572     XMLT_WARNING("mozXMLTerminal::Activate: Warning - Failed to register drag listener\n");
00573     return result;
00574   }
00575 
00576   return NS_OK;
00577 }
00578 
00579 
00586 NS_IMETHODIMP mozXMLTerminal::ScreenSize(PRInt32* rows, PRInt32* cols,
00587                                          PRInt32* xPixels, PRInt32* yPixels)
00588 {
00589   nsresult result;
00590 
00591   XMLT_LOG(mozXMLTerminal::ScreenSize,70,("\n"));
00592 
00593   nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
00594   if (!presShell)
00595     return NS_ERROR_FAILURE;
00596 
00597   // Get presentation context
00598   nsPresContext *presContext = presShell->GetPresContext();
00599 
00600   // Get the default fixed pitch font
00601   const nsFont* defaultFixedFont =
00602     presContext->GetDefaultFont(kPresContext_DefaultFixedFont_ID);
00603 
00604   // Get metrics for fixed font
00605   nsCOMPtr<nsIFontMetrics> fontMetrics =
00606     presContext->GetMetricsFor(*defaultFixedFont);
00607   if (!fontMetrics)
00608     return NS_ERROR_FAILURE;
00609 
00610   // Get font height (includes leading?)
00611   nscoord fontHeight, fontWidth;
00612   result = fontMetrics->GetHeight(fontHeight);
00613   result = fontMetrics->GetMaxAdvance(fontWidth);
00614 
00615   // Determine docshell size in twips
00616   nsRect shellArea = presContext->GetVisibleArea();
00617 
00618   // Determine twips to pixels conversion factor
00619   float pixelScale;
00620   pixelScale = presContext->TwipsToPixels();
00621 
00622   // Convert dimensions to pixels
00623   float xdel, ydel;
00624   xdel = pixelScale * fontWidth;
00625   ydel = pixelScale * fontHeight + 2;
00626 
00627   *xPixels = (int) (pixelScale * shellArea.width);
00628   *yPixels = (int) (pixelScale * shellArea.height);
00629 
00630   // Determine number of rows/columns
00631   *rows = (int) ((*yPixels-16) / ydel);
00632   *cols = (int) ((*xPixels-20) / xdel);
00633 
00634   if (*rows < 1) *rows = 1;
00635   if (*cols < 1) *cols = 1;
00636 
00637   XMLT_LOG(mozXMLTerminal::ScreenSize,72,
00638            ("rows=%d, cols=%d, xPixels=%d, yPixels=%d\n",
00639             *rows, *cols, *xPixels, *yPixels));
00640 
00641   return NS_OK;
00642 }
00643 
00644 
00645 // Transmit string to LineTerm (use saved cookie)
00646 NS_IMETHODIMP mozXMLTerminal::SendTextAux(const PRUnichar* aString)
00647 {
00648   return SendText(aString, mCookie.get());
00649 }
00650 
00651 
00652 // Transmit string to LineTerm
00653 NS_IMETHODIMP mozXMLTerminal::SendText(const PRUnichar* aString,
00654                                        const PRUnichar* aCookie)
00655 {
00656   nsresult result;
00657 
00658   if (!mLineTermAux)
00659     return NS_ERROR_FAILURE;
00660 
00661   nsAutoString sendStr(aString);
00662 
00663   // Preprocess string and check if it is to be consumed
00664   PRBool consumed, checkSize;
00665   result = mXMLTermSession->Preprocess(sendStr, consumed, checkSize);
00666 
00667   PRBool screenMode;
00668   GetScreenMode(&screenMode);
00669 
00670   if (!screenMode && (checkSize || mNeedsResizing)) {
00671     // Resize terminal, if need be
00672     mXMLTermSession->Resize(mLineTermAux);
00673     mNeedsResizing = PR_FALSE;
00674   }
00675 
00676   if (!consumed) {
00677     result = mLineTermAux->Write(sendStr.get(), aCookie);
00678     if (NS_FAILED(result)) {
00679       // Abort XMLterm session
00680       nsAutoString abortCode;
00681       abortCode.AssignLiteral("SendText");
00682       mXMLTermSession->Abort(mLineTermAux, abortCode);
00683       return NS_ERROR_FAILURE;
00684     }
00685   }
00686 
00687   return NS_OK;
00688 }
00689 
00692 NS_IMETHODIMP mozXMLTerminal::ShowCaret(void)
00693 {
00694   // In principle, this method needs to be called only once;
00695   // in practice, certain operations seem to hide the caret
00696   // especially when one starts mucking around with the display:
00697   // style property.
00698   // Under those circumstances, call this method to re-display the caret.
00699 
00700   XMLT_LOG(mozXMLTerminal::ShowCaret,70,("\n"));
00701 
00702   if (!mPresShell)
00703     return NS_ERROR_FAILURE;
00704 
00705   nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
00706   if (!presShell)
00707     return NS_ERROR_FAILURE;
00708 
00709   nsCOMPtr<nsISelectionController> selCon = do_QueryInterface(presShell);
00710 
00711   if (!selCon) {
00712     XMLT_WARNING("mozXMLTerminal::ShowCaret: Warning - Failed to get SelectionController\n");
00713     return NS_ERROR_FAILURE;
00714   }
00715 
00716   selCon->SetCaretEnabled(PR_TRUE);
00717   selCon->SetCaretReadOnly(PR_FALSE);
00718 
00719   nsCOMPtr<nsICaret> caret;
00720   if (NS_SUCCEEDED(presShell->GetCaret(getter_AddRefs(caret))) && caret) {
00721 
00722     caret->SetCaretVisible(PR_TRUE);
00723     caret->SetCaretReadOnly(PR_FALSE);
00724 
00725     nsCOMPtr<nsISelection> sel;
00726 
00727     if (NS_SUCCEEDED(selCon->GetSelection(nsISelectionController::SELECTION_NORMAL, getter_AddRefs(sel))) && sel) {
00728       caret->SetCaretDOMSelection(sel);
00729     }
00730   } else {
00731     XMLT_WARNING("mozXMLTerminal::ShowCaret: Warning - Failed to get caret\n");
00732   }
00733 
00734   return NS_OK;
00735 }
00736 
00737 
00738 // Paste data from clipboard to terminal
00739 NS_IMETHODIMP mozXMLTerminal::Paste()
00740 {
00741   nsresult result;
00742   nsAutoString pasteString;
00743 
00744   XMLT_LOG(mozXMLTerminal::Paste,20,("\n"));
00745 
00746   // Get Clipboard service
00747   nsCOMPtr<nsIClipboard> clipboard(do_GetService(kCClipboardCID, &result));
00748   if ( NS_FAILED(result) )
00749     return result;
00750     
00751   // Generic transferable for getting clipboard data
00752   nsCOMPtr<nsITransferable> trans = do_CreateInstance(kCTransferableCID, &result);
00753   if (NS_FAILED(result) || !trans)
00754     return NS_ERROR_FAILURE;
00755 
00756   // DataFlavors to get out of transferable
00757   // trans->AddDataFlavor(kHTMLMime); // Cannot handle HTML yet
00758   trans->AddDataFlavor(kUnicodeMime);
00759 
00760   // Get data from clipboard
00761   result = clipboard->GetData(trans, nsIClipboard::kSelectionClipboard);
00762   if (NS_FAILED(result))
00763     return result;
00764 
00765   char* bestFlavor = nsnull;
00766   nsCOMPtr<nsISupports> genericDataObj;
00767   PRUint32 objLen = 0;
00768   result = trans->GetAnyTransferData(&bestFlavor,
00769                                      getter_AddRefs(genericDataObj), &objLen);
00770   if (NS_FAILED(result))
00771     return result;
00772 
00773   XMLT_LOG(mozXMLTerminal::Paste,20,("flavour=%s\n", bestFlavor));
00774 
00775   if (strcmp(bestFlavor, kHTMLMime) == 0 || strcmp(bestFlavor, kUnicodeMime) == 0) {
00776     nsCOMPtr<nsISupportsString> textDataObj ( do_QueryInterface(genericDataObj) );
00777     if (textDataObj && objLen > 0) {
00778       PRUnichar* text = nsnull;
00779       textDataObj->ToString ( &text );
00780       pasteString.Assign( text, objLen / 2 );
00781       result = SendTextAux(pasteString.get());
00782     }
00783   }
00784   nsMemory::Free(bestFlavor);
00785 
00786   return NS_OK;
00787 }
00788 
00789 
00790 // Poll for readable data from LineTerm
00791 NS_IMETHODIMP mozXMLTerminal::Poll(void)
00792 {
00793   if (!mLineTermAux)
00794     return NS_ERROR_NOT_INITIALIZED;
00795 
00796   XMLT_LOG(mozXMLTerminal::Poll,20,("\n"));
00797 
00798   nsresult result;
00799   PRBool processedData;
00800 
00801   result = mXMLTermSession->ReadAll(mLineTermAux, processedData);
00802   if (NS_FAILED(result)) {
00803     XMLT_WARNING("mozXMLTerminal::Poll: Warning - Error return 0x%x from ReadAll\n", result);
00804     return result;
00805   }
00806 
00807   return NS_OK;
00808 }
00809 
00810 
00811 // Handle callback from LineTerm when new input/output needs to be displayed
00812 NS_IMETHODIMP mozXMLTerminal::Observe(nsISupports *aSubject,
00813                                   const char *aTopic,
00814                                   const PRUnichar *someData)
00815 {
00816   nsCOMPtr<mozILineTermAux> lineTermAux = do_QueryInterface(aSubject);
00817   PR_ASSERT(lineTermAux != nsnull);
00818 
00819   PR_ASSERT(lineTermAux.get() == mLineTermAux.get());
00820 
00821   return Poll();
00822 }
00823 
00824 
00825 // Returns document associated with XMLTerminal
00826 NS_IMETHODIMP mozXMLTerminal::GetDocument(nsIDOMDocument** aDoc)
00827 {
00828   if (!aDoc)
00829     return NS_ERROR_NULL_POINTER;
00830 
00831   *aDoc = nsnull;
00832 
00833   NS_PRECONDITION(mDOMDocument, "bad state, null mDOMDocument");
00834   if (!mDOMDocument)
00835     return NS_ERROR_NOT_INITIALIZED;
00836 
00837   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryReferent(mDOMDocument);
00838   if (!domDoc)
00839     return NS_ERROR_FAILURE;
00840 
00841   return domDoc->QueryInterface(NS_GET_IID(nsIDOMDocument),
00842                                       (void **)aDoc);
00843 }
00844 
00845 
00846 // Returns doc shell associated with XMLTerm
00847 NS_IMETHODIMP mozXMLTerminal::GetDocShell(nsIDocShell** aDocShell)
00848 {
00849   if (!aDocShell)
00850     return NS_ERROR_NULL_POINTER;
00851 
00852   *aDocShell = nsnull;
00853 
00854   NS_PRECONDITION(mDocShell, "bad state, null mDocShell");
00855   if (!mDocShell)
00856     return NS_ERROR_NOT_INITIALIZED;
00857 
00858   nsCOMPtr<nsIDocShell> docShell = do_QueryReferent(mDocShell);
00859   if (!docShell) {
00860     XMLT_ERROR("mozXMLTerminal::GetDocShell: Error - Invalid weak reference\n");
00861     return NS_ERROR_FAILURE;
00862   }
00863 
00864   return docShell->QueryInterface(NS_GET_IID(nsIDocShell),
00865                                     (void **)aDocShell);
00866 }
00867 
00868 
00869 // Returns presentation shell associated with XMLTerm
00870 NS_IMETHODIMP mozXMLTerminal::GetPresShell(nsIPresShell** aPresShell)
00871 {
00872   if (!aPresShell)
00873     return NS_ERROR_NULL_POINTER;
00874 
00875   *aPresShell = nsnull;
00876 
00877   NS_PRECONDITION(mPresShell, "bad state, null mPresShell");
00878   if (!mPresShell)
00879     return NS_ERROR_NOT_INITIALIZED;
00880 
00881   nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
00882   if (!presShell) {
00883     XMLT_ERROR("mozXMLTerminal::GetPresShell: Error - Invalid weak reference\n");
00884     return NS_ERROR_FAILURE;
00885   }
00886 
00887   return presShell->QueryInterface(NS_GET_IID(nsIPresShell),
00888                                     (void **)aPresShell);
00889 }
00890 
00891 
00892 // Returns DOMDocument associated with XMLTerm
00893 NS_IMETHODIMP mozXMLTerminal::GetDOMDocument(nsIDOMDocument** aDOMDocument)
00894 {
00895   if (!aDOMDocument)
00896     return NS_ERROR_NULL_POINTER;
00897 
00898   *aDOMDocument = nsnull;
00899 
00900   NS_PRECONDITION(mDOMDocument, "bad state, null mDOMDocument");
00901   if (!mDOMDocument)
00902     return NS_ERROR_NOT_INITIALIZED;
00903 
00904   nsCOMPtr<nsIDOMDocument> domDoc = do_QueryReferent(mDOMDocument);
00905   if (!domDoc) {
00906     XMLT_ERROR("mozXMLTerminal::GetDOMDocument: Error - Invalid weak reference\n");
00907     return NS_ERROR_FAILURE;
00908   }
00909 
00910   return domDoc->QueryInterface(NS_GET_IID(nsIDOMDocument),
00911                                 (void **)aDOMDocument);
00912 }
00913 
00914 
00915 // Returns SelectionController associated with XMLTerm
00916 NS_IMETHODIMP mozXMLTerminal::GetSelectionController(nsISelectionController** aSelectionController)
00917 {
00918   if (!aSelectionController)
00919     return NS_ERROR_NULL_POINTER;
00920 
00921   *aSelectionController = nsnull;
00922 
00923   NS_PRECONDITION(mPresShell, "bad state, null mPresShell");
00924   if (!mPresShell)
00925     return NS_ERROR_NOT_INITIALIZED;
00926 
00927   nsCOMPtr<nsIPresShell> presShell = do_QueryReferent(mPresShell);
00928   if (!presShell) {
00929     XMLT_ERROR("mozXMLTerminal::GetSelectionControlle: Error - Invalid weak reference\n");
00930     return NS_ERROR_FAILURE;
00931   }
00932 
00933   return presShell->QueryInterface(NS_GET_IID(nsISelectionController),
00934                                 (void **)aSelectionController);
00935 }
00936 
00937 
00941 NS_IMETHODIMP mozXMLTerminal::GetScreenMode(PRBool* aFlag)
00942 {
00943   return mXMLTermSession->GetScreenMode(aFlag);
00944 }
00945 
00946 
00951 NS_IMETHODIMP mozXMLTerminal::MatchesCookie(const PRUnichar* aCookie,
00952                                             PRBool *_retval)
00953 {
00954   XMLT_LOG(mozXMLTerminal::MatchesCookie,20,("\n"));
00955 
00956   if (!_retval)
00957     return NS_ERROR_NULL_POINTER;
00958 
00959   // Check if supplied cookie matches XMLTerm cookie
00960   *_retval = mCookie.Equals(aCookie);
00961 
00962   if (!(*_retval)) {
00963     XMLT_ERROR("mozXMLTerminal::MatchesCookie: Error - Cookie mismatch\n");
00964     return NS_ERROR_FAILURE;
00965   }
00966 
00967   return NS_OK;
00968 }
00969 
00970 
00973 NS_IMETHODIMP mozXMLTerminal::Resize(void)
00974 {
00975   nsresult result;
00976 
00977   XMLT_LOG(mozXMLTerminal::Resize,20,("\n"));
00978 
00979   if (!mXMLTermSession)
00980     return NS_ERROR_FAILURE;
00981 
00982   PRBool screenMode;
00983   GetScreenMode(&screenMode);
00984 
00985   if (screenMode) {
00986     // Delay resizing until next input processing
00987     mNeedsResizing = PR_TRUE;
00988   } else {
00989     // Resize session
00990     result = mXMLTermSession->Resize(mLineTermAux);
00991     if (NS_FAILED(result))
00992       return result;
00993   }
00994 
00995   return NS_OK;
00996 }
00997 
01003 NS_IMETHODIMP mozXMLTerminal::ExportHTML(const PRUnichar* aFilename,
01004                                          PRInt32 permissions,
01005                                          const PRUnichar* style,
01006                                          PRUint32 refreshSeconds,
01007                                          PRBool forceExport,
01008                                          PRBool* exported)
01009 {
01010   if (!mXMLTermSession)
01011     return NS_ERROR_FAILURE;
01012 
01013   return mXMLTermSession->ExportHTML( aFilename, permissions, style,
01014                                       refreshSeconds, forceExport,
01015                                       exported);
01016 }
01017 
01018 // nsIWebProgressListener methods
01019 NS_IMETHODIMP
01020 mozXMLTerminal::OnStateChange(nsIWebProgress* aWebProgress, 
01021                    nsIRequest *aRequest, 
01022                    PRUint32 progressStateFlags,
01023                    nsresult aStatus) {
01024     if (progressStateFlags & nsIWebProgressListener::STATE_IS_REQUEST)
01025         if (progressStateFlags & nsIWebProgressListener::STATE_START) {
01026             XMLT_LOG(mozXMLTerminal::OnStateChange,20,("\n"));
01027 
01028             // Activate XMLTerm
01029             Activate();
01030         }
01031     return NS_OK;
01032 
01033 }
01034 
01035 NS_IMETHODIMP
01036 mozXMLTerminal::OnProgressChange(nsIWebProgress *aWebProgress,
01037                                      nsIRequest *aRequest,
01038                                      PRInt32 aCurSelfProgress,
01039                                      PRInt32 aMaxSelfProgress,
01040                                      PRInt32 aCurTotalProgress,
01041                                      PRInt32 aMaxTotalProgress) {
01042     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
01043     return NS_OK;
01044 }
01045 
01046 NS_IMETHODIMP
01047 mozXMLTerminal::OnLocationChange(nsIWebProgress* aWebProgress,
01048                       nsIRequest* aRequest,
01049                       nsIURI *location) {
01050     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
01051     return NS_OK;
01052 }
01053 
01054 
01055 NS_IMETHODIMP
01056 mozXMLTerminal::OnStatusChange(nsIWebProgress* aWebProgress,
01057                     nsIRequest* aRequest,
01058                     nsresult aStatus,
01059                     const PRUnichar* aMessage) {
01060     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
01061     return NS_OK;
01062 }
01063 
01064 
01065 NS_IMETHODIMP
01066 mozXMLTerminal::OnSecurityChange(nsIWebProgress *aWebProgress, 
01067                       nsIRequest *aRequest, 
01068                       PRUint32 state) {
01069     NS_NOTREACHED("notification excluded in AddProgressListener(...)");
01070     return NS_OK;
01071 }