1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: inettbc.cxx,v $
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_svtools.hxx"
36 #include <sys/types.h>
40 #include <svtools/inettbc.hxx>
41 #include <com/sun/star/uno/Any.hxx>
42 #include <com/sun/star/uno/Reference.hxx>
43 #include <com/sun/star/beans/PropertyValue.hpp>
44 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
45 #include <com/sun/star/sdbc/XResultSet.hpp>
46 #include <com/sun/star/sdbc/XRow.hpp>
48 #ifndef _COM_SUN_STAR_TASK_XINTERACTIONHANDLER_HDL_
49 #include <com/sun/star/task/XInteractionHandler.hdl>
51 #include <com/sun/star/ucb/NumberedSortingInfo.hpp>
52 #include <com/sun/star/ucb/XAnyCompareFactory.hpp>
53 #include <com/sun/star/ucb/XProgressHandler.hpp>
54 #include <com/sun/star/ucb/XContentAccess.hpp>
55 #include <com/sun/star/ucb/XSortedDynamicResultSetFactory.hpp>
57 #ifndef _UNOTOOLS_PROCESSFACTORY_HXX
58 #include <comphelper/processfactory.hxx>
61 #include <vcl/toolbox.hxx>
62 #ifndef _VOS_THREAD_HXX //autogen
63 #include <vos/thread.hxx>
65 #ifndef _VOS_MUTEX_HXX //autogen
66 #include <vos/mutex.hxx>
68 #include <vcl/svapp.hxx>
69 #include <svtools/historyoptions.hxx>
70 #include <svtools/eitem.hxx>
71 #include <svtools/stritem.hxx>
72 #include <svtools/cancel.hxx>
73 #include <svtools/itemset.hxx>
74 #include "urihelper.hxx"
75 #include <svtools/pathoptions.hxx>
77 #define _SVSTDARR_STRINGSDTOR
78 #include <svtools/svstdarr.hxx>
79 #include <ucbhelper/commandenvironment.hxx>
80 #include <ucbhelper/content.hxx>
81 #include <unotools/localfilehelper.hxx>
82 #include <unotools/ucbhelper.hxx>
85 #include <asynclink.hxx>
86 #include <svtools/urlfilter.hxx>
91 // -----------------------------------------------------------------------
93 using namespace ::rtl
;
94 using namespace ::ucbhelper
;
95 using namespace ::utl
;
96 using namespace ::com::sun::star
;
97 using namespace ::com::sun::star::beans
;
98 using namespace ::com::sun::star::lang
;
99 using namespace ::com::sun::star::sdbc
;
100 using namespace ::com::sun::star::task
;
101 using namespace ::com::sun::star::ucb
;
102 using namespace ::com::sun::star::uno
;
104 // -----------------------------------------------------------------------
108 SvStringsDtor
* pURLs
;
109 SvStringsDtor
* pCompletions
;
110 const IUrlFilter
* pUrlFilter
;
111 ::std::vector
< WildCard
> m_aFilters
;
113 static sal_Bool
TildeParsing( String
& aText
, String
& aBaseUrl
);
115 inline SvtURLBox_Impl( )
117 ,pCompletions( NULL
)
120 FilterMatch::createWildCardFilterList(String(),m_aFilters
);
124 // -----------------------------------------------------------------------
125 class SvtMatchContext_Impl
: public ::vos::OThread
127 static ::vos::OMutex
* pDirMutex
;
129 SvStringsDtor aPickList
;
130 SvStringsDtor
* pCompletions
;
131 SvStringsDtor
* pURLs
;
132 svtools::AsynchronLink aLink
;
137 BOOL bOnlyDirectories
;
140 DECL_STATIC_LINK( SvtMatchContext_Impl
, Select_Impl
, void* );
142 virtual void SAL_CALL
onTerminated( );
143 virtual void SAL_CALL
run();
144 virtual void SAL_CALL
Cancel();
145 void Insert( const String
& rCompletion
, const String
& rURL
, BOOL bForce
= FALSE
);
146 void ReadFolder( const String
& rURL
, const String
& rMatch
, BOOL bSmart
);
147 void FillPicklist( SvStringsDtor
& rPickList
);
150 static ::vos::OMutex
* GetMutex();
152 SvtMatchContext_Impl( SvtURLBox
* pBoxP
, const String
& rText
);
153 ~SvtMatchContext_Impl();
157 ::vos::OMutex
* SvtMatchContext_Impl::pDirMutex
= 0;
159 ::vos::OMutex
* SvtMatchContext_Impl::GetMutex()
161 ::vos::OGuard
aGuard( ::vos::OMutex::getGlobalMutex() );
163 pDirMutex
= new ::vos::OMutex
;
167 //-------------------------------------------------------------------------
168 SvtMatchContext_Impl::SvtMatchContext_Impl(
169 SvtURLBox
* pBoxP
, const String
& rText
)
170 : aLink( STATIC_LINK( this, SvtMatchContext_Impl
, Select_Impl
) )
171 , aBaseURL( pBoxP
->aBaseURL
)
175 , bOnlyDirectories( pBoxP
->bOnlyDirectories
)
176 , bNoSelection( pBoxP
->bNoSelection
)
178 pURLs
= new SvStringsDtor
;
179 pCompletions
= new SvStringsDtor
;
183 FillPicklist( aPickList
);
188 //-------------------------------------------------------------------------
189 SvtMatchContext_Impl::~SvtMatchContext_Impl()
191 aLink
.ClearPendingCall();
196 //-------------------------------------------------------------------------
197 void SvtMatchContext_Impl::FillPicklist( SvStringsDtor
& rPickList
)
199 // Einlesung der Historypickliste
200 Sequence
< Sequence
< PropertyValue
> > seqPicklist
= SvtHistoryOptions().GetList( eHISTORY
);
201 sal_uInt32 nCount
= seqPicklist
.getLength();
203 for( sal_uInt32 nItem
=0; nItem
< nCount
; nItem
++ )
205 Sequence
< PropertyValue
> seqPropertySet
= seqPicklist
[ nItem
];
210 sal_uInt32 nPropertyCount
= seqPropertySet
.getLength();
212 for( sal_uInt32 nProperty
=0; nProperty
< nPropertyCount
; nProperty
++ )
214 if( seqPropertySet
[nProperty
].Name
== HISTORY_PROPERTYNAME_TITLE
)
216 seqPropertySet
[nProperty
].Value
>>= sTitle
;
217 aURL
.SetURL( sTitle
);
218 const StringPtr pStr
= new String( aURL
.GetMainURL( INetURLObject::DECODE_WITH_CHARSET
) );
219 rPickList
.Insert( pStr
, (USHORT
) nItem
);
226 //-------------------------------------------------------------------------
227 void SAL_CALL
SvtMatchContext_Impl::Cancel()
229 // Cancel button pressed
233 //-------------------------------------------------------------------------
234 void SvtMatchContext_Impl::Stop()
242 //-------------------------------------------------------------------------
243 void SvtMatchContext_Impl::onTerminated( )
248 //-------------------------------------------------------------------------
249 // This method is called via AsynchronLink, so it has the SolarMutex and
250 // calling solar code ( VCL ... ) is safe. It is called when the thread is
251 // terminated ( finished work or stopped ). Cancelling the thread via
252 // Cancellable does not not discard the information gained so far, it
253 // inserts all collected completions into the listbox.
255 IMPL_STATIC_LINK( SvtMatchContext_Impl
, Select_Impl
, void*, )
257 // avoid recursion through cancel button
260 // completions was stopped, no display
265 SvtURLBox
* pBox
= pThis
->pBox
;
266 pBox
->bAutoCompleteMode
= TRUE
;
268 // did we filter completions which otherwise would have been valid?
269 // (to be filled below)
270 bool bValidCompletionsFiltered
= false;
272 // insert all completed strings into the listbox
275 for( USHORT nPos
= 0; nPos
<pThis
->pCompletions
->Count(); nPos
++ )
277 String
sCompletion( *(*pThis
->pCompletions
)[nPos
] );
279 // convert the file into an URL
280 String
sURL( sCompletion
);
281 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( sCompletion
, sURL
);
282 // note: if this doesn't work, we're not interested in: we're checking the
283 // untouched sCompletion then
285 if ( pBox
->pImp
->pUrlFilter
)
287 if ( !pBox
->pImp
->pUrlFilter
->isUrlAllowed( sURL
) )
288 { // this URL is not allowed
289 bValidCompletionsFiltered
= true;
293 if (( sURL
.Len() > 0 ) && ( sURL
.GetChar(sURL
.Len()-1) != '/' ))
295 String
sUpperURL( sURL
);
296 sUpperURL
.ToUpperAscii();
298 ::std::vector
< WildCard
>::const_iterator aMatchingFilter
=
300 pBox
->pImp
->m_aFilters
.begin(),
301 pBox
->pImp
->m_aFilters
.end(),
302 FilterMatch( sUpperURL
)
304 if ( aMatchingFilter
== pBox
->pImp
->m_aFilters
.end() )
306 { // this URL is not allowed
307 bValidCompletionsFiltered
= true;
312 pBox
->InsertEntry( sCompletion
);
315 if( !pThis
->bNoSelection
&& pThis
->pCompletions
->Count() && !bValidCompletionsFiltered
)
317 // select the first one
318 String
aTmp( pBox
->GetEntry(0) );
319 pBox
->SetText( aTmp
);
320 pBox
->SetSelection( Selection( pThis
->aText
.Len(), aTmp
.Len() ) );
323 // transfer string lists to listbox and forget them
324 delete pBox
->pImp
->pURLs
;
325 delete pBox
->pImp
->pCompletions
;
326 pBox
->pImp
->pURLs
= pThis
->pURLs
;
327 pBox
->pImp
->pCompletions
= pThis
->pCompletions
;
329 pThis
->pCompletions
= NULL
;
331 // force listbox to resize ( it may be open )
334 // the box has this control as a member so we have to set that member
335 // to zero before deleting ourself.
342 //-------------------------------------------------------------------------
343 void SvtMatchContext_Impl::Insert( const String
& rCompletion
,
350 for( USHORT nPos
= pCompletions
->Count(); nPos
--; )
351 if( *(*pCompletions
)[ nPos
] == rCompletion
)
355 const StringPtr pCompletion
= new String( rCompletion
);
356 pCompletions
->Insert( pCompletion
, pCompletions
->Count() );
357 const StringPtr pURL
= new String( rURL
);
358 pURLs
->Insert( pURL
, pURLs
->Count() );
361 //-------------------------------------------------------------------------
362 void SvtMatchContext_Impl::ReadFolder( const String
& rURL
,
363 const String
& rMatch
,
366 // check folder to scan
367 if( !UCBContentHelper::IsFolder( rURL
) )
370 sal_Bool bPureHomePath
= sal_False
;
372 bPureHomePath
= aText
.Search( '~' ) == 0 && aText
.Search( '/' ) == STRING_NOTFOUND
;
375 sal_Bool bExectMatch
= bPureHomePath
376 || aText
.CompareToAscii( "." ) == COMPARE_EQUAL
377 || (aText
.Len() > 1 && aText
.Copy( aText
.Len() - 2, 2 ).CompareToAscii( "/." ) == COMPARE_EQUAL
)
378 || (aText
.Len() > 2 && aText
.Copy( aText
.Len() - 3, 3 ).CompareToAscii( "/.." ) == COMPARE_EQUAL
);
380 // for pure home pathes ( ~username ) the '.' at the end of rMatch
381 // means that it poits to root catalog
382 // this is done only for file contents since home pathes parsing is usefull only for them
383 if ( bPureHomePath
&& rMatch
.Equals( String::CreateFromAscii( "file:///." ) ) )
385 // a home that refers to /
387 String
aNewText( aText
);
389 Insert( aNewText
, rURL
, TRUE
);
394 // string to match with
395 INetURLObject
aMatchObj( rMatch
);
398 if ( rURL
!= String(aMatchObj
.GetMainURL( INetURLObject::NO_DECODE
) ))
400 aMatchName
= aMatchObj
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DECODE_WITH_CHARSET
);
402 // matching is always done case insensitive, but completion will be case sensitive and case preserving
403 aMatchName
.ToLowerAscii();
405 // if the matchstring ends with a slash, we must search for this also
406 if ( rMatch
.GetChar(rMatch
.Len()-1) == '/' )
410 xub_StrLen nMatchLen
= aMatchName
.Len();
412 INetURLObject
aFolderObj( rURL
);
413 DBG_ASSERT( aFolderObj
.GetProtocol() != INET_PROT_NOT_VALID
, "Invalid URL!" );
417 uno::Reference
< XMultiServiceFactory
> xFactory
= ::comphelper::getProcessServiceFactory();
419 Content
aCnt( aFolderObj
.GetMainURL( INetURLObject::NO_DECODE
),
420 new ::ucbhelper::CommandEnvironment( uno::Reference
< XInteractionHandler
>(),
421 uno::Reference
< XProgressHandler
>() ) );
422 uno::Reference
< XResultSet
> xResultSet
;
423 Sequence
< OUString
> aProps(2);
424 OUString
* pProps
= aProps
.getArray();
425 pProps
[0] = OUString( RTL_CONSTASCII_USTRINGPARAM( "Title" ) );
426 pProps
[1] = OUString( RTL_CONSTASCII_USTRINGPARAM( "IsFolder" ) );
430 uno::Reference
< XDynamicResultSet
> xDynResultSet
;
431 ResultSetInclude eInclude
= INCLUDE_FOLDERS_AND_DOCUMENTS
;
432 if ( bOnlyDirectories
)
433 eInclude
= INCLUDE_FOLDERS_ONLY
;
435 xDynResultSet
= aCnt
.createDynamicCursor( aProps
, eInclude
);
437 uno::Reference
< XAnyCompareFactory
> xCompare
;
438 uno::Reference
< XSortedDynamicResultSetFactory
> xSRSFac(
439 xFactory
->createInstance( OUString( RTL_CONSTASCII_USTRINGPARAM("com.sun.star.ucb.SortedDynamicResultSetFactory") ) ), UNO_QUERY
);
441 Sequence
< NumberedSortingInfo
> aSortInfo( 2 );
442 NumberedSortingInfo
* pInfo
= aSortInfo
.getArray();
443 pInfo
[ 0 ].ColumnIndex
= 2;
444 pInfo
[ 0 ].Ascending
= sal_False
;
445 pInfo
[ 1 ].ColumnIndex
= 1;
446 pInfo
[ 1 ].Ascending
= sal_True
;
448 uno::Reference
< XDynamicResultSet
> xDynamicResultSet
;
450 xSRSFac
->createSortedDynamicResultSet( xDynResultSet
, aSortInfo
, xCompare
);
452 if ( xDynamicResultSet
.is() )
454 xResultSet
= xDynamicResultSet
->getStaticResultSet();
457 catch( ::com::sun::star::uno::Exception
& ) {}
459 if ( xResultSet
.is() )
461 uno::Reference
< XRow
> xRow( xResultSet
, UNO_QUERY
);
462 uno::Reference
< XContentAccess
> xContentAccess( xResultSet
, UNO_QUERY
);
466 while ( schedule() && xResultSet
->next() )
468 String aURL
= xContentAccess
->queryContentIdentifierString();
469 String aTitle
= xRow
->getString(1);
470 sal_Bool bIsFolder
= xRow
->getBoolean(2);
472 // matching is always done case insensitive, but completion will be case sensitive and case preserving
473 aTitle
.ToLowerAscii();
477 (bExectMatch
&& aMatchName
.Equals(aTitle
)) ||
478 (!bExectMatch
&& aMatchName
.CompareTo(aTitle
, nMatchLen
) == COMPARE_EQUAL
)
481 // all names fit if matchstring is empty
482 INetURLObject
aObj( aURL
);
483 sal_Unicode aDelimiter
= '/';
485 // when parsing is done "smart", the delimiter must be "guessed"
486 aObj
.getFSysPath( (INetURLObject::FSysStyle
)(INetURLObject::FSYS_DETECT
& ~INetURLObject::FSYS_VOS
), &aDelimiter
);
489 aObj
.setFinalSlash();
491 // get the last name of the URL
492 String aMatch
= aObj
.getName( INetURLObject::LAST_SEGMENT
, true, INetURLObject::DECODE_WITH_CHARSET
);
493 String
aInput( aText
);
496 if ((aText
.Len() && aText
.GetChar(aText
.Len() - 1) == '.') || bPureHomePath
)
498 // if a "special folder" URL was typed, don't touch the user input
499 aMatch
.Erase( 0, nMatchLen
);
503 // make the user input case preserving
504 DBG_ASSERT( aInput
.Len() >= nMatchLen
, "Suspicious Matching!" );
505 aInput
.Erase( aInput
.Len() - nMatchLen
);
511 // folders should get a final slash automatically
513 aInput
+= aDelimiter
;
515 Insert( aInput
, aObj
.GetMainURL( INetURLObject::NO_DECODE
), TRUE
);
519 catch( ::com::sun::star::uno::Exception
& )
524 catch( ::com::sun::star::uno::Exception
& )
529 //-------------------------------------------------------------------------
530 String
SvtURLBox::ParseSmart( String aText
, String aBaseURL
, String aWorkDir
)
534 // parse ~ for Unix systems
535 // does nothing for Windows
536 if( !SvtURLBox_Impl::TildeParsing( aText
, aBaseURL
) )
539 INetURLObject aURLObject
;
542 INetProtocol eBaseProt
= INetURLObject::CompareProtocolScheme( aBaseURL
);
544 // if a base URL is set the string may be parsed relative
545 if( aText
.Search( '/' ) == 0 )
547 // text starting with slashes means absolute file URLs
548 String aTemp
= INetURLObject::GetScheme( eBaseProt
);
550 // file URL must be correctly encoded!
551 String aTextURL
= INetURLObject::encode( aText
, INetURLObject::PART_FPATH
,
552 '%', INetURLObject::ENCODE_ALL
);
555 INetURLObject
aTmp( aTemp
);
556 if ( !aTmp
.HasError() && aTmp
.GetProtocol() != INET_PROT_NOT_VALID
)
557 aMatch
= aTmp
.GetMainURL( INetURLObject::NO_DECODE
);
561 String
aSmart( aText
);
562 INetURLObject
aObj( aBaseURL
);
564 // HRO: I suppose this hack should only be done for Windows !!!???
566 // HRO: INetURLObject::smatRel2Abs does not recognize '\\' as a relative path
567 // but in case of "\\\\" INetURLObject is right - this is an absolute path !
569 if( aText
.Search( '\\' ) == 0 && (aText
.Len() < 2 || aText
.GetChar( 1 ) != '\\') )
571 // cut to first segment
572 String aTmp
= INetURLObject::GetScheme( eBaseProt
);
574 aTmp
+= String(aObj
.getName( 0, true, INetURLObject::DECODE_WITH_CHARSET
));
580 // base URL must be a directory !
581 aObj
.setFinalSlash();
583 // take base URL and append current input
584 bool bWasAbsolute
= FALSE
;
586 // don't support FSYS_MAC under Unix, because here ':' is a valid character for a filename
587 INetURLObject::FSysStyle eStyle
= static_cast< INetURLObject::FSysStyle
>( INetURLObject::FSYS_VOS
| INetURLObject::FSYS_UNX
| INetURLObject::FSYS_DOS
);
588 // encode file URL correctly
589 aSmart
= INetURLObject::encode( aSmart
, INetURLObject::PART_FPATH
, '%', INetURLObject::ENCODE_ALL
);
590 INetURLObject
aTmp( aObj
.smartRel2Abs(
591 aSmart
, bWasAbsolute
, false, INetURLObject::WAS_ENCODED
, RTL_TEXTENCODING_UTF8
, false, eStyle
) );
593 INetURLObject
aTmp( aObj
.smartRel2Abs( aSmart
, bWasAbsolute
) );
596 if ( aText
.GetChar( aText
.Len() - 1 ) == '.' )
597 // INetURLObject appends a final slash for the directories "." and "..", this is a bug!
598 // Remove it as a workaround
599 aTmp
.removeFinalSlash();
600 if ( !aTmp
.HasError() && aTmp
.GetProtocol() != INET_PROT_NOT_VALID
)
601 aMatch
= aTmp
.GetMainURL( INetURLObject::NO_DECODE
);
606 ::utl::LocalFileHelper::ConvertSystemPathToURL( aText
, aWorkDir
, aMatch
);
612 //-------------------------------------------------------------------------
613 void SvtMatchContext_Impl::run()
615 ::vos::OGuard
aGuard( GetMutex() );
617 // have we been stopped while we were waiting for the mutex?
621 pCompletions
->Remove( 0, pCompletions
->Count() );
622 pURLs
->Remove( 0, pURLs
->Count() );
625 USHORT nTextLen
= aText
.Len();
629 if( aText
.Search( '*' ) != STRING_NOTFOUND
|| aText
.Search( '?' ) != STRING_NOTFOUND
)
630 // no autocompletion for wildcards
634 String
aWorkDir( SvtPathOptions().GetWorkPath() );
635 INetProtocol eProt
= INetURLObject::CompareProtocolScheme( aText
);
636 INetProtocol eBaseProt
= INetURLObject::CompareProtocolScheme( aBaseURL
);
637 if ( !aBaseURL
.Len() )
638 eBaseProt
= INetURLObject::CompareProtocolScheme( aWorkDir
);
639 INetProtocol eSmartProt
= pBox
->GetSmartProtocol();
641 // if the user input is a valid URL, go on with it
642 // otherwise it could be parsed smart with a predefined smart protocol
643 // ( or if this is not set with the protocol of a predefined base URL )
644 if( eProt
== INET_PROT_NOT_VALID
|| eProt
== eSmartProt
|| (eSmartProt
== INET_PROT_NOT_VALID
&& eProt
== eBaseProt
) )
649 if ( eProt
== INET_PROT_NOT_VALID
)
650 aMatch
= SvtURLBox::ParseSmart( aText
, aBaseURL
, aWorkDir
);
655 INetURLObject
aURLObject( aMatch
);
656 String
aMainURL( aURLObject
.GetMainURL( INetURLObject::NO_DECODE
) );
657 if ( aMainURL
.Len() )
659 // if text input is a directory, it must be part of the match list! Until then it is scanned
660 if ( UCBContentHelper::IsFolder( aMainURL
) && aURLObject
.hasFinalSlash() )
661 Insert( aText
, aMatch
);
663 // otherwise the parent folder will be taken
664 aURLObject
.removeSegment();
666 // scan directory and insert all matches
667 ReadFolder( aURLObject
.GetMainURL( INetURLObject::NO_DECODE
), aMatch
, eProt
== INET_PROT_NOT_VALID
);
673 if ( bOnlyDirectories
)
674 // don't scan history picklist if only directories are allowed, picklist contains only files
678 int nCount
= aPickList
.Count();
680 INetURLObject aCurObj
;
681 String aEmpty
, aCurString
, aCurMainURL
;
683 aObj
.SetSmartProtocol( eSmartProt
== INET_PROT_NOT_VALID
? INET_PROT_HTTP
: eSmartProt
);
686 for( USHORT nPos
= 0; schedule() && nPos
< nCount
; nPos
++ )
688 aCurObj
.SetURL( *aPickList
.GetObject( nPos
) );
689 aCurObj
.SetSmartURL( aCurObj
.GetURLNoPass());
690 aCurMainURL
= aCurObj
.GetMainURL( INetURLObject::NO_DECODE
);
691 if( eProt
!= INET_PROT_NOT_VALID
&& aCurObj
.GetProtocol() != eProt
)
694 if( eSmartProt
!= INET_PROT_NOT_VALID
&& aCurObj
.GetProtocol() != eSmartProt
)
697 switch( aCurObj
.GetProtocol() )
700 case INET_PROT_HTTPS
:
703 if( eProt
== INET_PROT_NOT_VALID
&& !bFull
)
705 aObj
.SetSmartURL( aText
);
706 if( aObj
.GetURLPath().getLength() > 1 )
710 aCurString
= aCurMainURL
;
711 if( eProt
== INET_PROT_NOT_VALID
)
713 // try if text matches the scheme
714 String
aScheme( INetURLObject::GetScheme( aCurObj
.GetProtocol() ) );
715 if ( aText
.CompareTo( aScheme
, aText
.Len() ) == COMPARE_EQUAL
&& aText
.Len() < aScheme
.Len() )
718 aMatch
= aCurObj
.GetMainURL( INetURLObject::NO_DECODE
);
721 aCurObj
.SetMark( aEmpty
);
722 aCurObj
.SetParam( aEmpty
);
723 aCurObj
.SetURLPath( aEmpty
);
724 aMatch
= aCurObj
.GetMainURL( INetURLObject::NO_DECODE
);
727 Insert( aMatch
, aMatch
);
730 // now try smart matching
731 aCurString
.Erase( 0, aScheme
.Len() );
734 if( aText
.CompareTo( aCurString
, aText
.Len() )== COMPARE_EQUAL
)
737 aMatch
= aCurObj
.GetMainURL( INetURLObject::NO_DECODE
);
740 aCurObj
.SetMark( aEmpty
);
741 aCurObj
.SetParam( aEmpty
);
742 aCurObj
.SetURLPath( aEmpty
);
743 aMatch
= aCurObj
.GetMainURL( INetURLObject::NO_DECODE
);
746 String
aURL( aMatch
);
747 if( eProt
== INET_PROT_NOT_VALID
)
748 aMatch
.Erase( 0, sal::static_int_cast
< xub_StrLen
>(INetURLObject::GetScheme( aCurObj
.GetProtocol() ).getLength()) );
750 if( aText
.Len() < aMatch
.Len() )
751 Insert( aMatch
, aURL
);
762 if( aText
.CompareTo( aCurMainURL
, aText
.Len() ) == COMPARE_EQUAL
)
764 if( aText
.Len() < aCurMainURL
.Len() )
765 Insert( aCurMainURL
, aCurMainURL
);
783 //-------------------------------------------------------------------------
784 //-------------------------------------------------------------------------
785 //-------------------------------------------------------------------------
786 void SvtURLBox::TryAutoComplete( BOOL bForce
)
788 if( Application::AnyInput( INPUT_KEYBOARD
) ) return;
791 String aCurText
= GetText();
792 Selection
aSelection( GetSelection() );
793 if( aSelection
.Max() != aCurText
.Len() && !bForce
)
795 USHORT nLen
= (USHORT
)aSelection
.Min();
796 aCurText
.Erase( nLen
);
797 if( aCurText
.Len() && bIsAutoCompleteEnabled
)
804 pCtx
= new SvtMatchContext_Impl( this, aCurText
);
808 //-------------------------------------------------------------------------
809 SvtURLBox::SvtURLBox( Window
* pParent
, INetProtocol eSmart
)
810 : ComboBox( pParent
, WB_DROPDOWN
| WB_AUTOSIZE
| WB_AUTOHSCROLL
),
812 eSmartProtocol( eSmart
),
813 bAutoCompleteMode( FALSE
),
814 bOnlyDirectories( FALSE
),
815 bTryAutoComplete( FALSE
),
817 bHistoryDisabled( FALSE
),
818 bNoSelection( FALSE
),
819 bIsAutoCompleteEnabled( TRUE
)
823 if ( GetDesktopRectPixel().GetWidth() > 800 )
824 SetSizePixel( Size( 300, 240 ) );
826 SetSizePixel( Size( 225, 240 ) );
829 //-------------------------------------------------------------------------
830 SvtURLBox::SvtURLBox( Window
* pParent
, WinBits _nStyle
, INetProtocol eSmart
)
831 : ComboBox( pParent
, _nStyle
),
833 eSmartProtocol( eSmart
),
834 bAutoCompleteMode( FALSE
),
835 bOnlyDirectories( FALSE
),
836 bTryAutoComplete( FALSE
),
838 bHistoryDisabled( FALSE
),
839 bNoSelection( FALSE
),
840 bIsAutoCompleteEnabled( TRUE
)
845 //-------------------------------------------------------------------------
846 SvtURLBox::SvtURLBox( Window
* pParent
, const ResId
& _rResId
, INetProtocol eSmart
)
847 : ComboBox( pParent
, _rResId
),
849 eSmartProtocol( eSmart
),
850 bAutoCompleteMode( FALSE
),
851 bOnlyDirectories( FALSE
),
852 bTryAutoComplete( FALSE
),
854 bHistoryDisabled( FALSE
),
855 bNoSelection( FALSE
),
856 bIsAutoCompleteEnabled( TRUE
)
861 //-------------------------------------------------------------------------
862 void SvtURLBox::ImplInit()
864 pImp
= new SvtURLBox_Impl();
865 SetHelpId( SID_OPENURL
);
866 EnableAutocomplete( FALSE
);
870 GetSubEdit()->SetAutocompleteHdl( LINK( this, SvtURLBox
, AutoCompleteHdl_Impl
) );
871 UpdatePicklistForSmartProtocol_Impl();
874 //-------------------------------------------------------------------------
875 SvtURLBox::~SvtURLBox()
884 delete pImp
->pCompletions
;
888 //-------------------------------------------------------------------------
889 void SvtURLBox::UpdatePickList( )
897 String sText
= GetText();
898 if ( sText
.Len() && bIsAutoCompleteEnabled
)
899 pCtx
= new SvtMatchContext_Impl( this, sText
);
902 //-------------------------------------------------------------------------
903 void SvtURLBox::SetSmartProtocol( INetProtocol eProt
)
905 if ( eSmartProtocol
!= eProt
)
907 eSmartProtocol
= eProt
;
908 UpdatePicklistForSmartProtocol_Impl();
912 //-------------------------------------------------------------------------
913 void SvtURLBox::UpdatePicklistForSmartProtocol_Impl()
916 if ( !bHistoryDisabled
)
918 // read history pick list
919 Sequence
< Sequence
< PropertyValue
> > seqPicklist
= SvtHistoryOptions().GetList( eHISTORY
);
920 sal_uInt32 nCount
= seqPicklist
.getLength();
921 INetURLObject aCurObj
;
923 for( sal_uInt32 nItem
=0; nItem
< nCount
; nItem
++ )
925 Sequence
< PropertyValue
> seqPropertySet
= seqPicklist
[ nItem
];
929 sal_uInt32 nPropertyCount
= seqPropertySet
.getLength();
931 for( sal_uInt32 nProperty
=0; nProperty
< nPropertyCount
; nProperty
++ )
933 if( seqPropertySet
[nProperty
].Name
== HISTORY_PROPERTYNAME_URL
)
935 seqPropertySet
[nProperty
].Value
>>= sURL
;
936 aCurObj
.SetURL( sURL
);
938 if ( sURL
.getLength() && ( eSmartProtocol
!= INET_PROT_NOT_VALID
) )
940 if( aCurObj
.GetProtocol() != eSmartProtocol
)
944 String
aURL( aCurObj
.GetMainURL( INetURLObject::DECODE_WITH_CHARSET
) );
946 if ( aURL
.Len() && ( !pImp
->pUrlFilter
|| pImp
->pUrlFilter
->isUrlAllowed( aURL
) ) )
948 BOOL bFound
= (aURL
.GetChar(aURL
.Len()-1) == '/' );
951 String
aUpperURL( aURL
);
952 aUpperURL
.ToUpperAscii();
956 pImp
->m_aFilters
.begin(),
957 pImp
->m_aFilters
.end(),
958 FilterMatch( aUpperURL
) )
959 != pImp
->m_aFilters
.end());
964 if (::utl::LocalFileHelper::ConvertURLToSystemPath(aURL
,aFile
))
977 //-------------------------------------------------------------------------
978 BOOL
SvtURLBox::ProcessKey( const KeyCode
& rKey
)
980 // every key input stops the current matching thread
987 KeyCode
aCode( rKey
.GetCode() );
988 if ( aCode
== KEY_RETURN
&& GetText().Len() )
990 // wait for completion of matching thread
991 ::vos::OGuard
aGuard( SvtMatchContext_Impl::GetMutex() );
993 if ( bAutoCompleteMode
)
996 bAutoCompleteMode
= FALSE
;
997 Selection
aSelection( GetSelection() );
998 SetSelection( Selection( aSelection
.Min(), aSelection
.Min() ) );
999 if ( bOnlyDirectories
)
1002 UpdatePicklistForSmartProtocol_Impl();
1006 bCtrlClick
= rKey
.IsMod1();
1007 BOOL bHandled
= FALSE
;
1008 if ( GetOpenHdl().IsSet() )
1011 GetOpenHdl().Call(this);
1013 else if ( GetSelectHdl().IsSet() )
1016 GetSelectHdl().Call(this);
1024 else if ( aCode
== KEY_RETURN
&& !GetText().Len() && GetOpenHdl().IsSet() )
1027 bAutoCompleteMode
= FALSE
;
1028 GetOpenHdl().Call(this);
1031 else if( aCode
== KEY_ESCAPE
)
1033 Selection
aSelection( GetSelection() );
1034 if ( bAutoCompleteMode
|| aSelection
.Min() != aSelection
.Max() )
1036 SetSelection( Selection( aSelection
.Min(), aSelection
.Min() ) );
1037 if ( bOnlyDirectories
)
1040 UpdatePicklistForSmartProtocol_Impl();
1048 bAutoCompleteMode
= FALSE
;
1057 //-------------------------------------------------------------------------
1058 void SvtURLBox::Modify()
1063 //-------------------------------------------------------------------------
1064 long SvtURLBox::PreNotify( NotifyEvent
& rNEvt
)
1066 if( rNEvt
.GetWindow() == GetSubEdit() && rNEvt
.GetType() == EVENT_KEYINPUT
)
1069 const KeyEvent
& rEvent
= *rNEvt
.GetKeyEvent();
1070 const KeyCode
& rKey
= rEvent
.GetKeyCode();
1071 KeyCode
aCode( rKey
.GetCode() );
1072 if( ProcessKey( rKey
) )
1076 else if( ( aCode
== KEY_UP
|| aCode
== KEY_DOWN
) && !rKey
.IsMod2() )
1078 Selection
aSelection( GetSelection() );
1079 USHORT nLen
= (USHORT
)aSelection
.Min();
1080 GetSubEdit()->KeyInput( rEvent
);
1081 SetSelection( Selection( nLen
, GetText().Len() ) );
1085 if ( MatchesPlaceHolder( GetText() ) )
1087 // set the selection so a key stroke will overwrite
1088 // the placeholder rather than edit it
1089 SetSelection( Selection( 0, GetText().Len() ) );
1093 return ComboBox::PreNotify( rNEvt
);
1096 //-------------------------------------------------------------------------
1097 IMPL_LINK( SvtURLBox
, AutoCompleteHdl_Impl
, void*, EMPTYARG
)
1099 if ( GetSubEdit()->GetAutocompleteAction() == AUTOCOMPLETE_KEYINPUT
)
1101 TryAutoComplete( FALSE
);
1108 //-------------------------------------------------------------------------
1109 long SvtURLBox::Notify( NotifyEvent
&rEvt
)
1111 if ( EVENT_GETFOCUS
== rEvt
.GetType() )
1114 // pb: don't select automatically on unix #93251#
1115 SetSelection( Selection( 0, GetText().Len() ) );
1118 else if ( EVENT_LOSEFOCUS
== rEvt
.GetType() )
1120 if( !GetText().Len() )
1129 return ComboBox::Notify( rEvt
);
1132 //-------------------------------------------------------------------------
1133 void SvtURLBox::Select()
1139 //-------------------------------------------------------------------------
1140 void SvtURLBox::SetOnlyDirectories( BOOL bDir
)
1142 bOnlyDirectories
= bDir
;
1143 if ( bOnlyDirectories
)
1147 //-------------------------------------------------------------------------
1148 void SvtURLBox::SetNoURLSelection( BOOL bSet
)
1150 bNoSelection
= bSet
;
1153 //-------------------------------------------------------------------------
1154 String
SvtURLBox::GetURL()
1156 // wait for end of autocompletion
1157 ::vos::OGuard
aGuard( SvtMatchContext_Impl::GetMutex() );
1159 String
aText( GetText() );
1160 if ( MatchesPlaceHolder( aText
) )
1161 return aPlaceHolder
;
1162 // try to get the right case preserving URL from the list of URLs
1163 if ( pImp
->pCompletions
&& pImp
->pURLs
)
1165 for( USHORT nPos
=0; nPos
<pImp
->pCompletions
->Count(); nPos
++ )
1168 String
aTmp( *(*pImp
->pCompletions
)[ nPos
] );
1170 if( *(*pImp
->pCompletions
)[ nPos
] == aText
)
1171 return *(*pImp
->pURLs
)[nPos
];
1176 // erase trailing spaces on Windows since thay are invalid on this OS and
1177 // most of the time they are inserted by accident via copy / paste
1178 aText
.EraseTrailingChars();
1181 // #i9739# - 2002-12-03 - fs@openoffice.org
1184 INetURLObject
aObj( aText
);
1185 if( aText
.Search( '*' ) != STRING_NOTFOUND
|| aText
.Search( '?' ) != STRING_NOTFOUND
)
1187 // no autocompletion for wildcards
1188 INetURLObject aTempObj
;
1189 if ( eSmartProtocol
!= INET_PROT_NOT_VALID
)
1190 aTempObj
.SetSmartProtocol( eSmartProtocol
);
1191 if ( aTempObj
.SetSmartURL( aText
) )
1192 return aTempObj
.GetMainURL( INetURLObject::NO_DECODE
);
1197 if ( aObj
.GetProtocol() == INET_PROT_NOT_VALID
)
1199 String aName
= ParseSmart( aText
, aBaseURL
, SvtPathOptions().GetWorkPath() );
1200 aObj
.SetURL( aName
);
1201 ::rtl::OUString
aURL( aObj
.GetMainURL( INetURLObject::NO_DECODE
) );
1202 if ( !aURL
.getLength() )
1203 // aText itself is invalid, and even together with aBaseURL, it could not
1204 // made valid -> no chance
1207 bool bSlash
= aObj
.hasFinalSlash();
1209 static const rtl::OUString
aPropName(
1210 rtl::OUString::createFromAscii("CasePreservingURL"));
1212 rtl::OUString aFileURL
;
1215 UCBContentHelper::GetProperty(aURL
,aPropName
);
1216 sal_Bool success
= (aAny
>>= aFileURL
);
1220 INetURLObject(aFileURL
).getName(
1221 INetURLObject::LAST_SEGMENT
,
1223 INetURLObject::DECODE_WITH_CHARSET
));
1226 UCBContentHelper::GetTitle(aURL
,aTitle
);
1229 ( aTitle
.Len() > 1 ||
1230 (aTitle
.CompareToAscii("/") != 0 &&
1231 aTitle
.CompareToAscii(".") != 0) ) )
1233 aObj
.SetName( aTitle
);
1235 aObj
.setFinalSlash();
1240 return aObj
.GetMainURL( INetURLObject::NO_DECODE
);
1243 //-------------------------------------------------------------------------
1244 void SvtURLBox::DisableHistory()
1246 bHistoryDisabled
= TRUE
;
1247 UpdatePicklistForSmartProtocol_Impl();
1250 //-------------------------------------------------------------------------
1251 void SvtURLBox::SetBaseURL( const String
& rURL
)
1253 ::vos::OGuard
aGuard( SvtMatchContext_Impl::GetMutex() );
1255 // Reset match lists
1256 if ( pImp
->pCompletions
)
1257 pImp
->pCompletions
->Remove( 0, pImp
->pCompletions
->Count() );
1260 pImp
->pURLs
->Remove( 0, pImp
->pURLs
->Count() );
1265 //-------------------------------------------------------------------------
1266 /** Parse leading ~ for Unix systems,
1267 does nothing for Windows
1269 sal_Bool
SvtURLBox_Impl::TildeParsing(
1281 if( aText
.Search( '~' ) == 0 )
1284 sal_Bool bTrailingSlash
= sal_True
; // use trailing slash
1286 if( aText
.Len() == 1 || aText
.GetChar( 1 ) == '/' )
1288 // covers "~" or "~/..." cases
1289 const char* aHomeLocation
= getenv( "HOME" );
1290 if( !aHomeLocation
)
1293 aParseTilde
= String::CreateFromAscii( aHomeLocation
);
1295 // in case the whole path is just "~" then there should
1296 // be no trailing slash at the end
1297 if( aText
.Len() == 1 )
1298 bTrailingSlash
= sal_False
;
1302 // covers "~username" and "~username/..." cases
1303 xub_StrLen nNameEnd
= aText
.Search( '/' );
1304 String aUserName
= aText
.Copy( 1, ( nNameEnd
!= STRING_NOTFOUND
) ? nNameEnd
: ( aText
.Len() - 1 ) );
1306 struct passwd
* pPasswd
= NULL
;
1308 Sequence
< sal_Int8
> sBuf( 1024 );
1310 sal_Int32 nRes
= getpwnam_r( OUStringToOString( OUString( aUserName
), RTL_TEXTENCODING_ASCII_US
).getStr(),
1312 (char*)sBuf
.getArray(),
1315 if( !nRes
&& pPasswd
)
1316 aParseTilde
= String::CreateFromAscii( pPasswd
->pw_dir
);
1318 return sal_False
; // no such user
1320 pPasswd
= getpwnam( OUStringToOString( OUString( aUserName
), RTL_TEXTENCODING_ASCII_US
).getStr() );
1322 aParseTilde
= String::CreateFromAscii( pPasswd
->pw_dir
);
1324 return sal_False
; // no such user
1327 // in case the path is "~username" then there should
1328 // be no trailing slash at the end
1329 if( nNameEnd
== STRING_NOTFOUND
)
1330 bTrailingSlash
= sal_False
;
1333 if( !bTrailingSlash
)
1335 if( !aParseTilde
.Len() || aParseTilde
.EqualsAscii( "/" ) )
1337 // "/" path should be converted to "/."
1338 aParseTilde
= String::CreateFromAscii( "/." );
1342 // "blabla/" path should be converted to "blabla"
1343 aParseTilde
.EraseTrailingChars( '/' );
1348 if( aParseTilde
.GetChar( aParseTilde
.Len() - 1 ) != '/' )
1350 if( aText
.Len() > 2 )
1351 aParseTilde
+= aText
.Copy( 2 );
1354 aText
= aParseTilde
;
1355 aBaseURL
= String(); // tilde provide absolute path
1362 //-------------------------------------------------------------------------
1363 void SvtURLBox::SetUrlFilter( const IUrlFilter
* _pFilter
)
1365 pImp
->pUrlFilter
= _pFilter
;
1368 //-------------------------------------------------------------------------
1369 const IUrlFilter
* SvtURLBox::GetUrlFilter( ) const
1371 return pImp
->pUrlFilter
;
1373 // -----------------------------------------------------------------------------
1374 void SvtURLBox::SetFilter(const String
& _sFilter
)
1376 pImp
->m_aFilters
.clear();
1377 FilterMatch::createWildCardFilterList(_sFilter
,pImp
->m_aFilters
);