/************************************************************************* * * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * Copyright 2010 Eric Bachard * * OOo4Kids - a multi-platform office productivity suite * * $RCSfile: backingwindow-OOo4Kids.cxx,v $ * $Revision: 1 $ * * This file is part of OOo4Kids. * * OOo4Kids is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License version 3 * only, as published by the Free Software Foundation. * * OOo4Kids is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License version 3 for more details * (a copy is included in the LICENSE file that accompanied this code). * * You should have received a copy of the GNU Lesser General Public License * version 3 along with OOo4Kids. If not, see * * for a copy of the LGPLv3 License. * ************************************************************************/ // autogen include statement, do not remove #include "precompiled_framework.hxx" #include "backingwindow.hxx" #include "framework.hrc" #include "classes/fwkresid.hxx" #include #include "vcl/metric.hxx" #include "vcl/mnemonic.hxx" #include "vcl/menu.hxx" #include "vcl/svapp.hxx" #include "tools/urlobj.hxx" #include "svtools/dynamicmenuoptions.hxx" #include "svtools/imagemgr.hxx" #include "svtools/svtools.hrc" #include "comphelper/processfactory.hxx" #include "comphelper/sequenceashashmap.hxx" #include "rtl/strbuf.hxx" #include "rtl/ustrbuf.hxx" #include "com/sun/star/lang/XMultiServiceFactory.hpp" #include "com/sun/star/container/XNameAccess.hpp" #include "com/sun/star/system/XSystemShellExecute.hpp" #include "com/sun/star/system/SystemShellExecuteFlags.hpp" #include "com/sun/star/task/XJobExecutor.hpp" using namespace ::com::sun::star::beans; using namespace ::com::sun::star::frame; using namespace ::com::sun::star::uno; using namespace ::com::sun::star; using namespace framework; #define WRITER_URL "private:factory/swriter" #define CALC_URL "private:factory/scalc" #define IMPRESS_WIZARD_URL "private:factory/simpress?slot=6686" #define DRAW_URL "private:factory/sdraw" #define TEMPLATE_URL "slot:5500" #define OPEN_URL ".uno:Open" #ifdef DEBUG #include const sal_Char *dbg_dump(const rtl::OString &rStr) { static rtl::OStringBuffer aStr; aStr = rtl::OStringBuffer(rStr); aStr.append(static_cast(0)); return aStr.getStr(); } const sal_Char *dbg_dump(const rtl::OUString &rStr) { return dbg_dump(rtl::OUStringToOString(rStr, RTL_TEXTENCODING_UTF8)); } const sal_Char *dbg_dump(rtl_String *pStr) { return dbg_dump(rtl::OString(pStr)); } const sal_Char *dbg_dump(rtl_uString *pStr) { return dbg_dump(rtl::OUString(pStr)); } #endif DecoToolBox::DecoToolBox( Window* pParent, WinBits nStyle ) : ToolBox( pParent, nStyle ) { SetBackground(); SetPaintTransparent( TRUE ); } void DecoToolBox::DataChanged( const DataChangedEvent& rDCEvt ) { Window::DataChanged( rDCEvt ); if ( rDCEvt.GetFlags() & SETTINGS_STYLE ) { calcMinSize(); SetBackground(); SetPaintTransparent( TRUE ); } } void DecoToolBox::calcMinSize() { ToolBox aTbx( GetParent() ); USHORT nItems = GetItemCount(); for( USHORT i = 0; i < nItems; i++ ) { USHORT nId = GetItemId( i ); aTbx.InsertItem( nId, GetItemImage( nId ) ); } aTbx.SetOutStyle( TOOLBOX_STYLE_FLAT ); maMinSize = aTbx.CalcWindowSizePixel(); } Size DecoToolBox::getMinSize() { return maMinSize; } BackingWindow::BackingWindow( Window* i_pParent ) : Window( i_pParent, FwkResId( DLG_BACKING ) ), maWelcome( this, WB_LEFT ), maProduct( this, WB_LEFT ), maCreateText( this, WB_LEFT ), maToolbox( this, WB_DIALOGCONTROL ), maWelcomeString( FwkResId( STR_BACKING_WELCOME ) ), maProductString( FwkResId( STR_BACKING_WELCOMEPRODUCT ) ), maCreateString( FwkResId( STR_BACKING_CREATE ) ), maOpenString( FwkResId( STR_BACKING_FILE ) ), mbInitControls( false ), mpAccExec( NULL ) { mnColumnWidth[0] = mnColumnWidth[1] = 0; // Writer BitmapEx aWriterHelpImage( FwkResId( BMP_BACKING_WRITER ) ); String aWriterHelpText( FwkResId( STR_BACKING_WRITER ) ); // Draw BitmapEx aDrawHelpImage( FwkResId( BMP_BACKING_DRAW ) ); String aDrawHelpText( FwkResId( STR_BACKING_DRAW ) ); // Calc BitmapEx aCalcHelpImage( FwkResId( BMP_BACKING_CALC ) ); String aCalcHelpText( FwkResId( STR_BACKING_CALC ) ); // Impress BitmapEx aImpressHelpImage( FwkResId( BMP_BACKING_IMPRESS ) ); String aImpressHelpText( FwkResId( STR_BACKING_IMPRESS ) ); // Open a file BitmapEx aInfoImage( FwkResId( BMP_BACKING_OPENFILE ) ); String aInfoHelpText( FwkResId( STR_BACKING_FILE ) ); // clean up resource stack FreeResource(); maWelcome.SetPaintTransparent( TRUE ); maProduct.SetPaintTransparent( TRUE ); EnableChildTransparentMode(); SetStyle( GetStyle() | WB_DIALOGCONTROL ); // add some breathing space for the images maButtonImageSize.Width() += IMAGES_BREATHING_SPACE; maButtonImageSize.Height() += IMAGES_BREATHING_SPACE; // force tab cycling in toolbox maToolbox.SetStyle( maToolbox.GetStyle() | WB_FORCETABCYCLE ); // Writer item maToolbox.InsertItem( nItemId_Writer, Image( aWriterHelpImage ) ); maToolbox.SetItemText( nItemId_Writer, aWriterHelpText ); maToolbox.ShowItem( nItemId_Writer ); // add some space between buttons maToolbox.InsertSpace(); // Draw item maToolbox.InsertItem( nItemId_Draw, Image( aDrawHelpImage ) ); maToolbox.SetItemText( nItemId_Draw, aDrawHelpText ); maToolbox.ShowItem( nItemId_Draw ); maToolbox.InsertSpace(); // Impresse item maToolbox.InsertItem( nItemId_Impress, Image( aImpressHelpImage ) ); maToolbox.SetItemText( nItemId_Impress, aImpressHelpText ); maToolbox.ShowItem( nItemId_Impress ); maToolbox.InsertSpace(); // Calc item maToolbox.InsertItem( nItemId_Calc, Image( aCalcHelpImage ) ); maToolbox.SetItemText( nItemId_Calc, aCalcHelpText ); maToolbox.ShowItem( nItemId_Calc ); maToolbox.InsertSpace(); // Open file item maToolbox.InsertItem( nItemId_Info, Image( aInfoImage ) ); maToolbox.SetItemText( nItemId_Info, aInfoHelpText ); maToolbox.ShowItem( nItemId_Info ); // get dispatch provider mxDesktop = Reference( comphelper::getProcessServiceFactory()->createInstance(SERVICENAME_DESKTOP ),UNO_QUERY ); if( mxDesktop.is() ) mxDesktopDispatchProvider = Reference< XDispatchProvider >( mxDesktop, UNO_QUERY ); // init background initBackground(); } BackingWindow::~BackingWindow() { delete mpAccExec; } class ImageContainerRes : public Resource { public: ImageContainerRes( const ResId& i_rId ) : Resource( i_rId ) {} ~ImageContainerRes() { FreeResource(); } }; void BackingWindow::DataChanged( const DataChangedEvent& rDCEvt ) { Window::DataChanged( rDCEvt ); if ( rDCEvt.GetFlags() & SETTINGS_STYLE ) { initBackground(); Invalidate(); } } void BackingWindow::initBackground() { SetBackground( GetSettings().GetStyleSettings().GetWorkspaceGradient() ); bool bDark = GetSettings().GetStyleSettings().GetHighContrastMode(); maWelcomeTextColor = maLabelTextColor = bDark ? Color( COL_WHITE ) : Color( 0x58, 0x2c, 0x0f /* Orig. value: 0x26, 0x35, 0x42 */); Color aTextBGColor( bDark ? COL_BLACK : COL_WHITE ); // select image set ImageContainerRes aRes( FwkResId( bDark ? RES_BACKING_IMAGES_HC : RES_BACKING_IMAGES ) ); // scale middle segment Size aFullSize; if( !! maBackgroundMiddle ) aFullSize = maBackgroundMiddle.GetSizePixel(); // load middle segment == the new background maBackgroundMiddle = BitmapEx( FwkResId( BMP_BACKING_BACKGROUND_MONOBLOCK ) ); // and scale it to previous size if( aFullSize.Width() && aFullSize.Height() ) maBackgroundMiddle.Scale( aFullSize ); // we first draw the background of the welcome maWelcome.SetControlForeground( maWelcomeTextColor ); maWelcome.SetBackground(); // then the product fore and background // kept for information // maProduct.SetControlForeground( maWelcomeTextColor ); // maProduct.SetBackground(); // ...text maCreateText.SetControlForeground( maLabelTextColor ); // was buggy : maCreateText.SetControlBackground( aTextBGColor ); maCreateText.SetBackground(); } void BackingWindow::initControls() { if( mbInitControls ) return; mbInitControls = true; // calculate dialog size // begin with background bitmap maControlRect = Rectangle( Point(), maBackgroundMiddle.GetSizePixel() ); maControlRect.Left() += nShadowLeft; maControlRect.Right() -= nShadowRight; maControlRect.Top() += nShadowTop; maControlRect.Bottom() -= nShadowBottom; #ifdef DEBUG fprintf( stdout, "I'm in %s \n", __func__ ); fprintf( stdout, "At line %d \n", __LINE__ ); fprintf(stdout, "maControlRect.Top() : %ld \n", maControlRect.Top() ); fprintf(stdout, "maControlRect.Bottom() : %ld \n", maControlRect.Bottom() ); fprintf(stdout, "maControlRect.Left() : %ld \n", maControlRect.Left() ); fprintf(stdout, "maControlRect.Right() : %ld \n", maControlRect.Right() ); #endif long nYPos = 0; // set bigger welcome string maWelcome.SetText( maWelcomeString ); maTextFont = GetSettings().GetStyleSettings().GetLabelFont(); maTextFont.SetSize( Size( 0, 22) ); maTextFont.SetWeight( WEIGHT_BOLD ); maWelcome.SetFont( maTextFont ); // get metric to get correct width factor and adjust long nW = (maWelcome.GetFontMetric().GetWidth()*95)/100; maTextFont.SetSize( Size( nW, 20 ) ); maWelcome.SetFont( maTextFont ); maWelcome.SetControlFont( maTextFont ); maWelcomeSize = Size( maWelcome.GetTextWidth( maWelcomeString ), maWelcome.GetTextHeight() ); maWelcomeSize.Width() = (maWelcomeSize.Width() * 20)/19; if( maControlRect.GetWidth() < nBtnPos + maWelcomeSize.Width() + 20 ) maControlRect.Right() = maControlRect.Left() + maWelcomeSize.Width() + nBtnPos + 20; maWelcome.Show(); nYPos += 40;// FIXME : calculate a correct value // set a slighly larger font than normal labels on the texts maTextFont.SetSize( Size( 0, 16 ) ); maTextFont.SetWeight( WEIGHT_NORMAL ); maCreateText.SetFont( maTextFont ); maCreateText.SetControlFont( maTextFont ); maCreateText.SetText( maCreateString ); maCreateSize = Size( maCreateText.GetTextWidth( maCreateString ), maCreateText.GetTextHeight() ); maCreateText.Show(); nYPos += 40;// FIXME : calculate a correct value // collect the URLs of the entries in the File/New menu SvtModuleOptions aModuleOptions; std::set< rtl::OUString > aFileNewAppsAvailable; SvtDynamicMenuOptions aOpt; Sequence < Sequence < PropertyValue > > aNewMenu = aOpt.GetMenu( E_NEWMENU ); const rtl::OUString sURLKey( RTL_CONSTASCII_USTRINGPARAM( "URL" ) ); const Sequence< PropertyValue >* pNewMenu = aNewMenu.getConstArray(); const Sequence< PropertyValue >* pNewMenuEnd = aNewMenu.getConstArray() + aNewMenu.getLength(); for ( ; pNewMenu != pNewMenuEnd; ++pNewMenu ) { comphelper::SequenceAsHashMap aEntryItems( *pNewMenu ); rtl::OUString sURL( aEntryItems.getUnpackedValueOrDefault( sURLKey, rtl::OUString() ) ); if ( sURL.getLength() ) aFileNewAppsAvailable.insert( sURL ); } // create mnemonics on the fly, preregister the mnemonics of the menu MnemonicGenerator aMnemns; maOpenString = MnemonicGenerator::EraseAllMnemonicChars( maOpenString ); SystemWindow* pSysWin = GetSystemWindow(); if( pSysWin ) { MenuBar* pMBar = pSysWin->GetMenuBar(); if( pMBar ) { for( USHORT i = 0; i < pMBar->GetItemCount(); i++ ) { USHORT nItemId = pMBar->GetItemId( i ); String aItemText( pMBar->GetItemText( nItemId ) ); if( aItemText.Len() ) aMnemns.RegisterMnemonic( aItemText ); } } } #ifdef DEBUG fprintf( stdout, "I'm in %s \n", __func__ ); fprintf( stdout, "At line %d \n", __LINE__ ); fprintf(stdout, "maControlRect.Top() : %ld \n", maControlRect.Top() ); fprintf(stdout, "maControlRect.Bottom() : %ld \n", maControlRect.Bottom() ); fprintf(stdout, "maControlRect.Left() : %ld \n", maControlRect.Left() ); fprintf(stdout, "maControlRect.Right() : %ld \n", maControlRect.Right() ); #endif maToolbox.SetSelectHdl( LINK( this, BackingWindow, ToolboxHdl ) ); maToolbox.Show(); // scale middle map to formatted width Size aMiddleSegmentSize( maControlRect.GetSize().Width() + nShadowLeft + nShadowRight, maBackgroundMiddle.GetSizePixel().Height() ); long nLW = maBackgroundMiddle.GetSizePixel().Width(); if( aMiddleSegmentSize.Width() > nLW ) { aMiddleSegmentSize.Width() -= nLW; maBackgroundMiddle.Scale( aMiddleSegmentSize ); } else maBackgroundMiddle = BitmapEx(); Resize(); } void BackingWindow::loadImage( const ResId& i_rId, ImageButton& i_rButton ) { BitmapEx aBmp( i_rId ); Size aImgSize( aBmp.GetSizePixel() ); if( aImgSize.Width() > maButtonImageSize.Width() ) maButtonImageSize.Width() = aImgSize.Width(); if( aImgSize.Height() > maButtonImageSize.Height() ) maButtonImageSize.Height() = aImgSize.Height(); i_rButton.SetModeImage( aBmp ); } void BackingWindow::Paint( const Rectangle& ) { bool bDark = GetSettings().GetStyleSettings().GetHighContrastMode(); Color aBackColor( bDark ? COL_BLACK : COL_WHITE ); // Wild fix for the redraw. Needs more love, because probably costly on slow machines initBackground(); // draw bitmap if( GetSettings().GetLayoutRTL() ) { Point aTL( maControlRect.TopLeft() ); aTL.X() -= nShadowRight; aTL.Y() -= nShadowTop; DrawBitmapEx( aTL, maBackgroundMiddle ); aTL.X() += maBackgroundMiddle.GetSizePixel().Width(); } else { Point aTL( maControlRect.TopLeft() ); aTL.X() -= nShadowLeft; aTL.Y() -= nShadowTop; DrawBitmapEx( aTL, maBackgroundMiddle ); aTL.X() += maBackgroundMiddle.GetSizePixel().Width(); } } long BackingWindow::Notify( NotifyEvent& rNEvt ) { #ifdef DEBUG fprintf( stdout, "I'm in %s \n", __func__ ); #endif if( rNEvt.GetType() == EVENT_KEYINPUT ) { if( ! mpAccExec ) { mpAccExec = svt::AcceleratorExecute::createAcceleratorHelper(); mpAccExec->init( comphelper::getProcessServiceFactory(), mxFrame); } const KeyEvent* pEvt = rNEvt.GetKeyEvent(); if( pEvt && mpAccExec->execute(pEvt->GetKeyCode()) ) return 1; } return Window::Notify( rNEvt ); } void BackingWindow::setOwningFrame( const com::sun::star::uno::Reference< com::sun::star::frame::XFrame >& xFrame ) { mxFrame = xFrame; if( ! mbInitControls ) initControls(); } void BackingWindow::Resize() { Size aWindowSize( GetSizePixel() ); Size aControlSize = maControlRect.GetSize(); maControlRect = Rectangle( Point( (aWindowSize.Width() - aControlSize.Width()) / 2 , (aWindowSize.Height() - aControlSize.Height()) / 2 ), aControlSize ); maToolbox.calcMinSize(); Size aTBSize( maToolbox.getMinSize() ); Point aTBPos( maControlRect.Right() - aTBSize.Width() - TOOLBOX_OFFSET_X, maControlRect.Bottom() - aTBSize.Height() - TOOLBOX_OFFSET_Y ); maToolbox.SetPosSizePixel( aTBPos, aTBSize ); long nYPos = maControlRect.Top(); nYPos += 35;// FIXME: better method ... maWelcome.SetPosSizePixel( Point( maControlRect.Left() + nBtnPos - STRING_OFFSET_X, nYPos ), Size( maControlRect.GetWidth() - nBtnPos - 5, (maWelcomeSize.Height()*20)/19 ) ); // defines the location of the Create text nYPos += 210;// FIXME: better method ... maCreateText.SetPosSizePixel( Point( maControlRect.Left() + nBtnPos - ( (maCreateSize.Width() - maWelcomeSize.Width() ) / 2 ) - STRING_OFFSET_X , nYPos ), Size( maControlRect.GetWidth() - nBtnPos - 5, maCreateSize.Height() ) ); } IMPL_LINK( BackingWindow, ToolboxHdl, void*, EMPTYARG ) { const char* pNodePath = NULL; const char* pNode = NULL; switch( maToolbox.GetCurItemId() ) { case nItemId_Writer: dispatchURL( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(WRITER_URL) ) ); break; case nItemId_Calc: dispatchURL( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(CALC_URL) ) ); break; case nItemId_Draw: dispatchURL( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(DRAW_URL) ) ); break; case nItemId_Impress: dispatchURL( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(IMPRESS_WIZARD_URL) ) ); break; case nItemId_Info: { Reference< XDispatchProvider > xFrame( mxFrame, UNO_QUERY ); Sequence< com::sun::star::beans::PropertyValue > aArgs(1); PropertyValue* pArg = aArgs.getArray(); pArg[0].Name = rtl::OUString::createFromAscii("Referer"); pArg[0].Value <<= rtl::OUString::createFromAscii("private:user"); dispatchURL( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM(OPEN_URL) ), rtl::OUString(), xFrame, aArgs ); } break; case nItemId_Extensions: case nItemId_Reg: case nItemId_TplRep: default: break; } if( pNodePath && pNode ) { try { Reference xConfig( comphelper::getProcessServiceFactory()->createInstance(SERVICENAME_CFGPROVIDER),UNO_QUERY); if( xConfig.is() ) { Sequence args(1); PropertyValue val( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM("nodepath") ), 0, Any(rtl::OUString::createFromAscii(pNodePath)), PropertyState_DIRECT_VALUE); args.getArray()[0] <<= val; Reference xNameAccess(xConfig->createInstanceWithArguments(SERVICENAME_CFGREADACCESS,args), UNO_QUERY); if( xNameAccess.is() ) { rtl::OUString sURL; //throws css::container::NoSuchElementException, css::lang::WrappedTargetException Any value( xNameAccess->getByName(rtl::OUString::createFromAscii(pNode)) ); sURL = value.get (); Reference< com::sun::star::system::XSystemShellExecute > xSystemShellExecute( comphelper::getProcessServiceFactory()->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "com.sun.star.system.SystemShellExecute" ) ) ), UNO_QUERY_THROW); //throws css::lang::IllegalArgumentException, css::system::SystemShellExecuteException xSystemShellExecute->execute( sURL, rtl::OUString(), com::sun::star::system::SystemShellExecuteFlags::DEFAULTS); } } } catch (Exception& ) { } } return 0; } struct ImplDelayedDispatch { /* this structure contains all the information to be dispatched */ Reference< XDispatch > xDispatch; com::sun::star::util::URL aDispatchURL; Sequence< PropertyValue > aArgs; ImplDelayedDispatch( const Reference< XDispatch >& i_xDispatch, const com::sun::star::util::URL& i_rURL, const Sequence< PropertyValue >& i_rArgs ) : xDispatch( i_xDispatch ), aDispatchURL( i_rURL ), aArgs( i_rArgs ) { } ~ImplDelayedDispatch() {} }; static long implDispatchDelayed( void*, void* pArg ) { /* implemented call */ struct ImplDelayedDispatch* pDispatch = reinterpret_cast(pArg); try { pDispatch->xDispatch->dispatch( pDispatch->aDispatchURL, pDispatch->aArgs ); } catch( Exception ) { } // clean up delete pDispatch; return 0; } void BackingWindow::dispatchURL( const rtl::OUString& i_rURL, const rtl::OUString& rTarget, const Reference< XDispatchProvider >& i_xProv, const Sequence< PropertyValue >& i_rArgs ) { // if no special dispatch provider is given, get the desktop Reference< XDispatchProvider > xProvider( i_xProv.is() ? i_xProv : mxDesktopDispatchProvider ); // check for dispatch provider if( !xProvider.is()) return; // get an URL transformer to clean up the URL com::sun::star::util::URL aDispatchURL; aDispatchURL.Complete = i_rURL; Reference < com::sun::star::util::XURLTransformer > xURLTransformer( comphelper::getProcessServiceFactory()->createInstance( rtl::OUString::createFromAscii("com.sun.star.util.URLTransformer") ), com::sun::star::uno::UNO_QUERY ); if ( xURLTransformer.is() ) { try { // clean up the URL xURLTransformer->parseStrict( aDispatchURL ); // get a Dispatch for the URL and target Reference< XDispatch > xDispatch( xProvider->queryDispatch( aDispatchURL, rTarget, 0 ) ); // dispatch the URL if ( xDispatch.is() ) { ImplDelayedDispatch* pDisp = new ImplDelayedDispatch( xDispatch, aDispatchURL, i_rArgs ); ULONG nEventId = 0; if( ! Application::PostUserEvent( nEventId, Link( NULL, implDispatchDelayed ), pDisp ) ) delete pDisp; // event could not be posted for unknown reason, at least don't leak } } catch ( com::sun::star::uno::RuntimeException& ) { throw; } catch ( com::sun::star::uno::Exception& ) { } } }