forked from amazingfate/loongoffice
635 lines
16 KiB
C++
635 lines
16 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/*************************************************************************
|
|
*
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* Copyright 2000, 2010 Oracle and/or its affiliates.
|
|
*
|
|
* OpenOffice.org - a multi-platform office productivity suite
|
|
*
|
|
* This file is part of OpenOffice.org.
|
|
*
|
|
* OpenOffice.org 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.
|
|
*
|
|
* OpenOffice.org 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 OpenOffice.org. If not, see
|
|
* <http://www.openoffice.org/license.html>
|
|
* for a copy of the LGPLv3 License.
|
|
*
|
|
************************************************************************/
|
|
|
|
// MARKER(update_precomp.py): autogen include statement, do not remove
|
|
#include "precompiled_basic.hxx"
|
|
|
|
#include <stdio.h>
|
|
#include <vcl/msgbox.hxx>
|
|
#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 );
|
|
}
|
|
else
|
|
{
|
|
}
|
|
}
|
|
|
|
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();
|
|
}
|
|
}
|
|
|
|
long AppWin::PreNotify( NotifyEvent& rNEvt )
|
|
{
|
|
|
|
if ( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN )
|
|
Activate();
|
|
if ( rNEvt.GetType() == EVENT_GETFOCUS )
|
|
if ( pFrame->pList->back() != this )
|
|
Activate();
|
|
return sal_False; // the event shall continue to be handled
|
|
}
|
|
|
|
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 );
|
|
|
|
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:
|
|
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 );
|
|
}
|
|
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 );
|
|
}
|
|
default:
|
|
OSL_FAIL("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:
|
|
OSL_FAIL("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;
|
|
|
|
|
|
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;
|
|
|
|
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:
|
|
OSL_FAIL("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;
|
|
}
|
|
case SAVE_RES_ERROR:
|
|
return sal_False;
|
|
case SAVE_RES_CANCEL:
|
|
return sal_False;
|
|
default:
|
|
OSL_FAIL("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 );
|
|
}
|
|
|
|
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|