merge the formfield patch from ooo-build
[ooovba.git] / basic / source / app / appwin.cxx
blobad65d453958ceca52343ab33cd45ac5657d1da5b
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: appwin.cxx,v $
10 * $Revision: 1.16 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_basic.hxx"
34 #include <stdio.h>
35 #ifndef _MSGBOX_HXX //autogen
36 #include <vcl/msgbox.hxx>
37 #endif
38 #include <tools/fsys.hxx>
39 #include <svtools/stringtransfer.hxx>
41 #include "basic.hrc"
42 #include "app.hxx"
43 #include <basic/mybasic.hxx>
44 #include "status.hxx"
45 #include "appwin.hxx"
46 #include "dataedit.hxx"
47 #include "dialogs.hxx"
48 #include "basrid.hxx"
50 String *AppWin::pNoName = NULL; // contains the "Untitled"-String
51 short AppWin::nNumber = 0; // consecutive number
52 short AppWin::nCount = 0; // number of edit windows
54 TYPEINIT0(AppWin);
55 AppWin::AppWin( BasicFrame* pParent )
56 : DockingWindow( pParent, WB_SIZEMOVE | WB_CLOSEABLE | WB_PINABLE )
57 , nSkipReload(0)
58 , bHasFile( FALSE )
59 , bReloadAborted( FALSE )
60 , pFrame( pParent )
61 , bFind( TRUE )
62 , pDataEdit(NULL)
64 // Load the Untitled string if not yet loaded
65 if( !pNoName )
66 pNoName = new String( SttResId( IDS_NONAME ) );
67 nCount++;
69 // Get maximized state from current window
70 USHORT nInitialWinState;
71 if ( pFrame->pWork )
73 nInitialWinState = pFrame->pWork->GetWinState();
74 nInitialWinState &= TT_WIN_STATE_MAX | TT_WIN_STATE_FLOAT;
76 else
77 nInitialWinState = TT_WIN_STATE_MAX;
79 StartListening( *pFrame );
80 pFrame->AddWindow( this );
82 ShowTitleButton( TITLE_BUTTON_DOCKING );
83 ShowTitleButton( TITLE_BUTTON_HIDE );
84 SetActivateMode( ACTIVATE_MODE_GRABFOCUS );
86 Cascade( nCount );
87 if ( TT_WIN_STATE_MAX == nInitialWinState )
88 Maximize();
91 AppWin::~AppWin()
93 nCount--;
94 pFrame->RemoveWindow( this );
95 pFrame = NULL; // Set to stop setting window text after BasicRun
98 void AppWin::SetText( const XubString& rStr )
100 DockingWindow::SetText( rStr );
101 pFrame->WindowRenamed( this );
104 void AppWin::TitleButtonClick( USHORT nButton )
106 if ( TITLE_BUTTON_DOCKING == nButton )
107 if ( TT_WIN_STATE_MAX != nWinState )
108 Maximize();
109 else
110 Restore();
111 else // if ( TITLE_BUTTON_HIDE == nButton )
112 Minimize( TRUE );
115 void AppWin::Maximize()
117 if ( TT_WIN_STATE_MAX != nWinState )
119 nNormalPos = GetPosPixel();
120 nNormalSize = GetSizePixel();
122 SetFloatingMode( FALSE );
124 pFrame->nMaximizedWindows++;
125 nWinState = TT_WIN_STATE_MAX;
127 sal_Int32 nTitleHeight;
129 sal_Int32 nDummy1, nDummy2, nDummy3;
130 pFrame->GetBorder( nDummy1, nTitleHeight, nDummy2, nDummy3 );
133 Size aSize = pFrame->GetOutputSizePixel();
134 aSize.Height() -= nTitleHeight;
135 aSize.Height() -= 2;
136 aSize.Width() -= 2;
137 SetSizePixel( aSize );
138 SetPosPixel( Point( 1,1 ) );
139 pFrame->WinMax_Restore();
142 void AppWin::Restore()
144 SetFloatingMode( TRUE );
145 SetPosSizePixel( nNormalPos, nNormalSize );
147 if ( TT_WIN_STATE_MAX == nWinState )
148 pFrame->nMaximizedWindows--;
150 nWinState = TT_WIN_STATE_FLOAT;
151 pFrame->WinMax_Restore();
154 void AppWin::Minimize( BOOL bMinimize )
156 if ( bMinimize )
157 nWinState |= TT_WIN_STATE_HIDE;
158 else
159 nWinState &= ~TT_WIN_STATE_HIDE;
160 pFrame->WinMax_Restore();
163 void AppWin::Cascade( USHORT nNr )
165 Restore();
167 nNr--;
168 nNr %= 10;
169 nNr++;
171 sal_Int32 nTitleHeight;
173 sal_Int32 nDummy1, nDummy2, nDummy3;
174 pFrame->GetBorder( nDummy1, nTitleHeight, nDummy2, nDummy3 );
177 Size aWinSize = pFrame->GetOutputSizePixel();
178 aWinSize.Width() -= aWinSize.Width() / 5; // reduce to 80 %
179 aWinSize.Height() -= nTitleHeight * nNr; // snip height to appropriate value
180 aWinSize.Height() -= 2;
182 Point nPos( nTitleHeight * nNr, nTitleHeight * nNr );
184 SetPosSizePixel( nPos, aWinSize );
187 void AppWin::RequestHelp( const HelpEvent& )
189 Help();
192 void AppWin::Help()
194 String s = pDataEdit->GetSelected();
195 if( s.Len() > 0 )
197 // Trim leading whitespaces
198 while( s.GetChar(0) == ' ' )
199 s.Erase( 0, 1 );
200 // aBasicApp.pHelp->Start( s );
202 else
204 // aBasicApp.pHelp->Start( OOO_HELP_INDEX );
208 void AppWin::Resize()
210 if( pDataEdit )
212 pDataEdit->SetPosPixel( Point( 0, 0 ) );
213 pDataEdit->SetSizePixel( GetOutputSizePixel() );
217 void AppWin::GetFocus()
219 pFrame->FocusWindow( this );
220 if( pDataEdit ) // GetFocus is called by the destructor, so this check
222 pDataEdit->GrabFocus();
223 // InitMenu(GetpApp()->GetAppMenu()->GetPopupMenu( RID_APPEDIT ));
227 long AppWin::PreNotify( NotifyEvent& rNEvt )
230 if ( rNEvt.GetType() == EVENT_MOUSEBUTTONDOWN )
231 Activate();
232 if ( rNEvt.GetType() == EVENT_GETFOCUS )
233 if ( pFrame->pList->Last() != this )
234 Activate();
235 return FALSE; // Der event soll weiter verarbeitet werden
238 void AppWin::Activate()
240 GrabFocus();
243 // Set up the menu
244 long AppWin::InitMenu( Menu* pMenu )
247 ::rtl::OUString aTemp;
248 BOOL bMarked;
249 if( pDataEdit )
251 TextSelection r = pDataEdit->GetSelection();
252 bMarked = r.HasRange();
254 else
255 bMarked = FALSE;
256 pMenu->EnableItem( RID_EDITREPEAT, (aFind.Len() != 0 ) );
257 pMenu->EnableItem( RID_EDITCUT, bMarked );
258 pMenu->EnableItem( RID_EDITCOPY, bMarked );
259 pMenu->EnableItem( RID_EDITPASTE, ( ::svt::OStringTransfer::PasteString( aTemp, this ) ) );
260 pMenu->EnableItem( RID_EDITDEL, bMarked );
261 // pMenu->EnableItem( RID_HELPTOPIC, bMarked );
263 BOOL bHasText;
264 if( pDataEdit )
265 bHasText = pDataEdit->HasText();
266 else
267 bHasText = FALSE;
268 BOOL bRunning = pFrame->Basic().IsRunning();
269 BOOL bCanExecute = BOOL( (!bRunning && bHasText) || pFrame->bInBreak );
270 pMenu->EnableItem( RID_RUNSTART, bCanExecute );
271 pMenu->EnableItem( RID_RUNBREAK, bRunning && !pFrame->bInBreak);
272 pMenu->EnableItem( RID_RUNSTOP, bRunning );
273 pMenu->EnableItem( RID_RUNTOCURSOR, bCanExecute );
274 pMenu->EnableItem( RID_RUNSTEPINTO, bCanExecute );
275 pMenu->EnableItem( RID_RUNSTEPOVER, bCanExecute );
276 return TRUE;
279 long AppWin::DeInitMenu( Menu* pMenu )
281 pMenu->EnableItem( RID_EDITREPEAT );
282 pMenu->EnableItem( RID_EDITCUT );
283 pMenu->EnableItem( RID_EDITCOPY );
284 pMenu->EnableItem( RID_EDITPASTE );
285 pMenu->EnableItem( RID_EDITDEL );
287 pMenu->EnableItem( RID_RUNSTART );
288 pMenu->EnableItem( RID_RUNBREAK );
289 pMenu->EnableItem( RID_RUNSTOP );
290 pMenu->EnableItem( RID_RUNTOCURSOR );
291 pMenu->EnableItem( RID_RUNSTEPINTO );
292 pMenu->EnableItem( RID_RUNSTEPOVER );
293 return TRUE;
296 // Menu Handler
298 void AppWin::Command( const CommandEvent& rCEvt )
300 TextSelection r = pDataEdit->GetSelection();
301 BOOL bHasMark = r.HasRange();
302 switch( rCEvt.GetCommand() ) {
303 case RID_FILESAVE:
304 QuerySave( QUERY_DISK_CHANGED | SAVE_NOT_DIRTY ); break;
305 case RID_FILESAVEAS:
306 SaveAs(); break;
307 case RID_EDITSEARCH:
308 Find(); break;
309 case RID_EDITREPLACE:
310 Replace(); break;
311 case RID_EDITREPEAT:
312 Repeat(); break;
313 case RID_EDITCUT:
314 if( bHasMark )
315 pDataEdit->Cut();
316 break;
317 case RID_EDITCOPY:
318 if( bHasMark )
319 pDataEdit->Copy();
320 break;
321 case RID_EDITPASTE:
323 ::rtl::OUString aTemp;
324 if( ::svt::OStringTransfer::PasteString( aTemp, this ) )
325 pDataEdit->Paste();
327 break;
328 case RID_EDITDEL:
329 /*if( bHasMark ) */pDataEdit->Delete();
330 break;
331 case RID_EDITUNDO:
332 pDataEdit->Undo();
333 break;
334 case RID_EDITREDO:
335 pDataEdit->Redo();
336 break;
337 case COMMAND_CONTEXTMENU:
339 PopupMenu *pKontext = NULL;
340 pDataEdit->BuildKontextMenu( pKontext );
341 if ( pKontext )
343 USHORT nRes = pKontext->Execute( this, GetPointerPosPixel() );
344 if ( nRes )
345 pFrame->Command( nRes );
346 delete pKontext;
349 break;
354 BOOL AppWin::IsSkipReload()
356 return nSkipReload != 0;
359 void AppWin::SkipReload( BOOL bSkip )
361 DBG_ASSERT( bSkip || nSkipReload, "SkipReload aufgehoben ohne es zu aktivieren");
362 if ( bSkip )
363 nSkipReload++;
364 else
365 nSkipReload--;
368 BOOL AppWin::DiskFileChanged( USHORT nWhat )
370 if ( !bHasFile )
371 return FALSE;
373 switch ( nWhat )
375 case SINCE_LAST_LOAD:
377 if ( bReloadAborted )
378 return TRUE;
379 else
380 return DiskFileChanged( SINCE_LAST_ASK_RELOAD );
382 // uncomment to avoid compiler warning
383 // break;
384 case SINCE_LAST_ASK_RELOAD:
386 String aFilename( GetText() );
388 DirEntry aFile( aFilename );
389 FileStat aStat( aFile );
391 return ( !aLastAccess.GetError() != !aStat.GetError() )
392 || aLastAccess.IsYounger( aStat ) || aStat.IsYounger( aLastAccess );
394 // uncomment to avoid compiler warning
395 // break;
396 default:
397 DBG_ERROR("Not Implemented in AppWin::DiskFileChanged");
399 return TRUE;
402 void AppWin::UpdateFileInfo( USHORT nWhat )
404 switch ( nWhat )
406 case HAS_BEEN_LOADED:
408 bReloadAborted = FALSE;
409 UpdateFileInfo( ASKED_RELOAD );
412 break;
413 case ASKED_RELOAD:
415 String aFilename( GetText() );
417 DirEntry aFile( aFilename );
418 aLastAccess.Update( aFile );
420 break;
421 default:
422 DBG_ERROR("Not Implemented in AppWin::UpdateFileInfo");
426 void AppWin::CheckReload()
428 if ( IsSkipReload() || !bHasFile )
429 return;
431 String aFilename( GetText() );
432 DirEntry aFile( aFilename );
433 if ( !aFilename.Len() )
434 return;
436 if ( !aFile.Exists() )
437 return;
439 // FileStat aStat( aFile );
441 if ( DiskFileChanged( SINCE_LAST_ASK_RELOAD ) && ReloadAllowed() )
443 UpdateFileInfo( ASKED_RELOAD );
444 ToTop();
445 Update();
446 if ( (IsModified() && QueryBox( this, SttResId( IDS_ASKDIRTYRELOAD ) ).Execute() == RET_YES )
447 || ( !IsModified() && ( pFrame->IsAutoReload() || QueryBox( this, SttResId( IDS_ASKRELOAD ) ).Execute() == RET_YES ) ) )
449 Reload();
451 else
453 bReloadAborted = TRUE;
458 void AppWin::Reload()
460 SkipReload();
461 TextSelection aSelMemo = pDataEdit->GetSelection();
462 Load( GetText() );
463 pDataEdit->SetSelection( aSelMemo );
464 SkipReload( FALSE );
467 // Load file
468 BOOL AppWin::Load( const String& aName )
470 SkipReload();
471 BOOL bErr;
473 // if( !QuerySave() )
474 // return;
475 bErr = !pDataEdit->Load( aName );
476 if( bErr )
478 ErrorBox aBox( this, SttResId( IDS_READERROR ) );
479 String aMsg = aBox.GetMessText();
480 aMsg.AppendAscii("\n\"");
481 aMsg.Append( aName );
482 aMsg.AppendAscii("\"");
483 if ( pFrame->IsAutoRun() )
485 printf( "%s\n", ByteString( aMsg, osl_getThreadTextEncoding() ).GetBuffer() );
487 else
489 aBox.SetMessText( aMsg );
490 aBox.Execute();
493 else
495 DirEntry aEntry( aName );
496 String aModName = aEntry.GetFull();
497 SetText( aModName );
498 UpdateFileInfo( HAS_BEEN_LOADED );
499 PostLoad();
500 bHasFile = TRUE;
502 SkipReload( FALSE );
503 return !bErr;
506 // Save file
507 USHORT AppWin::ImplSave()
509 SkipReload();
510 USHORT nResult = SAVE_RES_NOT_SAVED;
511 String s1 = *pNoName;
512 String s2 = GetText().Copy( 0, s1.Len() );
513 if( s1 == s2 )
514 nResult = SaveAs();
515 else {
516 String aName = GetText();
517 if ( pDataEdit->Save( aName ) )
519 nResult = SAVE_RES_SAVED;
520 bHasFile = TRUE;
522 else
524 nResult = SAVE_RES_ERROR;
525 ErrorBox( this, SttResId( IDS_WRITEERROR ) ).Execute();
527 UpdateFileInfo( HAS_BEEN_LOADED );
529 SkipReload( FALSE );
530 return nResult;
533 // Save to new file name
534 USHORT AppWin::SaveAs()
536 SkipReload();
537 String s1 = *pNoName;
538 String s2 = GetText().Copy( 0, s1.Len() );
539 if( s1 == s2 ) s2.Erase();
540 else s2 = GetText();
541 if( pFrame->QueryFileName( s2, GetFileType(), TRUE ) )
543 SetText( s2 );
544 PostSaveAs();
545 SkipReload( FALSE );
546 return ImplSave();
548 else
550 SkipReload( FALSE );
551 return SAVE_RES_CANCEL;
555 // Should we save the file?
556 USHORT AppWin::QuerySave( QueryBits nBits )
558 BOOL bQueryDirty = ( nBits & QUERY_DIRTY ) != 0;
559 BOOL bQueryDiskChanged = ( nBits & QUERY_DISK_CHANGED ) != 0;
560 BOOL bSaveNotDirty = ( nBits & SAVE_NOT_DIRTY ) != 0;
562 SkipReload();
563 short nResult;
564 if ( IsModified() || bSaveNotDirty )
565 nResult = RET_YES;
566 else
567 nResult = RET_NO;
569 BOOL bAlwaysEnableInput = pFrame->IsAlwaysEnableInput();
570 pFrame->AlwaysEnableInput( FALSE );
571 if( ( ( IsModified() || bSaveNotDirty ) && bQueryDirty ) || ( DiskFileChanged( SINCE_LAST_LOAD ) && bQueryDiskChanged ) )
573 ToTop();
574 if ( ( ( IsModified() && bQueryDirty ) && DiskFileChanged( SINCE_LAST_LOAD ) )
575 || ( IsModified() && ( DiskFileChanged( SINCE_LAST_LOAD ) && bQueryDiskChanged ) ) )
576 nResult = QueryBox( this, SttResId( IDS_ASK_DIRTY_AND_DISKCHANGE_SAVE ) ).Execute();
577 else if ( ( IsModified() && bQueryDirty ) )
578 nResult = QueryBox( this, SttResId( IDS_ASK_DIRTY_SAVE ) ).Execute();
579 else
580 nResult = QueryBox( this, SttResId( IDS_ASK_DISKCHANGE_SAVE ) ).Execute();
582 pFrame->AlwaysEnableInput( bAlwaysEnableInput );
584 USHORT nReturn;
585 switch( nResult )
587 case RET_YES:
588 nReturn = ImplSave();
589 break;
590 case RET_NO:
591 nReturn = SAVE_RES_NOT_SAVED;
592 break;
593 case RET_CANCEL:
594 nReturn = SAVE_RES_CANCEL;
595 break;
596 default:
597 DBG_ERROR("switch default where no default should be: Internal error");
598 nReturn = SAVE_RES_CANCEL;
600 SkipReload( FALSE );
601 return nReturn;
604 BOOL AppWin::Close()
606 switch ( QuerySave( QUERY_DIRTY ) )
608 case SAVE_RES_NOT_SAVED:
609 case SAVE_RES_SAVED:
611 DockingWindow::Close();
612 delete this;
613 return TRUE;
615 // uncomment to avoid compiler warning
616 // break;
617 case SAVE_RES_ERROR:
618 return FALSE;
619 // uncomment to avoid compiler warning
620 // break;
621 case SAVE_RES_CANCEL:
622 return FALSE;
623 // uncomment to avoid compiler warning
624 // break;
625 default:
626 DBG_ERROR("Not Implemented in AppWin::Close");
627 return FALSE;
631 // Search and find text
632 void AppWin::Find()
634 SttResId aResId( IDD_FIND_DIALOG );
635 FindDialog aDlg( this, aResId, aFind );
636 if( aDlg.Execute() ) {
637 bFind = TRUE;
638 Repeat();
642 // Replace text
643 void AppWin::Replace()
645 SttResId aResId( IDD_REPLACE_DIALOG );
646 ReplaceDialog* pDlg = new ReplaceDialog
647 (this, aResId, aFind, aReplace );
648 if( pDlg->Execute() ) {
649 bFind = FALSE;
650 Repeat();
654 // Repeat search/replace operation
655 void AppWin::Repeat()
657 if( (aFind.Len() != 0 ) && ( pDataEdit->Find( aFind ) || (ErrorBox(this,SttResId(IDS_PATTERNNOTFOUND)).Execute() && FALSE) ) && !bFind )
658 pDataEdit->ReplaceSelected( aReplace );