| /************************************************************** |
| * |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| * |
| *************************************************************/ |
| |
| |
| |
| // MARKER(update_precomp.py): autogen include statement, do not remove |
| #include "precompiled_basic.hxx" |
| |
| #include <stdio.h> |
| #ifndef _MSGBOX_HXX //autogen |
| #include <vcl/msgbox.hxx> |
| #endif |
| #include <tools/fsys.hxx> |
| #include <svtools/stringtransfer.hxx> |
| |
| #include "basic.hrc" |
| #include "app.hxx" |
| #include <basic/mybasic.hxx> |
| #include "status.hxx" |
| #include "appwin.hxx" |
| #include "dataedit.hxx" |
| #include "dialogs.hxx" |
| #include "basrid.hxx" |
| |
| String *AppWin::pNoName = NULL; // contains the "Untitled"-String |
| short AppWin::nNumber = 0; // consecutive number |
| short AppWin::nCount = 0; // number of edit windows |
| |
| TYPEINIT0(AppWin); |
| AppWin::AppWin( BasicFrame* pParent ) |
| : DockingWindow( pParent, WB_SIZEMOVE | WB_CLOSEABLE | WB_PINABLE ) |
| , nSkipReload(0) |
| , bHasFile( sal_False ) |
| , bReloadAborted( sal_False ) |
| , pFrame( pParent ) |
| , bFind( sal_True ) |
| , pDataEdit(NULL) |
| { |
| // Load the Untitled string if not yet loaded |
| if( !pNoName ) |
| pNoName = new String( SttResId( IDS_NONAME ) ); |
| nCount++; |
| |
| // Get maximized state from current window |
| sal_uInt16 nInitialWinState; |
| if ( pFrame->pWork ) |
| { |
| nInitialWinState = pFrame->pWork->GetWinState(); |
| nInitialWinState &= TT_WIN_STATE_MAX | TT_WIN_STATE_FLOAT; |
| } |
| else |
| nInitialWinState = TT_WIN_STATE_MAX; |
| |
| StartListening( *pFrame ); |
| pFrame->AddWindow( this ); |
| |
| ShowTitleButton( TITLE_BUTTON_DOCKING ); |
| ShowTitleButton( TITLE_BUTTON_HIDE ); |
| SetActivateMode( ACTIVATE_MODE_GRABFOCUS ); |
| |
| Cascade( nCount ); |
| if ( TT_WIN_STATE_MAX == nInitialWinState ) |
| Maximize(); |
| } |
| |
| AppWin::~AppWin() |
| { |
| nCount--; |
| pFrame->RemoveWindow( this ); |
| pFrame = NULL; // Set to stop setting window text after BasicRun |
| } |
| |
| void AppWin::SetText( const XubString& rStr ) |
| { |
| DockingWindow::SetText( rStr ); |
| pFrame->WindowRenamed( this ); |
| } |
| |
| void AppWin::TitleButtonClick( sal_uInt16 nButton ) |
| { |
| if ( TITLE_BUTTON_DOCKING == nButton ) |
| if ( TT_WIN_STATE_MAX != nWinState ) |
| Maximize(); |
| else |
| Restore(); |
| else // if ( TITLE_BUTTON_HIDE == nButton ) |
| Minimize( sal_True ); |
| } |
| |
| void AppWin::Maximize() |
| { |
| if ( TT_WIN_STATE_MAX != nWinState ) |
| { |
| nNormalPos = GetPosPixel(); |
| nNormalSize = GetSizePixel(); |
| |
| SetFloatingMode( sal_False ); |
| |
| pFrame->nMaximizedWindows++; |
| nWinState = TT_WIN_STATE_MAX; |
| } |
| |
| Size aSize = pFrame->GetInnerRect().GetSize(); |
| aSize.Height() -= 2; |
| aSize.Width() -= 2; |
| SetSizePixel( aSize ); |
| SetPosPixel( Point( 1,1 ) ); |
| pFrame->WinMax_Restore(); |
| } |
| |
| void AppWin::Restore() |
| { |
| SetFloatingMode( sal_True ); |
| SetPosSizePixel( nNormalPos, nNormalSize ); |
| |
| if ( TT_WIN_STATE_MAX == nWinState ) |
| pFrame->nMaximizedWindows--; |
| |
| nWinState = TT_WIN_STATE_FLOAT; |
| pFrame->WinMax_Restore(); |
| } |
| |
| void AppWin::Minimize( sal_Bool bMinimize ) |
| { |
| if ( bMinimize ) |
| nWinState |= TT_WIN_STATE_HIDE; |
| else |
| nWinState &= ~TT_WIN_STATE_HIDE; |
| pFrame->WinMax_Restore(); |
| } |
| |
| void AppWin::Cascade( sal_uInt16 nNr ) |
| { |
| Restore(); |
| |
| nNr--; |
| nNr %= 10; |
| nNr++; |
| |
| sal_Int32 nTitleHeight; |
| { |
| sal_Int32 nDummy1, nDummy2, nDummy3; |
| pFrame->GetBorder( nDummy1, nTitleHeight, nDummy2, nDummy3 ); |
| } |
| |
| Size aWinSize = pFrame->GetOutputSizePixel(); |
| aWinSize.Width() -= aWinSize.Width() / 5; // reduce to 80 % |
| aWinSize.Height() -= nTitleHeight * nNr; // snip height to appropriate value |
| aWinSize.Height() -= 2; |
| |
| Point nPos( nTitleHeight * nNr, nTitleHeight * nNr ); |
| |
| SetPosSizePixel( nPos, aWinSize ); |
| } |
| |
| void AppWin::RequestHelp( const HelpEvent& ) |
| { |
| Help(); |
| } |
| |
| void AppWin::Help() |
| { |
| String s = pDataEdit->GetSelected(); |
| if( s.Len() > 0 ) |
| { |
| // Trim leading whitespaces |
| while( s.GetChar(0) == ' ' ) |
| s.Erase( 0, 1 ); |
| // aBasicApp.pHelp->Start( s ); |
| } |
| else |
| { |
| // aBasicApp.pHelp->Start( OOO_HELP_INDEX ); |
| } |
| } |
| |
| void AppWin::Resize() |
| { |
| if( pDataEdit ) |
| { |
| pDataEdit->SetPosPixel( Point( 0, 0 ) ); |
| pDataEdit->SetSizePixel( GetOutputSizePixel() ); |
| } |
| } |
| |
| void AppWin::GetFocus() |
| { |
| pFrame->FocusWindow( this ); |
| if( pDataEdit ) // GetFocus is called by the destructor, so this check |
| { |
| pDataEdit->GrabFocus(); |
| // InitMenu(GetpApp()->GetAppMenu()->GetPopupMenu( RID_APPEDIT )); |
| } |
| } |
| |
| long AppWin::PreNotify( NotifyEvent& rNEvt ) |
| { |
| |
| if ( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN ) |
| Activate(); |
| if ( rNEvt.GetType() == EVENT_GETFOCUS ) |
| if ( pFrame->pList->Last() != this ) |
| Activate(); |
| return sal_False; // Der event soll weiter verarbeitet werden |
| } |
| |
| void AppWin::Activate() |
| { |
| GrabFocus(); |
| } |
| |
| // Set up the menu |
| long AppWin::InitMenu( Menu* pMenu ) |
| { |
| |
| ::rtl::OUString aTemp; |
| sal_Bool bMarked; |
| if( pDataEdit ) |
| { |
| TextSelection r = pDataEdit->GetSelection(); |
| bMarked = r.HasRange(); |
| } |
| else |
| bMarked = sal_False; |
| pMenu->EnableItem( RID_EDITREPEAT, (aFind.Len() != 0 ) ); |
| pMenu->EnableItem( RID_EDITCUT, bMarked ); |
| pMenu->EnableItem( RID_EDITCOPY, bMarked ); |
| pMenu->EnableItem( RID_EDITPASTE, ( ::svt::OStringTransfer::PasteString( aTemp, this ) ) ); |
| pMenu->EnableItem( RID_EDITDEL, bMarked ); |
| // pMenu->EnableItem( RID_HELPTOPIC, bMarked ); |
| |
| sal_Bool bHasText; |
| if( pDataEdit ) |
| bHasText = pDataEdit->HasText(); |
| else |
| bHasText = sal_False; |
| sal_Bool bRunning = pFrame->Basic().IsRunning(); |
| sal_Bool bCanExecute = sal_Bool( (!bRunning && bHasText) || pFrame->bInBreak ); |
| pMenu->EnableItem( RID_RUNSTART, bCanExecute ); |
| pMenu->EnableItem( RID_RUNBREAK, bRunning && !pFrame->bInBreak); |
| pMenu->EnableItem( RID_RUNSTOP, bRunning ); |
| pMenu->EnableItem( RID_RUNTOCURSOR, bCanExecute ); |
| pMenu->EnableItem( RID_RUNSTEPINTO, bCanExecute ); |
| pMenu->EnableItem( RID_RUNSTEPOVER, bCanExecute ); |
| return sal_True; |
| } |
| |
| long AppWin::DeInitMenu( Menu* pMenu ) |
| { |
| pMenu->EnableItem( RID_EDITREPEAT ); |
| pMenu->EnableItem( RID_EDITCUT ); |
| pMenu->EnableItem( RID_EDITCOPY ); |
| pMenu->EnableItem( RID_EDITPASTE ); |
| pMenu->EnableItem( RID_EDITDEL ); |
| |
| pMenu->EnableItem( RID_RUNSTART ); |
| pMenu->EnableItem( RID_RUNBREAK ); |
| pMenu->EnableItem( RID_RUNSTOP ); |
| pMenu->EnableItem( RID_RUNTOCURSOR ); |
| pMenu->EnableItem( RID_RUNSTEPINTO ); |
| pMenu->EnableItem( RID_RUNSTEPOVER ); |
| return sal_True; |
| } |
| |
| // Menu Handler |
| |
| void AppWin::Command( const CommandEvent& rCEvt ) |
| { |
| TextSelection r = pDataEdit->GetSelection(); |
| sal_Bool bHasMark = r.HasRange(); |
| switch( rCEvt.GetCommand() ) { |
| case RID_FILESAVE: |
| QuerySave( QUERY_DISK_CHANGED | SAVE_NOT_DIRTY ); break; |
| case RID_FILESAVEAS: |
| SaveAs(); break; |
| case RID_EDITSEARCH: |
| Find(); break; |
| case RID_EDITREPLACE: |
| Replace(); break; |
| case RID_EDITREPEAT: |
| Repeat(); break; |
| case RID_EDITCUT: |
| if( bHasMark ) |
| pDataEdit->Cut(); |
| break; |
| case RID_EDITCOPY: |
| if( bHasMark ) |
| pDataEdit->Copy(); |
| break; |
| case RID_EDITPASTE: |
| { |
| ::rtl::OUString aTemp; |
| if( ::svt::OStringTransfer::PasteString( aTemp, this ) ) |
| pDataEdit->Paste(); |
| } |
| break; |
| case RID_EDITDEL: |
| /*if( bHasMark ) */pDataEdit->Delete(); |
| break; |
| case RID_EDITUNDO: |
| pDataEdit->Undo(); |
| break; |
| case RID_EDITREDO: |
| pDataEdit->Redo(); |
| break; |
| case COMMAND_CONTEXTMENU: |
| { |
| PopupMenu *pKontext = NULL; |
| pDataEdit->BuildKontextMenu( pKontext ); |
| if ( pKontext ) |
| { |
| sal_uInt16 nRes = pKontext->Execute( this, GetPointerPosPixel() ); |
| if ( nRes ) |
| pFrame->Command( nRes ); |
| delete pKontext; |
| } |
| } |
| break; |
| } |
| } |
| |
| |
| sal_Bool AppWin::IsSkipReload() |
| { |
| return nSkipReload != 0; |
| } |
| |
| void AppWin::SkipReload( sal_Bool bSkip ) |
| { |
| DBG_ASSERT( bSkip || nSkipReload, "SkipReload aufgehoben ohne es zu aktivieren"); |
| if ( bSkip ) |
| nSkipReload++; |
| else |
| nSkipReload--; |
| } |
| |
| sal_Bool AppWin::DiskFileChanged( sal_uInt16 nWhat ) |
| { |
| if ( !bHasFile ) |
| return sal_False; |
| |
| switch ( nWhat ) |
| { |
| case SINCE_LAST_LOAD: |
| { |
| if ( bReloadAborted ) |
| return sal_True; |
| else |
| return DiskFileChanged( SINCE_LAST_ASK_RELOAD ); |
| } |
| // uncomment to avoid compiler warning |
| // break; |
| case SINCE_LAST_ASK_RELOAD: |
| { |
| String aFilename( GetText() ); |
| |
| DirEntry aFile( aFilename ); |
| FileStat aStat( aFile ); |
| |
| return ( !aLastAccess.GetError() != !aStat.GetError() ) |
| || aLastAccess.IsYounger( aStat ) || aStat.IsYounger( aLastAccess ); |
| } |
| // uncomment to avoid compiler warning |
| // break; |
| default: |
| DBG_ERROR("Not Implemented in AppWin::DiskFileChanged"); |
| } |
| return sal_True; |
| } |
| |
| void AppWin::UpdateFileInfo( sal_uInt16 nWhat ) |
| { |
| switch ( nWhat ) |
| { |
| case HAS_BEEN_LOADED: |
| { |
| bReloadAborted = sal_False; |
| UpdateFileInfo( ASKED_RELOAD ); |
| |
| } |
| break; |
| case ASKED_RELOAD: |
| { |
| String aFilename( GetText() ); |
| |
| DirEntry aFile( aFilename ); |
| aLastAccess.Update( aFile ); |
| } |
| break; |
| default: |
| DBG_ERROR("Not Implemented in AppWin::UpdateFileInfo"); |
| } |
| } |
| |
| void AppWin::CheckReload() |
| { |
| if ( IsSkipReload() || !bHasFile ) |
| return; |
| |
| String aFilename( GetText() ); |
| DirEntry aFile( aFilename ); |
| if ( !aFilename.Len() ) |
| return; |
| |
| if ( !aFile.Exists() ) |
| return; |
| |
| // FileStat aStat( aFile ); |
| |
| if ( DiskFileChanged( SINCE_LAST_ASK_RELOAD ) && ReloadAllowed() ) |
| { |
| UpdateFileInfo( ASKED_RELOAD ); |
| ToTop(); |
| Update(); |
| if ( (IsModified() && QueryBox( this, SttResId( IDS_ASKDIRTYRELOAD ) ).Execute() == RET_YES ) |
| || ( !IsModified() && ( pFrame->IsAutoReload() || QueryBox( this, SttResId( IDS_ASKRELOAD ) ).Execute() == RET_YES ) ) ) |
| { |
| Reload(); |
| } |
| else |
| { |
| bReloadAborted = sal_True; |
| } |
| } |
| } |
| |
| void AppWin::Reload() |
| { |
| SkipReload(); |
| TextSelection aSelMemo = pDataEdit->GetSelection(); |
| Load( GetText() ); |
| pDataEdit->SetSelection( aSelMemo ); |
| SkipReload( sal_False ); |
| } |
| |
| // Load file |
| sal_Bool AppWin::Load( const String& aName ) |
| { |
| SkipReload(); |
| sal_Bool bErr; |
| |
| // if( !QuerySave() ) |
| // return; |
| bErr = !pDataEdit->Load( aName ); |
| if( bErr ) |
| { |
| ErrorBox aBox( this, SttResId( IDS_READERROR ) ); |
| String aMsg = aBox.GetMessText(); |
| aMsg.AppendAscii("\n\""); |
| aMsg.Append( aName ); |
| aMsg.AppendAscii("\""); |
| if ( pFrame->IsAutoRun() ) |
| { |
| printf( "%s\n", ByteString( aMsg, osl_getThreadTextEncoding() ).GetBuffer() ); |
| } |
| else |
| { |
| aBox.SetMessText( aMsg ); |
| aBox.Execute(); |
| } |
| } |
| else |
| { |
| DirEntry aEntry( aName ); |
| String aModName = aEntry.GetFull(); |
| SetText( aModName ); |
| UpdateFileInfo( HAS_BEEN_LOADED ); |
| PostLoad(); |
| bHasFile = sal_True; |
| } |
| SkipReload( sal_False ); |
| return !bErr; |
| } |
| |
| // Save file |
| sal_uInt16 AppWin::ImplSave() |
| { |
| SkipReload(); |
| sal_uInt16 nResult = SAVE_RES_NOT_SAVED; |
| String s1 = *pNoName; |
| String s2 = GetText().Copy( 0, s1.Len() ); |
| if( s1 == s2 ) |
| nResult = SaveAs(); |
| else { |
| String aName = GetText(); |
| if ( pDataEdit->Save( aName ) ) |
| { |
| nResult = SAVE_RES_SAVED; |
| bHasFile = sal_True; |
| } |
| else |
| { |
| nResult = SAVE_RES_ERROR; |
| ErrorBox( this, SttResId( IDS_WRITEERROR ) ).Execute(); |
| } |
| UpdateFileInfo( HAS_BEEN_LOADED ); |
| } |
| SkipReload( sal_False ); |
| return nResult; |
| } |
| |
| // Save to new file name |
| sal_uInt16 AppWin::SaveAs() |
| { |
| SkipReload(); |
| String s1 = *pNoName; |
| String s2 = GetText().Copy( 0, s1.Len() ); |
| if( s1 == s2 ) s2.Erase(); |
| else s2 = GetText(); |
| if( pFrame->QueryFileName( s2, GetFileType(), sal_True ) ) |
| { |
| SetText( s2 ); |
| PostSaveAs(); |
| SkipReload( sal_False ); |
| return ImplSave(); |
| } |
| else |
| { |
| SkipReload( sal_False ); |
| return SAVE_RES_CANCEL; |
| } |
| } |
| |
| // Should we save the file? |
| sal_uInt16 AppWin::QuerySave( QueryBits nBits ) |
| { |
| sal_Bool bQueryDirty = ( nBits & QUERY_DIRTY ) != 0; |
| sal_Bool bQueryDiskChanged = ( nBits & QUERY_DISK_CHANGED ) != 0; |
| sal_Bool bSaveNotDirty = ( nBits & SAVE_NOT_DIRTY ) != 0; |
| |
| SkipReload(); |
| short nResult; |
| if ( IsModified() || bSaveNotDirty ) |
| nResult = RET_YES; |
| else |
| nResult = RET_NO; |
| |
| sal_Bool bAlwaysEnableInput = pFrame->IsAlwaysEnableInput(); |
| pFrame->AlwaysEnableInput( sal_False ); |
| if( ( ( IsModified() || bSaveNotDirty ) && bQueryDirty ) || ( DiskFileChanged( SINCE_LAST_LOAD ) && bQueryDiskChanged ) ) |
| { |
| ToTop(); |
| if ( ( ( IsModified() && bQueryDirty ) && DiskFileChanged( SINCE_LAST_LOAD ) ) |
| || ( IsModified() && ( DiskFileChanged( SINCE_LAST_LOAD ) && bQueryDiskChanged ) ) ) |
| nResult = QueryBox( this, SttResId( IDS_ASK_DIRTY_AND_DISKCHANGE_SAVE ) ).Execute(); |
| else if ( ( IsModified() && bQueryDirty ) ) |
| nResult = QueryBox( this, SttResId( IDS_ASK_DIRTY_SAVE ) ).Execute(); |
| else |
| nResult = QueryBox( this, SttResId( IDS_ASK_DISKCHANGE_SAVE ) ).Execute(); |
| } |
| pFrame->AlwaysEnableInput( bAlwaysEnableInput ); |
| |
| sal_uInt16 nReturn; |
| switch( nResult ) |
| { |
| case RET_YES: |
| nReturn = ImplSave(); |
| break; |
| case RET_NO: |
| nReturn = SAVE_RES_NOT_SAVED; |
| break; |
| case RET_CANCEL: |
| nReturn = SAVE_RES_CANCEL; |
| break; |
| default: |
| DBG_ERROR("switch default where no default should be: Internal error"); |
| nReturn = SAVE_RES_CANCEL; |
| } |
| SkipReload( sal_False ); |
| return nReturn; |
| } |
| |
| sal_Bool AppWin::Close() |
| { |
| switch ( QuerySave( QUERY_DIRTY ) ) |
| { |
| case SAVE_RES_NOT_SAVED: |
| case SAVE_RES_SAVED: |
| { |
| DockingWindow::Close(); |
| delete this; |
| return sal_True; |
| } |
| // uncomment to avoid compiler warning |
| // break; |
| case SAVE_RES_ERROR: |
| return sal_False; |
| // uncomment to avoid compiler warning |
| // break; |
| case SAVE_RES_CANCEL: |
| return sal_False; |
| // uncomment to avoid compiler warning |
| // break; |
| default: |
| DBG_ERROR("Not Implemented in AppWin::Close"); |
| return sal_False; |
| } |
| } |
| |
| // Search and find text |
| void AppWin::Find() |
| { |
| SttResId aResId( IDD_FIND_DIALOG ); |
| FindDialog aDlg( this, aResId, aFind ); |
| if( aDlg.Execute() ) { |
| bFind = sal_True; |
| Repeat(); |
| } |
| } |
| |
| // Replace text |
| void AppWin::Replace() |
| { |
| SttResId aResId( IDD_REPLACE_DIALOG ); |
| ReplaceDialog* pDlg = new ReplaceDialog |
| (this, aResId, aFind, aReplace ); |
| if( pDlg->Execute() ) { |
| bFind = sal_False; |
| Repeat(); |
| } |
| } |
| |
| // Repeat search/replace operation |
| void AppWin::Repeat() |
| { |
| if( (aFind.Len() != 0 ) && ( pDataEdit->Find( aFind ) || (ErrorBox(this,SttResId(IDS_PATTERNNOTFOUND)).Execute() && sal_False) ) && !bFind ) |
| pDataEdit->ReplaceSelected( aReplace ); |
| } |
| |