GME  13
ConsoleCtl.cpp
Go to the documentation of this file.
00001 // ConsoleCtl.cpp : Implementation of the CConsoleCtrl ActiveX Control class.
00002 
00003 #include "stdafx.h"
00004 #include "Console.h"
00005 #include "Console_i.h"
00006 #include "ConsoleCtl.h"
00007 #include "ConsolePpg.h"
00008 #include "GME.h"
00009 #include "MgaUtil.h"
00010 #include <mshtml.h>         //IWeb objects
00011 #include <limits.h>
00012 #include <afx.h>
00013 #include "Strsafe.h"
00014 
00015 #define BUTTON_ICON_SIZE                16
00016 
00017 
00018 #ifdef _DEBUG
00019 #define new DEBUG_NEW
00020 #undef THIS_FILE
00021 static char THIS_FILE[] = __FILE__;
00022 #endif
00023 
00024 
00025 IMPLEMENT_DYNCREATE(CConsoleCtrl, COleControl)
00026 
00027 
00028 // Message map
00029 
00030 BEGIN_MESSAGE_MAP(CConsoleCtrl, COleControl)
00031         //{{AFX_MSG_MAP(CConsoleCtrl)
00032         ON_WM_CREATE()
00033         //}}AFX_MSG_MAP
00034         ON_OLEVERB(AFX_IDS_VERB_PROPERTIES, OnProperties)
00035         ON_COMMAND( IDC_MENU_COMMAND, OnShowMenu)
00036         ON_COMMAND( IDC_LOADSCRIPT_COMMAND, LoadScriptDlg)
00037         ON_COMMAND( IDC_RUNSCRIPT_COMMAND, runScript)
00038         ON_COMMAND( IDC_RELOAD_COMMAND, relScript)
00039         ON_COMMAND( IDC_RELOADRUN_COMMAND, rlrScript)
00040         ON_COMMAND( IDC_CLEARCONSOLE_COMMAND, Clear)
00041         ON_COMMAND( IDC_SELECTENGINE_COMMAND, selectEngine)
00042         ON_COMMAND( IDC_PREV_COMMAND, prevCommand)
00043         ON_COMMAND( IDC_NEXT_COMMAND, nextCommand)
00044         ON_COMMAND( IDC_RETURN_COMMAND, retCommand)
00045         ON_COMMAND_RANGE( IDC_RECENT_SCRIPT1, IDC_RECENT_SCRIPT5, loadRecent)
00046         ON_NOTIFY_EX( TTN_NEEDTEXT, 0, OnToolTipNotify)
00047 END_MESSAGE_MAP()
00048 
00049 
00051 // Dispatch map
00052 
00053 BEGIN_DISPATCH_MAP(CConsoleCtrl, COleControl)
00054         //{{AFX_DISPATCH_MAP(CConsoleCtrl)
00055         DISP_PROPERTY_EX(CConsoleCtrl, "Contents", GetContents, SetContents, VT_BSTR)
00056         DISP_FUNCTION(CConsoleCtrl, "Message", Message, VT_EMPTY, VTS_BSTR VTS_I2)
00057         DISP_FUNCTION(CConsoleCtrl, "Clear", Clear, VT_EMPTY, VTS_NONE)
00058         DISP_DEFVALUE(CConsoleCtrl, "Contents")
00059         DISP_FUNCTION(CConsoleCtrl, "SetGMEApp", SetGMEApp, VT_EMPTY, VTS_DISPATCH)
00060         DISP_FUNCTION(CConsoleCtrl, "SetGMEProj", SetGMEProj, VT_EMPTY, VTS_DISPATCH)
00061         DISP_FUNCTION_ID(CConsoleCtrl, "NavigateTo", dispidNavigateTo, NavigateTo, VT_EMPTY, VTS_BSTR)
00062     DISP_FUNCTION(CConsoleCtrl, "LoadScript", LoadScript, VT_EMPTY, VTS_BSTR)
00063         DISP_FUNCTION(CConsoleCtrl, "RunLoadedScript", RunScript, VT_EMPTY, VTS_NONE)
00064         DISP_FUNCTION(CConsoleCtrl, "SetContents", SetContents, VT_EMPTY, VTS_BSTR)
00065         DISP_FUNCTION(CConsoleCtrl, "RunCode", RunCode, VT_EMPTY, VTS_BSTR)
00066         DISP_PROPERTY_EX_ID(CConsoleCtrl, "GetCWnd", 0x43576E64, GetCWnd, SetCWnd, VT_I8)
00067         DISP_FUNCTION_ID(CConsoleCtrl, "AboutBox", DISPID_ABOUTBOX, AboutBox, VT_EMPTY, VTS_NONE)
00068         //}}AFX_DISPATCH_MAP
00069 END_DISPATCH_MAP()
00070 
00071 
00073 // Event map
00074 
00075 BEGIN_EVENT_MAP(CConsoleCtrl, COleControl)
00076         //{{AFX_EVENT_MAP(CConsoleCtrl)
00077         EVENT_CUSTOM("ClickMGAID", FireClickMGAID, VTS_BSTR)
00078         //}}AFX_EVENT_MAP
00079 END_EVENT_MAP()
00080 
00081 
00083 // Property pages
00084 
00085 // TODO: Add more property pages as needed.  Remember to increase the count!
00086 BEGIN_PROPPAGEIDS(CConsoleCtrl, 1)
00087         PROPPAGEID(CConsolePropPage::guid)
00088 END_PROPPAGEIDS(CConsoleCtrl)
00089 
00091 // Initialize class factory and guid
00092 
00093 IMPLEMENT_OLECREATE_EX(CConsoleCtrl, "GME.Console.1",
00094         0xe4eb8324, 0x13f0, 0x46cb, 0x96, 0xa3, 0xf5, 0x39, 0xdf, 0x7f, 0x79, 0xd4)
00095 
00096 
00098 // Type library ID and version
00099 
00100 IMPLEMENT_OLETYPELIB(CConsoleCtrl, _tlid, _wVerMajor, _wVerMinor)
00101 
00102 
00104 // Interface IDs
00105 
00106 const IID BASED_CODE IID_DConsole =
00107                 { 0x71655c2b, 0xd6dd, 0x4345, { 0xb2, 0x73, 0x5b, 0xd1, 0x42, 0x23, 0x70, 0xcb } };
00108 const IID BASED_CODE IID_DConsoleEvents =
00109                 { 0x39f56b4c, 0xe7db, 0x4a54, { 0x86, 0x8c, 0xca, 0xa7, 0xeb, 0xe2, 0x32, 0x33 } };
00110 
00111 
00113 // Control type information
00114 
00115 static const DWORD BASED_CODE _dwConsoleOleMisc =
00116         OLEMISC_ACTIVATEWHENVISIBLE |
00117         OLEMISC_SETCLIENTSITEFIRST |
00118         OLEMISC_INSIDEOUT |
00119         OLEMISC_CANTLINKINSIDE |
00120         OLEMISC_RECOMPOSEONRESIZE;
00121 
00122 IMPLEMENT_OLECTLTYPE(CConsoleCtrl, IDS_CONSOLE, _dwConsoleOleMisc)
00123 
00124 
00125 
00126 // CConsoleCtrl::CConsoleCtrlFactory::UpdateRegistry -
00127 // Adds or removes system registry entries for CConsoleCtrl
00128 
00129 BOOL CConsoleCtrl::CConsoleCtrlFactory::UpdateRegistry(BOOL bRegister)
00130 {
00131         // TODO: Verify that your control follows apartment-model threading rules.
00132         // Refer to MFC TechNote 64 for more information.
00133         // If your control does not conform to the apartment-model rules, then
00134         // you must modify the code below, changing the 6th parameter from
00135         // afxRegApartmentThreading to 0.
00136 
00137         if (bRegister)
00138                 return AfxOleRegisterControlClass(
00139                         AfxGetInstanceHandle(),
00140                         m_clsid,
00141                         m_lpszProgID,
00142                         IDS_CONSOLE,
00143                         IDB_CONSOLE,
00144                         afxRegApartmentThreading,
00145                         _dwConsoleOleMisc,
00146                         _tlid,
00147                         _wVerMajor,
00148                         _wVerMinor);
00149         else
00150                 return AfxOleUnregisterClass(m_clsid, m_lpszProgID);
00151 }
00152 
00153 
00155 // CConsoleCtrl::CConsoleCtrl - Constructor
00156 
00157 CConsoleCtrl::CConsoleCtrl()
00158 : m_recent1(_T(""))
00159 , m_recent2(_T(""))
00160 , m_recent3(_T(""))
00161 , m_recent4(_T(""))
00162 , m_recent5(_T(""))
00163 , m_hIco1(NULL)
00164 , m_hIco2(NULL)
00165 , m_hIco3(NULL)
00166 , m_hIcou(NULL)
00167 , m_hIcod(NULL)
00168 , m_hIcor(NULL)
00169 {
00170         InitializeIIDs(&IID_DConsole, &IID_DConsoleEvents);
00171 
00172         // TODO: Initialize your control's instance data here.
00173 }
00174 
00175 
00177 // CConsoleCtrl::~CConsoleCtrl - Destructor
00178 
00179 CConsoleCtrl::~CConsoleCtrl()
00180 {
00181         // TODO: Cleanup your control's instance data here.
00182         if (m_hIco1)
00183                 ::DestroyIcon(m_hIco1);
00184         if (m_hIco2)
00185                 ::DestroyIcon(m_hIco2);
00186         if (m_hIco3)
00187                 ::DestroyIcon(m_hIco3);
00188         if (m_hIcou)
00189                 ::DestroyIcon(m_hIcou);
00190         if (m_hIcod)
00191                 ::DestroyIcon(m_hIcod);
00192         if (m_hIcor)
00193                 ::DestroyIcon(m_hIcor);
00194 }
00195 
00196 // centeres a rectangle inside another one, so that a 
00197 // square with p_bt_size side will sit in the center
00198 CRect centered( const CRect& p_rcIn, int p_vertic_size, int p_horiz_size, int p_bt_size)
00199 {
00200         CRect rc( p_rcIn);
00201         rc.top += (p_vertic_size - p_bt_size)/2;
00202         rc.bottom -= (p_vertic_size - p_bt_size)/2;
00203         rc.left += (p_horiz_size - p_bt_size)/2;
00204         rc.right -= (p_horiz_size - p_bt_size)/2;
00205         return rc;
00206 }
00207 
00209 // CConsoleCtrl::OnDraw - Drawing function
00210 
00211 void CConsoleCtrl::OnDraw(
00212                         CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
00213 {
00214         AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
00215 
00216         const int vertic_size = 26 * GetDeviceCaps(pdc->GetSafeHdc(), LOGPIXELSY) / 96 /* USER_DEFAULT_SCREEN_DPI */;
00217         const int horiz_size    = 26 * GetDeviceCaps(pdc->GetSafeHdc(), LOGPIXELSY) / 96 /* USER_DEFAULT_SCREEN_DPI */;
00218         const int bt_size       = 20 * GetDeviceCaps(pdc->GetSafeHdc(), LOGPIXELSY) / 96 /* USER_DEFAULT_SCREEN_DPI */;
00219         const int prnx_size     = 19 * GetDeviceCaps(pdc->GetSafeHdc(), LOGPIXELSY) / 96 /* USER_DEFAULT_SCREEN_DPI */; // width of the prev/next buttons
00220 
00221 
00222         if (m_browser.GetSafeHwnd()) {
00223                 bool  anything_loaded = !m_edit.GetLoadedScript().IsEmpty();
00224                 CRect rcBrwsr, rcExtra, rcExtra2;  // browser rect, extra rect
00225                 rcExtra2 = rcBrwsr = rcExtra = rcBounds;
00226 
00227                 rcExtra2.left -= 1;
00228                 rcExtra2.bottom += 1;
00229                 // light gray background for the whole region
00230                 DWORD dw = ::GetSysColor(COLOR_3DFACE);
00231                 BYTE r = GetRValue(dw);
00232                 BYTE g = GetGValue(dw);
00233                 BYTE b = GetBValue(dw);
00234                 COLORREF col = RGB(r,g,b);
00235                 CBrush brush;
00236                 brush.CreateSolidBrush(col);
00237                 pdc->FillRect(&rcExtra2, &brush);
00238 
00239                 rcBrwsr.bottom -= vertic_size;     // take from the browser's space 30 lines
00240                 rcExtra.top = rcBrwsr.bottom;      // extra is the remaining space
00241                 rcBrwsr.bottom -= 1;               // use less space for the browser to have a divide
00242 
00243 
00244                 pdc->SelectStockObject( BLACK_PEN);
00245                 pdc->SelectStockObject( GRAY_BRUSH);
00246                 rcExtra2.top = rcBrwsr.bottom;
00247                 rcExtra2.bottom = rcExtra2.top+1;
00248                 pdc->Rectangle( rcExtra2);         // a divider line between the browser and scripting 
00249 
00250                 // place browser
00251                 m_browser.MoveWindow( rcBrwsr, TRUE);
00252 
00253                 // place the generic command button
00254                 CRect rcLoad( rcExtra);                     // load btn rect
00255                 rcLoad.right = rcLoad.left + horiz_size;
00256                 
00257                 m_cmdButton.MoveWindow( centered( rcLoad, vertic_size, horiz_size, bt_size), TRUE);
00258 
00259                 // place and show/hide 'Execute' button based on bool (anything_loaded)
00260                 if (anything_loaded) {
00261                         rcLoad.OffsetRect( horiz_size, 0);
00262                         
00263                         m_exeButton.MoveWindow( centered( rcLoad, vertic_size, horiz_size, bt_size), TRUE);
00264                         m_exeButton.ShowWindow(SW_SHOW);
00265                 }
00266                 else {
00267                         m_exeButton.ShowWindow(SW_HIDE);
00268                 }
00269 
00270                 // place 'Clear'
00271                 CRect rcClean = rcExtra;                    // clear btn rect
00272                 rcClean.left = rcClean.right - horiz_size;
00273                 
00274                 CRect rcClrBtn(rcClean);
00275                 m_clrButton.MoveWindow( centered( rcClrBtn, vertic_size, horiz_size, bt_size), TRUE);
00276 
00277                 // place 'Return'
00278                 rcClean.right = rcClean.left;
00279                 rcClean.left -= horiz_size;
00280 
00281                 m_retButton.MoveWindow( centered( rcClean, vertic_size, horiz_size, bt_size), TRUE);
00282 
00283                 // place history prev/next button pair to the left of Clean
00284                 rcClean.right = rcClean.left; rcClean.left -= prnx_size;
00285                 rcClean.bottom = rcClean.top + static_cast<int>(vertic_size/2);
00286                 CRect rcUDBtn( rcClean);
00287                 rcUDBtn.DeflateRect( 0, 2, 0, 0);
00288                 m_upButton.MoveWindow( rcUDBtn, TRUE);
00289 
00290                 rcClean.top = rcClean.bottom;
00291                 rcClean.bottom = rcExtra.bottom;//rcClean.OffsetRect( 0, vertic_size - static_cast<int>(vertic_size/2));
00292                 rcUDBtn = rcClean;
00293                 rcUDBtn.DeflateRect( 0, 1, 0, 2);
00294                 m_dnButton.MoveWindow( rcUDBtn, TRUE);
00295                 
00296                 CRect rcRemain = rcExtra; // remaining rect
00297                 rcRemain.left = rcLoad.right;         // left side
00298                 rcRemain.right= rcClean.left;         // right side
00299 
00300                 rcRemain.top += 2;
00301                 rcRemain.left += 2;
00302                 rcRemain.bottom -= 2;
00303                 rcRemain.right -= 2;
00304                 
00305                 // move input control too 
00306                 m_edit.MoveWindow(rcRemain, TRUE);
00307         }
00308         else {
00309                 CBrush brush (RGB(255,255,255));
00310                 pdc->FillRect (rcBounds, &brush);
00311 
00312                 CRect edge(rcBounds);
00313                 pdc->DrawEdge(&edge, EDGE_BUMP, BF_RECT);
00314                 
00315                 CString label(_T("GME Console OCX"));
00316 
00317                 BITMAP bm;
00318                 CBitmap bitmap;
00319                 bitmap.LoadBitmap(IDB_CONSOLE);
00320                 bitmap.GetBitmap(&bm);
00321                 CSize size(bm.bmWidth, bm.bmHeight);
00322                 pdc->DPtoLP(&size);
00323                 CPoint org(0,0);
00324                 pdc->DPtoLP(&org);
00325                 CPoint pos(rcBounds.Width()/2, rcBounds.Height()/2 - (pdc->GetTextExtent(label).cy) );
00326                 CDC dcMem;
00327                 dcMem.CreateCompatibleDC(pdc);
00328                 CBitmap *oldbitmap = dcMem.SelectObject(&bitmap);
00329                 dcMem.SetMapMode (pdc->GetMapMode());
00330                 pdc->BitBlt(pos.x, pos.y, size.cx, size.cy, &dcMem, org.x, org.y, SRCCOPY);
00331                 dcMem.SelectObject(oldbitmap);
00332                 
00333                 pdc->SetTextAlign(TA_CENTER);
00334                 pdc->TextOut(rcBounds.Width()/2, rcBounds.Height()/2, label);
00335         }
00336 }
00337 
00338 
00340 // CConsoleCtrl::DoPropExchange - Persistence support
00341 
00342 void CConsoleCtrl::DoPropExchange(CPropExchange* pPX)
00343 {
00344         ExchangeVersion(pPX, MAKELONG(_wVerMinor, _wVerMajor));
00345         COleControl::DoPropExchange(pPX);
00346 
00347         // TODO: Call PX_ functions for each persistent custom property.
00348 
00349 }
00350 
00351 
00353 // CConsoleCtrl::OnResetState - Reset control to default state
00354 
00355 void CConsoleCtrl::OnResetState()
00356 {
00357         COleControl::OnResetState();  // Resets defaults found in DoPropExchange
00358 
00359         // TODO: Reset any other control state here.
00360 }
00361 
00362 
00364 // CConsoleCtrl::AboutBox - Display an "About" box to the user
00365 
00366 void CConsoleCtrl::AboutBox()
00367 {
00368         AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
00369         CDialog dlgAbout(IDD_ABOUTBOX_CONSOLE);
00370         dlgAbout.DoModal();
00371 }
00372 
00374 void CConsoleCtrl::SetGMEApp(IDispatch *disp)
00375 {
00376         AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
00377         m_edit.SetGMEApp(disp);
00378         m_gmeptr = disp;
00379         AddGMEToScript();
00380 }
00381 
00382 void CConsoleCtrl::SetGMEProj(IDispatch *disp)
00383 {
00384         AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
00385         m_edit.SetGMEProj(disp);
00386 }
00387 
00388 void CConsoleCtrl::NavigateTo(LPCTSTR url)
00389 {
00390         AFX_MANAGE_STATE(AfxGetStaticModuleState());
00391         m_browser.Navigate2(url);
00392 }
00394 // CConsoleCtrl message handlers
00395 
00396 int CConsoleCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
00397 {
00398         if (COleControl::OnCreate(lpCreateStruct) == -1)
00399                 return -1;
00400         
00401         CRect rect(0,0,0,0);
00402         // create an input control too
00403         if (!m_browser.Create(NULL, _T("GME Console"), (WS_VISIBLE | WS_CHILD), 
00404                 rect, this, IDD_BROWSER))
00405                 // FIXME: warn user that GME requires IE (e.g. Windows Server Core 2008R2)
00406                 return -1;
00407         m_browser.LoadFromResource(_T("BLANK.HTML"));
00408         
00409         // KMS: need to pump messages here, since m_browser loads in a different thread and 
00410         // posts messages to initialize. If RPC wins the race, it can call SetContents et al and
00411         // get_body will return NULL
00412         // (out-of-proc CoCreateInstance("GMEOleApp") will block until after this method returns)
00413         CComPtr<IHTMLDocument2> pHtmlDoc;
00414         CComPtr<IDispatch> pDispatch = m_browser.GetHtmlDocument();
00415         COMTHROW(pDispatch.QueryInterface(&pHtmlDoc));
00416         ASSERT(pHtmlDoc != NULL);
00417         MSG msg;
00418         while (GetMessage(&msg, NULL, 0, 0)) 
00419         {
00420                 TranslateMessage(&msg);
00421                 DispatchMessage(&msg);
00422                 CComPtr<IHTMLElement> pElement;
00423                 COMTHROW(pHtmlDoc->get_body( &pElement ));
00424                 if (pElement != NULL)
00425                         break;
00426         }
00427 
00428         m_edit.Create((ES_AUTOHSCROLL | WS_VISIBLE | WS_CHILD | WS_BORDER), rect, this, IDD_EDIT);
00429         m_edit.LimitText(300);
00430         bool ret = m_edit.Init(this);
00431         if (!ret) {
00432                 ASSERT(false);
00433                 return -1;
00434         }
00435         m_edit.ModifyStyleEx(WS_EX_CLIENTEDGE, WS_EX_STATICEDGE);
00436 
00437 
00438         m_hIco1 = (HICON)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_LOADSCR),      IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
00439         m_hIco2 = (HICON)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_EXECSCR),      IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
00440         m_hIco3 = (HICON)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_CLEANCON),     IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
00441         m_hIcou = (HICON)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_BTNUP),        IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
00442         m_hIcod = (HICON)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_BTNDN),        IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
00443         m_hIcor = (HICON)::LoadImage(AfxGetResourceHandle(), MAKEINTRESOURCE(IDI_BTNRET),       IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
00444 
00445         rect.bottom = rect.right = 100;
00446         rect.left = rect.right - BUTTON_ICON_SIZE;
00447         rect.bottom = rect.top - BUTTON_ICON_SIZE;
00448 
00449         m_cmdButton.Create( _T("MenuButton"), WS_CHILD|WS_VISIBLE|BS_ICON, rect, this, IDC_MENU_COMMAND);
00450         m_cmdButton.SetIcon(m_hIco1);
00451 
00452         rect.right += BUTTON_ICON_SIZE;
00453         rect.left  += BUTTON_ICON_SIZE;
00454         m_exeButton.Create( _T("ExecButton"), WS_CHILD/*|WS_VISIBLE*/|BS_ICON, rect, this, IDC_RUNSCRIPT_COMMAND);
00455         m_exeButton.SetIcon(m_hIco2);
00456 
00457         rect.left  += BUTTON_ICON_SIZE;
00458         rect.right += BUTTON_ICON_SIZE;
00459         m_clrButton.Create( _T("ClearConsButton"), WS_CHILD|WS_VISIBLE|BS_ICON, rect, this, IDC_CLEARCONSOLE_COMMAND);
00460         m_clrButton.SetIcon(m_hIco3);
00461 
00462         CRect rec2 = rect;
00463         //rec2.right = rec2.left + 40; rec2.bottom = rec2.top + BUTTON_ICON_SIZE;
00464         rec2.right = rec2.left + BUTTON_ICON_SIZE + 3;  //bmuSize.cx + 3; 
00465         rec2.bottom = rec2.top + BUTTON_ICON_SIZE;              //bmuSize.cy + 3;
00466         m_upButton.Create(_T("Prev"), WS_CHILD|WS_VISIBLE|BS_ICON, rec2, this, IDC_PREV_COMMAND);
00467         m_upButton.SetIcon(m_hIcou);
00468 
00469         m_dnButton.Create(_T("Next"), WS_CHILD|WS_VISIBLE|BS_ICON, rec2, this, IDC_NEXT_COMMAND);
00470         m_dnButton.SetIcon(m_hIcod);
00471 
00472         m_retButton.Create(_T("Return"), WS_CHILD|WS_VISIBLE|BS_ICON, rec2, this, IDC_RETURN_COMMAND);
00473         m_retButton.SetIcon(m_hIcor);
00474 
00475         EnableToolTips();
00476 
00477         return 0;
00478 }
00479 
00480 
00481 static const TCHAR* icons[] = {
00482         _T("NORMAL.GIF"),
00483         _T("INFO.GIF"),
00484         _T("WARNING.GIF"),
00485         _T("ERROR.GIF")
00486 };
00487 
00488 void CConsoleCtrl::Message(LPCTSTR str, short type) 
00489 {
00490         AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
00491 
00492         if (type < MSG_NORMAL || type > MSG_ERROR) {
00493                 type = MSG_ERROR;
00494         }
00495     CComPtr<IDispatch> pDispatch = m_browser.GetHtmlDocument();
00496     if( pDispatch != NULL )
00497     {
00498                 CString line;
00499                 
00500                 line.Format(_T("<IMG SRC=\"%s\" ALIGN=MIDDLE > %s<BR>"), icons[type], str);
00501 
00502                 VARIANT_BOOL time_stamping = VARIANT_FALSE; // default
00503                 try {
00504                         CComPtr<IMgaRegistrar> registrar;
00505                         COMTHROW( registrar.CoCreateInstance(L"Mga.MgaRegistrar") );
00506 
00507                         COMTHROW( registrar->GetTimeStamping(REGACCESS_USER, &time_stamping));
00508                         if(time_stamping != VARIANT_FALSE)
00509                         {
00510                                 CTime time = CTime::GetCurrentTime();
00511                                 line = time.Format(_T("[%H:%M:%S] ")) + line;
00512                         }
00513                 } catch(hresult_exception &)
00514                 {
00515                 }
00516 
00517                 try {
00518                         CComPtr<IHTMLDocument2> pHtmlDoc;
00519                         COMTHROW(pDispatch.QueryInterface(&pHtmlDoc));
00520                         ASSERT(pHtmlDoc != NULL);
00521                         CComPtr<IHTMLElement> pElement;
00522                         COMTHROW(pHtmlDoc->get_body( &pElement ));
00523                         ASSERT(pElement != NULL);
00524                         CComBSTR where(L"BeforeEnd");
00525                         CComBSTR text(line);
00526                         COMTHROW(pElement->insertAdjacentHTML(where, text));
00527 
00528                         // Scroll
00529                         CComPtr<IHTMLWindow2> parentWindow;
00530                         COMTHROW(pHtmlDoc->get_parentWindow( &parentWindow ));
00531                         ASSERT(parentWindow != NULL);
00532                         HRESULT hhh = (parentWindow->scrollTo( 0,  LONG_MAX/16)); // Starting from IE8 we need this /16 hack.  
00533                                                                                                                                           // If you know the proper way of scrolling to the bottom, fix this.
00534                         //COMTHROW(parentWindow->scrollTo( 0,  LONG_MAX));
00535                 }
00536                 catch (hresult_exception &)
00537                 {
00538                 }
00539     }
00540 
00541 }
00542 
00543 void CConsoleCtrl::Clear() 
00544 {
00545         AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
00546         m_browser.LoadFromResource(_T("BLANK.HTML"));
00547 }
00548 
00549 BSTR CConsoleCtrl::GetContents() 
00550 {
00551         AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
00552         CComBSTR contents;
00553         
00554     CComPtr<IDispatch> pDispatch = m_browser.GetHtmlDocument();
00555     if( pDispatch != NULL )
00556     {
00557                 try {
00558                         CComPtr<IHTMLDocument2> pHtmlDoc;
00559                         COMTHROW(pDispatch.QueryInterface(&pHtmlDoc));
00560                         ASSERT(pHtmlDoc != NULL);
00561                         CComPtr<IHTMLElement> pElement;
00562                         COMTHROW(pHtmlDoc->get_body( &pElement ));
00563                         ASSERT(pElement != NULL);
00564                         // FIXME: under wine, access violation in ieframe.dll
00565                         COMTHROW(pElement->get_innerHTML(&contents));
00566                 }
00567                 catch (hresult_exception &)
00568                 {
00569                 }
00570     }
00571 
00572         return contents.Detach();
00573 }
00574 
00575 void CConsoleCtrl::SetContents(LPCTSTR lpszNewValue) 
00576 {
00577         AFX_MANAGE_STATE(AfxGetStaticModuleState( ));
00578         CComBSTR contents(lpszNewValue);
00579         
00580     CComPtr<IDispatch> pDispatch = m_browser.GetHtmlDocument();
00581     if( pDispatch != NULL )
00582     {
00583                 try {
00584                         CComPtr<IHTMLDocument2> pHtmlDoc;
00585                         COMTHROW(pDispatch.QueryInterface(&pHtmlDoc));
00586                         ASSERT(pHtmlDoc != NULL);
00587                         CComPtr<IHTMLElement> pElement;
00588                         COMTHROW(pHtmlDoc->get_body( &pElement ));
00589                         ASSERT(pElement != NULL);
00590                         COMTHROW(pElement->put_innerHTML(contents));
00591                 }
00592                 catch (hresult_exception &)
00593                 {
00594                 }
00595     }
00596 
00597         SetModifiedFlag();
00598 }
00599 
00600 void CConsoleCtrl::OnShowMenu()
00601 {
00602         if( 0 > ::GetKeyState( VK_CONTROL))
00603         {
00604                 runScript();
00605                 return;
00606         }
00607         else if( 0 > ::GetKeyState( VK_SHIFT))
00608         {
00609                 LoadScriptDlg();
00610                 return;
00611         }
00612 
00613         CMenu r; // recentMenu;
00614         if( r.CreatePopupMenu())
00615         {
00616                 if( !m_recent1.IsEmpty()) r.AppendMenu( MF_STRING, IDC_RECENT_SCRIPT1,  m_recent1);
00617                 if( !m_recent2.IsEmpty()) r.AppendMenu( MF_STRING, IDC_RECENT_SCRIPT2,  m_recent2);
00618                 if( !m_recent3.IsEmpty()) r.AppendMenu( MF_STRING, IDC_RECENT_SCRIPT3,  m_recent3);
00619                 if( !m_recent4.IsEmpty()) r.AppendMenu( MF_STRING, IDC_RECENT_SCRIPT4,  m_recent4);
00620                 if( !m_recent5.IsEmpty()) r.AppendMenu( MF_STRING, IDC_RECENT_SCRIPT5,  m_recent5);
00621         }
00622 
00623         CMenu p;
00624         if( p.CreatePopupMenu())
00625         {
00626                 p.AppendMenu( MF_STRING, IDC_LOADSCRIPT_COMMAND,   _T("Load Script"));
00627                 if( !m_edit.GetLoadedScriptFileName().IsEmpty())
00628                         p.AppendMenu( MF_STRING,IDC_RELOAD_COMMAND, _T("Reload Current")); // or IDC_RELOADRUN_COMMAND
00629                 if( !m_recent1.IsEmpty()) // m_recent1 can tell us if there is anything in the recent list
00630                         p.AppendMenu( MF_POPUP, (UINT_PTR) r.GetSafeHmenu(), _T("Recent Scripts"));
00631                 p.AppendMenu( MF_STRING, IDC_SELECTENGINE_COMMAND,   _T("Settings"));
00632                 
00633                 CRect rc;
00634                 m_cmdButton.GetWindowRect( &rc);
00635                 p.TrackPopupMenu( TPM_LEFTALIGN | TPM_LEFTBUTTON, rc.left + rc.Width()/2, rc.top + rc.Height()/2, this);
00636                 Invalidate();
00637         }
00638 }
00639 
00640 void CConsoleCtrl::RunScript()
00641 {
00642         if( !m_edit.GetLoadedScript().IsEmpty())
00643         {
00644                 Message( CString( _T("Executing script: ")) + m_edit.GetLoadedScriptFileName(), MSG_INFO);
00645                 m_edit.ExecuteScript( m_edit.GetLoadedScript());
00646         }
00647         else
00648                 Message( _T("Script not found!"), MSG_INFO);
00649 }
00650 
00651 void CConsoleCtrl::LoadScript(BSTR p_fileName)
00652 {
00653         m_edit.SetLoadedScript(_T("")); // erase old loaded script contents
00654 
00655         CStdioFile _file;
00656 
00657         // open file
00658         if( _file.Open( p_fileName, CFile::modeRead | CFile::typeBinary) == 0) {
00659                 Message( CString(_T("Unable to open file '")) + static_cast<const TCHAR*>(p_fileName) + _T("'"), MSG_ERROR);
00660                 return;
00661         }
00662 
00663         unsigned char utf16_bom[] = { 0xFF, 0xFE };
00664         unsigned char bytes[2];
00665         _file.Read(bytes, 2);
00666         if (memcmp(utf16_bom, bytes, 2) == 0)
00667         {
00668                 CString script_buf;
00669                 unsigned int sizeof_file = _file.GetLength();
00670                 // skipping BOM
00671                 sizeof_file -= 2;
00672                 sizeof_file = _file.Read(script_buf.GetBuffer(sizeof_file / sizeof(wchar_t)), sizeof_file);
00673                 script_buf.ReleaseBuffer();
00674                 _file.Close();
00675                 m_edit.SetLoadedScript(script_buf);
00676         }
00677         else
00678         {
00679                 _file.SeekToBegin();
00680                 CStringA script_buf;
00681                 unsigned int sizeof_file = _file.GetLength();
00682                 sizeof_file = _file.Read(script_buf.GetBuffer(sizeof_file), sizeof_file);
00683                 script_buf.ReleaseBuffer();
00684                 _file.Close();
00685                 m_edit.SetLoadedScript(CString(script_buf));
00686         }
00687 
00688         m_edit.SetScriptFileName( p_fileName);
00689 
00690         Message( CString( _T("Loaded script: ")) + p_fileName, MSG_INFO);
00691         Invalidate();
00692 }
00693 
00694 void CConsoleCtrl::LoadScriptDlg()
00695 {
00696         CFileDialog dlg(TRUE, _T("py"), 0,
00697                 OFN_EXPLORER | OFN_HIDEREADONLY | OFN_OVERWRITEPROMPT,
00698                 _T("Script Files (*.js;*.py;*.vbs)|*.js;*.vbs;*.py|")
00699                 _T("Python Script Files (*.py)|*.py|")
00700                 _T("JScript Files (*.js)|*.js|")
00701                 _T("VBScript Files (*.vbs)|*.vbs|")
00702                 _T("Text Files (*.txt)|*.txt|")
00703                 _T("HTML Files (*.html;*.htm)|*.html;*.htm|")
00704                 _T("All Files (*.*)|*.*||"));
00705 
00706         if( dlg.DoModal() == IDOK) 
00707         {
00708                 CString fpath = dlg.GetPathName();
00709                 CString ext = dlg.GetFileExt().MakeLower();
00710                 if (ext == _T("html") || ext == _T("htm")) {
00711                         m_browser.Navigate2(fpath);
00712                         return;
00713                 }
00714 
00715                 LoadScript(_bstr_t(fpath));
00716 
00717                 if( m_recent1.IsEmpty())
00718                         m_recent1 = fpath;
00719                 else if( m_recent2.IsEmpty())
00720                 {
00721                         m_recent2 = m_recent1;
00722                         m_recent1 = fpath;
00723                 }
00724                 else if( m_recent3.IsEmpty())
00725                 {
00726                         m_recent3 = m_recent2;
00727                         m_recent2 = m_recent1;
00728                         m_recent1 = fpath;
00729                 }
00730                 else if( m_recent4.IsEmpty())
00731                 {
00732                         m_recent4 = m_recent3;
00733                         m_recent3 = m_recent2;
00734                         m_recent2 = m_recent1;
00735                         m_recent1 = fpath;
00736                 }
00737                 else if( m_recent5.IsEmpty())
00738                 {
00739                         m_recent5 = m_recent4;
00740                         m_recent4 = m_recent3;
00741                         m_recent3 = m_recent2;
00742                         m_recent2 = m_recent1;
00743                         m_recent1 = fpath;
00744                 }
00745         }
00746 }
00747 
00748 void CConsoleCtrl::runScript()
00749 {
00750         RunScript();
00751 }
00752 
00753 void CConsoleCtrl::relScript() // reload
00754 {
00755         LoadScript(_bstr_t(m_edit.GetLoadedScriptFileName()));
00756 }
00757 
00758 void CConsoleCtrl::rlrScript() // reload & run
00759 {
00760         LoadScript(_bstr_t(m_edit.GetLoadedScriptFileName()));
00761         RunScript();
00762 }
00763 
00764 void CConsoleCtrl::selectEngine()
00765 {
00766         try {
00767                 CComPtr<IMgaLauncher> launcher;
00768                 COMTHROW( launcher.CoCreateInstance(L"Mga.MgaLauncher") );
00769                 COMTHROW( launcher->GmeDlg());
00770         }
00771         catch(...) {
00772                 Message( _T("Error while trying to show GME settings dialog"), MSG_ERROR);
00773         }
00774 }
00775 
00776 void CConsoleCtrl::loadRecent( UINT which)
00777 {
00778         switch( which) {
00779         case IDC_RECENT_SCRIPT1: LoadScript(_bstr_t(m_recent1));break;
00780         case IDC_RECENT_SCRIPT2: LoadScript(_bstr_t(m_recent2));break;
00781         case IDC_RECENT_SCRIPT3: LoadScript(_bstr_t(m_recent3));break;
00782         case IDC_RECENT_SCRIPT4: LoadScript(_bstr_t(m_recent4));break;
00783         case IDC_RECENT_SCRIPT5: LoadScript(_bstr_t(m_recent5));break;
00784         }
00785 }
00786 
00787 void CConsoleCtrl::prevCommand()
00788 {
00789         m_edit.showPrev();
00790 }
00791 
00792 void CConsoleCtrl::nextCommand()
00793 {
00794         m_edit.showNext();
00795 }
00796 
00797 void CConsoleCtrl::retCommand()
00798 {
00799         m_edit.returnHit();
00800 }
00801 
00802 BOOL CConsoleCtrl::OnToolTipNotify(UINT id, NMHDR *pNMHDR, LRESULT *pResult)
00803 {
00804         // need to handle both ANSI and UNICODE versions of the message
00805         TOOLTIPTEXTA* pTTTA = (TOOLTIPTEXTA*)pNMHDR;
00806         TOOLTIPTEXTW* pTTTW = (TOOLTIPTEXTW*)pNMHDR;
00807         UINT_PTR nID = pNMHDR->idFrom;
00808         
00809         CString tip;
00810 
00811         if( pNMHDR->code == TTN_NEEDTEXTA && (pTTTA->uFlags & TTF_IDISHWND) ||
00812             pNMHDR->code == TTN_NEEDTEXTW && (pTTTW->uFlags & TTF_IDISHWND))
00813         {
00814                 // idFrom is actually the HWND of the tool
00815                 nID = ::GetDlgCtrlID((HWND)nID);
00816         }
00817 
00818         if( nID != 0) // will be zero on a separator
00819         {
00820                 //tip.Format("Control ID = %d", nID);
00821                 switch( nID)
00822                 {
00823                               case IDC_RETURN_COMMAND:       tip = _T("Executes the command typed into the edit field");
00824                         break;case IDC_RUNSCRIPT_COMMAND:    tip = _T("Executes ") + m_edit.GetLoadedScriptFileName();
00825                         break;case IDC_MENU_COMMAND:         tip = _T("Load scripts and access recent scripts");
00826                         break;case IDC_CLEARCONSOLE_COMMAND: tip = _T("Clear the console");
00827                         break;case IDC_PREV_COMMAND:         tip = _T("Previous command in history");
00828                         break;case IDC_NEXT_COMMAND:         tip = _T("Next command in history");
00829                         break;case IDD_EDIT:                 tip = _T("Enter a command here");
00830                 }
00831         }
00832 
00833         CStringA aTip(tip);
00834         CStringW wTip(tip);
00835         if( pNMHDR->code == TTN_NEEDTEXTA)
00836                 StringCchCopyA(pTTTA->szText, sizeof(pTTTA->szText) / sizeof(char) - 1, aTip);
00837         else
00838                 StringCchCopyW(pTTTW->szText, sizeof(pTTTW->szText) / sizeof(wchar_t) - 1, wTip);
00839 
00840         *pResult = 0;
00841         return TRUE;    // message was handled
00842 }
00843 
00844 BOOL CConsoleCtrl::PreTranslateMessage(MSG* pMsg) {
00845         HWND h = ::GetFocus();
00846         while (h) {
00847                 if (h == m_browser.GetSafeHwnd()) {
00848                         return m_browser.PreTranslateMessage(pMsg);
00849                 }
00850                 h = ::GetParent(h);
00851         }
00852         return FALSE;
00853 }
00854 
00855 HRESULT CConsoleCtrl::AddGMEToScript()
00856 {
00857         COMTRY {
00858         HRESULT hr;
00859 
00860         CComPtr<IHTMLDocument2> pHtmlDoc;
00861         CComPtr<IDispatch> pDispatch = m_browser.GetHtmlDocument();
00862         // This QI fails on Win7 if the link is to file:///folder
00863         COMTHROW(pDispatch.QueryInterface(&pHtmlDoc));
00864 
00865         CComPtr<IDispatch> script;
00866         pHtmlDoc->get_Script(&script);
00867         CComPtr<IDispatchEx> scriptex;
00868         if (script)
00869         {
00870                 script->QueryInterface(IID_IDispatchEx, (void**)&scriptex);
00871         }
00872         
00873         if(script == NULL) // || m_gmeptr == NULL)
00874                 return E_INVALIDARG;
00875 
00876         DISPID dispIdThis = 0;
00877         hr = scriptex->GetDispID(_bstr_t(L"gme"), fdexNameEnsure | fdexNameCaseSensitive, &dispIdThis);
00878         if (FAILED(hr))
00879                 return hr;
00880         if (dispIdThis == 0)
00881                 return E_FAIL;
00882 
00883         DISPID dispIdPut = DISPID_PROPERTYPUT;
00884         DISPPARAMS params = {0};
00885         EXCEPINFO ei;
00886                         
00887         CComVariant arg = m_gmeptr;
00888         params.cArgs = 1;
00889         params.rgvarg = &arg;
00890         params.cNamedArgs = 1;
00891         params.rgdispidNamedArgs = &dispIdPut;
00892                         
00893         return scriptex->InvokeEx(dispIdThis, LOCALE_SYSTEM_DEFAULT, DISPATCH_PROPERTYPUT, &params, NULL, &ei, NULL);
00894         } COMCATCH(;)
00895 }
00896