update dev300-m58
[ooovba.git] / svtools / source / control / inettbc.cxx
blobf0e7899a6b85fc9ed131b9c32c1ae3e1bad2f84a
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: inettbc.cxx,v $
10 * $Revision: 1.12 $
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"
34 #ifdef UNX
35 #include <pwd.h>
36 #include <sys/types.h>
37 #endif
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>
50 #endif
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>
59 #endif
61 #include <vcl/toolbox.hxx>
62 #ifndef _VOS_THREAD_HXX //autogen
63 #include <vos/thread.hxx>
64 #endif
65 #ifndef _VOS_MUTEX_HXX //autogen
66 #include <vos/mutex.hxx>
67 #endif
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>
84 #include "iodlg.hrc"
85 #include <asynclink.hxx>
86 #include <svtools/urlfilter.hxx>
88 #include <vector>
89 #include <algorithm>
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 // -----------------------------------------------------------------------
105 class SvtURLBox_Impl
107 public:
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( )
116 :pURLs( NULL )
117 ,pCompletions( NULL )
118 ,pUrlFilter( 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;
133 String aBaseURL;
134 String aText;
135 SvtURLBox* pBox;
136 BOOL bStop;
137 BOOL bOnlyDirectories;
138 BOOL bNoSelection;
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 );
149 public:
150 static ::vos::OMutex* GetMutex();
152 SvtMatchContext_Impl( SvtURLBox* pBoxP, const String& rText );
153 ~SvtMatchContext_Impl();
154 void Stop();
157 ::vos::OMutex* SvtMatchContext_Impl::pDirMutex = 0;
159 ::vos::OMutex* SvtMatchContext_Impl::GetMutex()
161 ::vos::OGuard aGuard( ::vos::OMutex::getGlobalMutex() );
162 if( !pDirMutex )
163 pDirMutex = new ::vos::OMutex;
164 return pDirMutex;
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 )
172 , aText( rText )
173 , pBox( pBoxP )
174 , bStop( FALSE )
175 , bOnlyDirectories( pBoxP->bOnlyDirectories )
176 , bNoSelection( pBoxP->bNoSelection )
178 pURLs = new SvStringsDtor;
179 pCompletions = new SvStringsDtor;
181 aLink.CreateMutex();
183 FillPicklist( aPickList );
185 create();
188 //-------------------------------------------------------------------------
189 SvtMatchContext_Impl::~SvtMatchContext_Impl()
191 aLink.ClearPendingCall();
192 delete pURLs;
193 delete pCompletions;
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 ];
207 OUString sTitle;
208 INetURLObject aURL;
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 );
220 break;
226 //-------------------------------------------------------------------------
227 void SAL_CALL SvtMatchContext_Impl::Cancel()
229 // Cancel button pressed
230 terminate();
233 //-------------------------------------------------------------------------
234 void SvtMatchContext_Impl::Stop()
236 bStop = TRUE;
238 if( isRunning() )
239 terminate();
242 //-------------------------------------------------------------------------
243 void SvtMatchContext_Impl::onTerminated( )
245 aLink.Call( this );
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
258 if( pThis->bStop )
260 // completions was stopped, no display
261 delete pThis;
262 return 0;
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
273 pBox->Clear();
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;
290 continue;
293 if (( sURL.Len() > 0 ) && ( sURL.GetChar(sURL.Len()-1) != '/' ))
295 String sUpperURL( sURL );
296 sUpperURL.ToUpperAscii();
298 ::std::vector< WildCard >::const_iterator aMatchingFilter =
299 ::std::find_if(
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;
308 continue;
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;
328 pThis->pURLs = NULL;
329 pThis->pCompletions = NULL;
331 // force listbox to resize ( it may be open )
332 pBox->Resize();
334 // the box has this control as a member so we have to set that member
335 // to zero before deleting ourself.
336 pBox->pCtx = NULL;
337 delete pThis;
339 return 0;
342 //-------------------------------------------------------------------------
343 void SvtMatchContext_Impl::Insert( const String& rCompletion,
344 const String& rURL,
345 BOOL bForce )
347 if( !bForce )
349 // avoid doubles
350 for( USHORT nPos = pCompletions->Count(); nPos--; )
351 if( *(*pCompletions)[ nPos ] == rCompletion )
352 return;
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,
364 BOOL bSmart )
366 // check folder to scan
367 if( !UCBContentHelper::IsFolder( rURL ) )
368 return;
370 sal_Bool bPureHomePath = sal_False;
371 #ifdef UNX
372 bPureHomePath = aText.Search( '~' ) == 0 && aText.Search( '/' ) == STRING_NOTFOUND;
373 #endif
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 );
388 aNewText += '/';
389 Insert( aNewText, rURL, TRUE );
391 return;
394 // string to match with
395 INetURLObject aMatchObj( rMatch );
396 String aMatchName;
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) == '/' )
407 aMatchName += '/';
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;
449 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();
475 if (
476 !nMatchLen ||
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 = '/';
484 if ( bSmart )
485 // when parsing is done "smart", the delimiter must be "guessed"
486 aObj.getFSysPath( (INetURLObject::FSysStyle)(INetURLObject::FSYS_DETECT & ~INetURLObject::FSYS_VOS), &aDelimiter );
488 if ( bIsFolder )
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 );
494 if ( nMatchLen )
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 );
501 else
503 // make the user input case preserving
504 DBG_ASSERT( aInput.Len() >= nMatchLen, "Suspicious Matching!" );
505 aInput.Erase( aInput.Len() - nMatchLen );
509 aInput += aMatch;
511 // folders should get a final slash automatically
512 if ( bIsFolder )
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 )
532 String aMatch;
534 // parse ~ for Unix systems
535 // does nothing for Windows
536 if( !SvtURLBox_Impl::TildeParsing( aText, aBaseURL ) )
537 return String();
539 INetURLObject aURLObject;
540 if( aBaseURL.Len() )
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 );
553 aTemp += aTextURL;
555 INetURLObject aTmp( aTemp );
556 if ( !aTmp.HasError() && aTmp.GetProtocol() != INET_PROT_NOT_VALID )
557 aMatch = aTmp.GetMainURL( INetURLObject::NO_DECODE );
559 else
561 String aSmart( aText );
562 INetURLObject aObj( aBaseURL );
564 // HRO: I suppose this hack should only be done for Windows !!!???
565 #ifdef WNT
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 );
573 aTmp += '/';
574 aTmp += String(aObj.getName( 0, true, INetURLObject::DECODE_WITH_CHARSET ));
575 aObj.SetURL( aTmp );
577 aSmart.Erase(0,1);
579 #endif
580 // base URL must be a directory !
581 aObj.setFinalSlash();
583 // take base URL and append current input
584 bool bWasAbsolute = FALSE;
585 #ifdef UNX
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 ) );
592 #else
593 INetURLObject aTmp( aObj.smartRel2Abs( aSmart, bWasAbsolute ) );
594 #endif
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 );
604 else
606 ::utl::LocalFileHelper::ConvertSystemPathToURL( aText, aWorkDir, aMatch );
609 return aMatch;
612 //-------------------------------------------------------------------------
613 void SvtMatchContext_Impl::run()
615 ::vos::OGuard aGuard( GetMutex() );
616 if( bStop )
617 // have we been stopped while we were waiting for the mutex?
618 return;
620 // Reset match lists
621 pCompletions->Remove( 0, pCompletions->Count() );
622 pURLs->Remove( 0, pURLs->Count() );
624 // check for input
625 USHORT nTextLen = aText.Len();
626 if ( !nTextLen )
627 return;
629 if( aText.Search( '*' ) != STRING_NOTFOUND || aText.Search( '?' ) != STRING_NOTFOUND )
630 // no autocompletion for wildcards
631 return;
633 String aMatch;
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) )
646 // not stopped yet ?
647 if( schedule() )
649 if ( eProt == INET_PROT_NOT_VALID )
650 aMatch = SvtURLBox::ParseSmart( aText, aBaseURL, aWorkDir );
651 else
652 aMatch = aText;
653 if ( aMatch.Len() )
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 );
662 else
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
675 return;
677 BOOL bFull = FALSE;
678 int nCount = aPickList.Count();
680 INetURLObject aCurObj;
681 String aEmpty, aCurString, aCurMainURL;
682 INetURLObject aObj;
683 aObj.SetSmartProtocol( eSmartProt == INET_PROT_NOT_VALID ? INET_PROT_HTTP : eSmartProt );
684 for( ;; )
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 )
692 continue;
694 if( eSmartProt != INET_PROT_NOT_VALID && aCurObj.GetProtocol() != eSmartProt )
695 continue;
697 switch( aCurObj.GetProtocol() )
699 case INET_PROT_HTTP:
700 case INET_PROT_HTTPS:
701 case INET_PROT_FTP:
703 if( eProt == INET_PROT_NOT_VALID && !bFull )
705 aObj.SetSmartURL( aText );
706 if( aObj.GetURLPath().getLength() > 1 )
707 continue;
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() )
717 if( bFull )
718 aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
719 else
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 )
736 if( bFull )
737 aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
738 else
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 );
753 continue;
755 break;
757 default:
759 if( bFull )
760 continue;
762 if( aText.CompareTo( aCurMainURL, aText.Len() ) == COMPARE_EQUAL )
764 if( aText.Len() < aCurMainURL.Len() )
765 Insert( aCurMainURL, aCurMainURL );
767 continue;
769 break;
774 if( !bFull )
775 bFull = TRUE;
776 else
777 break;
780 return;
783 //-------------------------------------------------------------------------
784 //-------------------------------------------------------------------------
785 //-------------------------------------------------------------------------
786 void SvtURLBox::TryAutoComplete( BOOL bForce )
788 if( Application::AnyInput( INPUT_KEYBOARD ) ) return;
790 String aMatchString;
791 String aCurText = GetText();
792 Selection aSelection( GetSelection() );
793 if( aSelection.Max() != aCurText.Len() && !bForce )
794 return;
795 USHORT nLen = (USHORT)aSelection.Min();
796 aCurText.Erase( nLen );
797 if( aCurText.Len() && bIsAutoCompleteEnabled )
799 if ( pCtx )
801 pCtx->Stop();
802 pCtx = NULL;
804 pCtx = new SvtMatchContext_Impl( this, aCurText );
808 //-------------------------------------------------------------------------
809 SvtURLBox::SvtURLBox( Window* pParent, INetProtocol eSmart )
810 : ComboBox( pParent , WB_DROPDOWN | WB_AUTOSIZE | WB_AUTOHSCROLL ),
811 pCtx( 0 ),
812 eSmartProtocol( eSmart ),
813 bAutoCompleteMode( FALSE ),
814 bOnlyDirectories( FALSE ),
815 bTryAutoComplete( FALSE ),
816 bCtrlClick( FALSE ),
817 bHistoryDisabled( FALSE ),
818 bNoSelection( FALSE ),
819 bIsAutoCompleteEnabled( TRUE )
821 ImplInit();
823 if ( GetDesktopRectPixel().GetWidth() > 800 )
824 SetSizePixel( Size( 300, 240 ) );
825 else
826 SetSizePixel( Size( 225, 240 ) );
829 //-------------------------------------------------------------------------
830 SvtURLBox::SvtURLBox( Window* pParent, WinBits _nStyle, INetProtocol eSmart )
831 : ComboBox( pParent, _nStyle ),
832 pCtx( 0 ),
833 eSmartProtocol( eSmart ),
834 bAutoCompleteMode( FALSE ),
835 bOnlyDirectories( FALSE ),
836 bTryAutoComplete( FALSE ),
837 bCtrlClick( FALSE ),
838 bHistoryDisabled( FALSE ),
839 bNoSelection( FALSE ),
840 bIsAutoCompleteEnabled( TRUE )
842 ImplInit();
845 //-------------------------------------------------------------------------
846 SvtURLBox::SvtURLBox( Window* pParent, const ResId& _rResId, INetProtocol eSmart )
847 : ComboBox( pParent , _rResId ),
848 pCtx( 0 ),
849 eSmartProtocol( eSmart ),
850 bAutoCompleteMode( FALSE ),
851 bOnlyDirectories( FALSE ),
852 bTryAutoComplete( FALSE ),
853 bCtrlClick( FALSE ),
854 bHistoryDisabled( FALSE ),
855 bNoSelection( FALSE ),
856 bIsAutoCompleteEnabled( TRUE )
858 ImplInit();
861 //-------------------------------------------------------------------------
862 void SvtURLBox::ImplInit()
864 pImp = new SvtURLBox_Impl();
865 SetHelpId( SID_OPENURL );
866 EnableAutocomplete( FALSE );
868 SetText( String() );
870 GetSubEdit()->SetAutocompleteHdl( LINK( this, SvtURLBox, AutoCompleteHdl_Impl ) );
871 UpdatePicklistForSmartProtocol_Impl();
874 //-------------------------------------------------------------------------
875 SvtURLBox::~SvtURLBox()
877 if( pCtx )
879 pCtx->Stop();
880 pCtx = NULL;
883 delete pImp->pURLs;
884 delete pImp->pCompletions;
885 delete pImp;
888 //-------------------------------------------------------------------------
889 void SvtURLBox::UpdatePickList( )
891 if( pCtx )
893 pCtx->Stop();
894 pCtx = NULL;
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()
915 Clear();
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 ];
927 OUString sURL;
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 )
941 break;
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) == '/' );
949 if ( !bFound )
951 String aUpperURL( aURL );
952 aUpperURL.ToUpperAscii();
954 bFound
955 = (::std::find_if(
956 pImp->m_aFilters.begin(),
957 pImp->m_aFilters.end(),
958 FilterMatch( aUpperURL ) )
959 != pImp->m_aFilters.end());
961 if ( bFound )
963 String aFile;
964 if (::utl::LocalFileHelper::ConvertURLToSystemPath(aURL,aFile))
965 InsertEntry(aFile);
966 else
967 InsertEntry(aURL);
970 break;
977 //-------------------------------------------------------------------------
978 BOOL SvtURLBox::ProcessKey( const KeyCode& rKey )
980 // every key input stops the current matching thread
981 if( pCtx )
983 pCtx->Stop();
984 pCtx = NULL;
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 )
995 // reset picklist
996 bAutoCompleteMode = FALSE;
997 Selection aSelection( GetSelection() );
998 SetSelection( Selection( aSelection.Min(), aSelection.Min() ) );
999 if ( bOnlyDirectories )
1000 Clear();
1001 else
1002 UpdatePicklistForSmartProtocol_Impl();
1003 Resize();
1006 bCtrlClick = rKey.IsMod1();
1007 BOOL bHandled = FALSE;
1008 if ( GetOpenHdl().IsSet() )
1010 bHandled = TRUE;
1011 GetOpenHdl().Call(this);
1013 else if ( GetSelectHdl().IsSet() )
1015 bHandled = TRUE;
1016 GetSelectHdl().Call(this);
1019 bCtrlClick = FALSE;
1021 ClearModifyFlag();
1022 return bHandled;
1024 else if ( aCode == KEY_RETURN && !GetText().Len() && GetOpenHdl().IsSet() )
1026 // for file dialog
1027 bAutoCompleteMode = FALSE;
1028 GetOpenHdl().Call(this);
1029 return TRUE;
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 )
1038 Clear();
1039 else
1040 UpdatePicklistForSmartProtocol_Impl();
1041 Resize();
1043 else
1045 return FALSE;
1048 bAutoCompleteMode = FALSE;
1049 return TRUE;
1051 else
1053 return FALSE;
1057 //-------------------------------------------------------------------------
1058 void SvtURLBox::Modify()
1060 ComboBox::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 ) )
1074 return TRUE;
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() ) );
1082 return TRUE;
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 );
1102 return 1L;
1105 return 0L;
1108 //-------------------------------------------------------------------------
1109 long SvtURLBox::Notify( NotifyEvent &rEvt )
1111 if ( EVENT_GETFOCUS == rEvt.GetType() )
1113 #ifndef UNX
1114 // pb: don't select automatically on unix #93251#
1115 SetSelection( Selection( 0, GetText().Len() ) );
1116 #endif
1118 else if ( EVENT_LOSEFOCUS == rEvt.GetType() )
1120 if( !GetText().Len() )
1121 ClearModifyFlag();
1122 if ( pCtx )
1124 pCtx->Stop();
1125 pCtx = NULL;
1129 return ComboBox::Notify( rEvt );
1132 //-------------------------------------------------------------------------
1133 void SvtURLBox::Select()
1135 ComboBox::Select();
1136 ClearModifyFlag();
1139 //-------------------------------------------------------------------------
1140 void SvtURLBox::SetOnlyDirectories( BOOL bDir )
1142 bOnlyDirectories = bDir;
1143 if ( bOnlyDirectories )
1144 Clear();
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++ )
1167 #ifdef DBG_UTIL
1168 String aTmp( *(*pImp->pCompletions)[ nPos ] );
1169 #endif
1170 if( *(*pImp->pCompletions)[ nPos ] == aText )
1171 return *(*pImp->pURLs)[nPos];
1175 #ifdef WNT
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();
1179 if ( !aText.Len() )
1180 return aText;
1181 // #i9739# - 2002-12-03 - fs@openoffice.org
1182 #endif
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 );
1193 else
1194 return aText;
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
1205 return aText;
1207 bool bSlash = aObj.hasFinalSlash();
1209 static const rtl::OUString aPropName(
1210 rtl::OUString::createFromAscii("CasePreservingURL"));
1212 rtl::OUString aFileURL;
1214 Any aAny =
1215 UCBContentHelper::GetProperty(aURL,aPropName);
1216 sal_Bool success = (aAny >>= aFileURL);
1217 String aTitle;
1218 if(success)
1219 aTitle = String(
1220 INetURLObject(aFileURL).getName(
1221 INetURLObject::LAST_SEGMENT,
1222 true,
1223 INetURLObject::DECODE_WITH_CHARSET ));
1224 else
1225 success =
1226 UCBContentHelper::GetTitle(aURL,aTitle);
1228 if( success &&
1229 ( aTitle.Len() > 1 ||
1230 (aTitle.CompareToAscii("/") != 0 &&
1231 aTitle.CompareToAscii(".") != 0) ) )
1233 aObj.SetName( aTitle );
1234 if ( bSlash )
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() );
1259 if ( pImp->pURLs )
1260 pImp->pURLs->Remove( 0, pImp->pURLs->Count() );
1262 aBaseURL = rURL;
1265 //-------------------------------------------------------------------------
1266 /** Parse leading ~ for Unix systems,
1267 does nothing for Windows
1269 sal_Bool SvtURLBox_Impl::TildeParsing(
1270 String&
1271 #ifdef UNX
1272 aText
1273 #endif
1274 , String&
1275 #ifdef UNX
1276 aBaseURL
1277 #endif
1280 #ifdef UNX
1281 if( aText.Search( '~' ) == 0 )
1283 String aParseTilde;
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 )
1291 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;
1300 else
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;
1307 #ifdef SOLARIS
1308 Sequence< sal_Int8 > sBuf( 1024 );
1309 struct passwd aTmp;
1310 sal_Int32 nRes = getpwnam_r( OUStringToOString( OUString( aUserName ), RTL_TEXTENCODING_ASCII_US ).getStr(),
1311 &aTmp,
1312 (char*)sBuf.getArray(),
1313 1024,
1314 &pPasswd );
1315 if( !nRes && pPasswd )
1316 aParseTilde = String::CreateFromAscii( pPasswd->pw_dir );
1317 else
1318 return sal_False; // no such user
1319 #else
1320 pPasswd = getpwnam( OUStringToOString( OUString( aUserName ), RTL_TEXTENCODING_ASCII_US ).getStr() );
1321 if( pPasswd )
1322 aParseTilde = String::CreateFromAscii( pPasswd->pw_dir );
1323 else
1324 return sal_False; // no such user
1325 #endif
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( "/." );
1340 else
1342 // "blabla/" path should be converted to "blabla"
1343 aParseTilde.EraseTrailingChars( '/' );
1346 else
1348 if( aParseTilde.GetChar( aParseTilde.Len() - 1 ) != '/' )
1349 aParseTilde += '/';
1350 if( aText.Len() > 2 )
1351 aParseTilde += aText.Copy( 2 );
1354 aText = aParseTilde;
1355 aBaseURL = String(); // tilde provide absolute path
1357 #endif
1359 return sal_True;
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);