GPU-Calc: remove Alloc_Host_Ptr for clmem of NAN vector
[LibreOffice.git] / svtools / source / control / inettbc.cxx
blob4cbe2a68395ea96e2bb4feac3e3b813d2293d317
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #ifdef UNX
21 #include <pwd.h>
22 #include <sys/types.h>
23 #endif
25 #include <svtools/inettbc.hxx>
26 #include <com/sun/star/uno/Any.hxx>
27 #include <com/sun/star/uno/Reference.hxx>
28 #include <com/sun/star/beans/Property.hpp>
29 #include <com/sun/star/beans/PropertyValue.hpp>
30 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
31 #include <com/sun/star/sdbc/XResultSet.hpp>
32 #include <com/sun/star/sdbc/XRow.hpp>
33 #include <com/sun/star/task/XInteractionHandler.hpp>
34 #include <com/sun/star/ucb/NumberedSortingInfo.hpp>
35 #include <com/sun/star/ucb/UniversalContentBroker.hpp>
36 #include <com/sun/star/ucb/XAnyCompareFactory.hpp>
37 #include <com/sun/star/ucb/XCommandProcessor2.hpp>
38 #include <com/sun/star/ucb/XProgressHandler.hpp>
39 #include <com/sun/star/ucb/XContentAccess.hpp>
40 #include <com/sun/star/ucb/SortedDynamicResultSetFactory.hpp>
41 #include <comphelper/processfactory.hxx>
42 #include <comphelper/string.hxx>
43 #include <rtl/instance.hxx>
44 #include <salhelper/thread.hxx>
45 #include <osl/mutex.hxx>
46 #include <vcl/builder.hxx>
47 #include <vcl/svapp.hxx>
48 #include <vcl/toolbox.hxx>
49 #include <unotools/historyoptions.hxx>
50 #include <svl/eitem.hxx>
51 #include <svl/stritem.hxx>
52 #include <svl/itemset.hxx>
53 #include "svl/urihelper.hxx"
54 #include <unotools/pathoptions.hxx>
55 #include <ucbhelper/commandenvironment.hxx>
56 #include <ucbhelper/content.hxx>
57 #include <unotools/localfilehelper.hxx>
58 #include <unotools/ucbhelper.hxx>
59 #include "iodlg.hrc"
60 #include <svtools/asynclink.hxx>
61 #include <svl/urlfilter.hxx>
63 #include <vector>
64 #include <algorithm>
66 using namespace ::rtl;
67 using namespace ::ucbhelper;
68 using namespace ::utl;
69 using namespace ::com::sun::star;
70 using namespace ::com::sun::star::beans;
71 using namespace ::com::sun::star::lang;
72 using namespace ::com::sun::star::sdbc;
73 using namespace ::com::sun::star::task;
74 using namespace ::com::sun::star::ucb;
75 using namespace ::com::sun::star::uno;
77 class SvtURLBox_Impl
79 public:
80 std::vector<OUString> aURLs;
81 std::vector<OUString> aCompletions;
82 std::vector<WildCard> m_aFilters;
84 static sal_Bool TildeParsing( OUString& aText, OUString& aBaseUrl );
86 inline SvtURLBox_Impl( )
88 FilterMatch::createWildCardFilterList(OUString(),m_aFilters);
92 class SvtMatchContext_Impl: public salhelper::Thread
94 static ::osl::Mutex* pDirMutex;
96 std::vector<OUString> aPickList;
97 std::vector<OUString> aCompletions;
98 std::vector<OUString> aURLs;
99 svtools::AsynchronLink aLink;
100 OUString aBaseURL;
101 OUString aText;
102 SvtURLBox* pBox;
103 sal_Bool bOnlyDirectories;
104 sal_Bool bNoSelection;
106 osl::Mutex mutex_;
107 bool stopped_;
108 css::uno::Reference< css::ucb::XCommandProcessor > processor_;
109 sal_Int32 commandId_;
111 DECL_STATIC_LINK( SvtMatchContext_Impl, Select_Impl, void* );
113 virtual ~SvtMatchContext_Impl();
114 virtual void execute();
115 void doExecute();
116 void Insert( const OUString& rCompletion, const OUString& rURL, sal_Bool bForce = sal_False);
117 void ReadFolder( const OUString& rURL, const OUString& rMatch, sal_Bool bSmart );
118 void FillPicklist(std::vector<OUString>& rPickList);
120 public:
121 SvtMatchContext_Impl( SvtURLBox* pBoxP, const OUString& rText );
122 void Stop();
125 namespace
127 struct theSvtMatchContextMutex
128 : public rtl::Static< ::osl::Mutex, theSvtMatchContextMutex > {};
131 SvtMatchContext_Impl::SvtMatchContext_Impl(
132 SvtURLBox* pBoxP, const OUString& rText )
133 : Thread( "SvtMatchContext_Impl" )
134 , aLink( STATIC_LINK( this, SvtMatchContext_Impl, Select_Impl ) )
135 , aBaseURL( pBoxP->aBaseURL )
136 , aText( rText )
137 , pBox( pBoxP )
138 , bOnlyDirectories( pBoxP->bOnlyDirectories )
139 , bNoSelection( pBoxP->bNoSelection )
140 , stopped_(false)
141 , commandId_(0)
143 aLink.CreateMutex();
145 FillPicklist( aPickList );
148 SvtMatchContext_Impl::~SvtMatchContext_Impl()
150 aLink.ClearPendingCall();
153 void SvtMatchContext_Impl::FillPicklist(std::vector<OUString>& rPickList)
155 // Einlesung der Historypickliste
156 Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( eHISTORY );
157 sal_uInt32 nCount = seqPicklist.getLength();
159 for( sal_uInt32 nItem=0; nItem < nCount; nItem++ )
161 Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
163 OUString sTitle;
164 INetURLObject aURL;
166 sal_uInt32 nPropertyCount = seqPropertySet.getLength();
168 for( sal_uInt32 nProperty=0; nProperty < nPropertyCount; nProperty++ )
170 if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_TITLE )
172 seqPropertySet[nProperty].Value >>= sTitle;
173 aURL.SetURL( sTitle );
174 rPickList.insert(rPickList.begin() + nItem, aURL.GetMainURL(INetURLObject::DECODE_WITH_CHARSET));
175 break;
181 void SvtMatchContext_Impl::Stop()
183 css::uno::Reference< css::ucb::XCommandProcessor > proc;
184 sal_Int32 id(0);
186 osl::MutexGuard g(mutex_);
187 if (!stopped_) {
188 stopped_ = true;
189 proc = processor_;
190 id = commandId_;
193 if (proc.is()) {
194 proc->abort(id);
196 terminate();
199 void SvtMatchContext_Impl::execute( )
201 doExecute();
202 aLink.Call( this );
205 //-------------------------------------------------------------------------
206 // This method is called via AsynchronLink, so it has the SolarMutex and
207 // calling solar code ( VCL ... ) is safe. It is called when the thread is
208 // terminated ( finished work or stopped ). Cancelling the thread via
209 // Cancellable does not not discard the information gained so far, it
210 // inserts all collected completions into the listbox.
212 IMPL_STATIC_LINK( SvtMatchContext_Impl, Select_Impl, void*, )
214 // avoid recursion through cancel button
216 osl::MutexGuard g(pThis->mutex_);
217 if (pThis->stopped_) {
218 // Completion was stopped, no display:
219 return 0;
223 SvtURLBox* pBox = pThis->pBox;
224 pBox->bAutoCompleteMode = sal_True;
226 // did we filter completions which otherwise would have been valid?
227 // (to be filled below)
228 bool bValidCompletionsFiltered = false;
230 // insert all completed strings into the listbox
231 pBox->Clear();
233 for(std::vector<OUString>::iterator i = pThis->aCompletions.begin(); i != pThis->aCompletions.end(); ++i)
235 OUString sCompletion(*i);
237 // convert the file into an URL
238 OUString sURL( sCompletion );
239 ::utl::LocalFileHelper::ConvertPhysicalNameToURL( sCompletion, sURL );
240 // note: if this doesn't work, we're not interested in: we're checking the
241 // untouched sCompletion then
243 if ( !sURL.isEmpty() && !sURL.endsWith("/") )
245 OUString sUpperURL( sURL.toAsciiUpperCase() );
247 ::std::vector< WildCard >::const_iterator aMatchingFilter =
248 ::std::find_if(
249 pBox->pImp->m_aFilters.begin(),
250 pBox->pImp->m_aFilters.end(),
251 FilterMatch( sUpperURL )
253 if ( aMatchingFilter == pBox->pImp->m_aFilters.end() )
255 { // this URL is not allowed
256 bValidCompletionsFiltered = true;
257 continue;
261 pBox->InsertEntry( sCompletion );
264 if( !pThis->bNoSelection && !pThis->aCompletions.empty() && !bValidCompletionsFiltered )
266 // select the first one
267 OUString aTmp( pBox->GetEntry(0) );
268 pBox->SetText( aTmp );
269 pBox->SetSelection( Selection( pThis->aText.getLength(), aTmp.getLength() ) );
272 // transfer string lists to listbox and forget them
273 pBox->pImp->aURLs = pThis->aURLs;
274 pBox->pImp->aCompletions = pThis->aCompletions;
275 pThis->aURLs.clear();
276 pThis->aCompletions.clear();
278 // force listbox to resize ( it may be open )
279 pBox->Resize();
281 // the box has this control as a member so we have to set that member
282 // to zero before deleting ourself.
283 pBox->pCtx.clear();
285 return 0;
288 //-------------------------------------------------------------------------
289 void SvtMatchContext_Impl::Insert( const OUString& rCompletion,
290 const OUString& rURL,
291 sal_Bool bForce )
293 if( !bForce )
295 // avoid doubles
296 if(find(aCompletions.begin(), aCompletions.end(), OUString(rCompletion)) != aCompletions.end())
297 return;
300 aCompletions.push_back(rCompletion);
301 aURLs.push_back(rURL);
304 //-------------------------------------------------------------------------
305 void SvtMatchContext_Impl::ReadFolder( const OUString& rURL,
306 const OUString& rMatch,
307 sal_Bool bSmart )
309 // check folder to scan
310 if( !UCBContentHelper::IsFolder( rURL ) )
311 return;
313 sal_Bool bPureHomePath = sal_False;
314 #ifdef UNX
315 bPureHomePath = aText.startsWith( "~" ) && aText.indexOf( '/' ) == -1;
316 #endif
318 sal_Bool bExectMatch = bPureHomePath
319 || aText == "."
320 || aText.endsWith("/.")
321 || aText.endsWith("/..");
323 // for pure home paths ( ~username ) the '.' at the end of rMatch
324 // means that it poits to root catalog
325 // this is done only for file contents since home paths parsing is useful only for them
326 if ( bPureHomePath && rMatch == "file:///." )
328 // a home that refers to /
330 OUString aNewText( aText );
331 aNewText += "/";
332 Insert( aNewText, rURL, sal_True );
334 return;
337 // string to match with
338 INetURLObject aMatchObj( rMatch );
339 OUString aMatchName;
341 if ( rURL != aMatchObj.GetMainURL( INetURLObject::NO_DECODE ) )
343 aMatchName = aMatchObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
345 // matching is always done case insensitive, but completion will be case sensitive and case preserving
346 aMatchName = aMatchName.toAsciiLowerCase();
348 // if the matchstring ends with a slash, we must search for this also
349 if ( rMatch.endsWith("/") )
350 aMatchName += "/";
353 sal_Int32 nMatchLen = aMatchName.getLength();
355 INetURLObject aFolderObj( rURL );
356 DBG_ASSERT( aFolderObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" );
360 Content aCnt( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ),
361 new ::ucbhelper::CommandEnvironment( uno::Reference< XInteractionHandler >(),
362 uno::Reference< XProgressHandler >() ),
363 comphelper::getProcessComponentContext() );
364 uno::Reference< XResultSet > xResultSet;
365 Sequence< OUString > aProps(2);
366 OUString* pProps = aProps.getArray();
367 pProps[0] = "Title";
368 pProps[1] = "IsFolder";
372 uno::Reference< XDynamicResultSet > xDynResultSet;
373 ResultSetInclude eInclude = INCLUDE_FOLDERS_AND_DOCUMENTS;
374 if ( bOnlyDirectories )
375 eInclude = INCLUDE_FOLDERS_ONLY;
377 xDynResultSet = aCnt.createDynamicCursor( aProps, eInclude );
379 uno::Reference < XAnyCompareFactory > xCompare;
380 uno::Reference < XSortedDynamicResultSetFactory > xSRSFac =
381 SortedDynamicResultSetFactory::create( ::comphelper::getProcessComponentContext() );
383 Sequence< NumberedSortingInfo > aSortInfo( 2 );
384 NumberedSortingInfo* pInfo = aSortInfo.getArray();
385 pInfo[ 0 ].ColumnIndex = 2;
386 pInfo[ 0 ].Ascending = sal_False;
387 pInfo[ 1 ].ColumnIndex = 1;
388 pInfo[ 1 ].Ascending = sal_True;
390 uno::Reference< XDynamicResultSet > xDynamicResultSet;
391 xDynamicResultSet =
392 xSRSFac->createSortedDynamicResultSet( xDynResultSet, aSortInfo, xCompare );
394 if ( xDynamicResultSet.is() )
396 xResultSet = xDynamicResultSet->getStaticResultSet();
399 catch( ::com::sun::star::uno::Exception& ) {}
401 if ( xResultSet.is() )
403 uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
404 uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
408 while ( schedule() && xResultSet->next() )
410 OUString aURL = xContentAccess->queryContentIdentifierString();
411 OUString aTitle = xRow->getString(1);
412 sal_Bool bIsFolder = xRow->getBoolean(2);
414 // matching is always done case insensitive, but completion will be case sensitive and case preserving
415 aTitle = aTitle.toAsciiLowerCase();
417 if (
418 !nMatchLen ||
419 (bExectMatch && aMatchName == aTitle) ||
420 (!bExectMatch && aMatchName.compareTo(aTitle, nMatchLen) == 0)
423 // all names fit if matchstring is empty
424 INetURLObject aObj( aURL );
425 sal_Unicode aDelimiter = '/';
426 if ( bSmart )
427 // when parsing is done "smart", the delimiter must be "guessed"
428 aObj.getFSysPath( (INetURLObject::FSysStyle)(INetURLObject::FSYS_DETECT & ~INetURLObject::FSYS_VOS), &aDelimiter );
430 if ( bIsFolder )
431 aObj.setFinalSlash();
433 // get the last name of the URL
434 OUString aMatch = aObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
435 OUString aInput( aText );
436 if ( nMatchLen )
438 if (aText.endsWith(".") || bPureHomePath)
440 // if a "special folder" URL was typed, don't touch the user input
441 aMatch = aMatch.copy( nMatchLen );
443 else
445 // make the user input case preserving
446 DBG_ASSERT( aInput.getLength() >= nMatchLen, "Suspicious Matching!" );
447 aInput = aInput.copy( 0, aInput.getLength() - nMatchLen );
451 aInput += aMatch;
453 // folders should get a final slash automatically
454 if ( bIsFolder )
455 aInput += OUString(aDelimiter);
457 Insert( aInput, aObj.GetMainURL( INetURLObject::NO_DECODE ), sal_True );
461 catch( ::com::sun::star::uno::Exception& )
466 catch( ::com::sun::star::uno::Exception& )
471 //-------------------------------------------------------------------------
472 OUString SvtURLBox::ParseSmart( OUString aText, OUString aBaseURL, const OUString& aWorkDir )
474 OUString aMatch;
476 // parse ~ for Unix systems
477 // does nothing for Windows
478 if( !SvtURLBox_Impl::TildeParsing( aText, aBaseURL ) )
479 return OUString();
481 if( !aBaseURL.isEmpty() )
483 INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL );
485 // if a base URL is set the string may be parsed relative
486 if( aText.startsWith( "/" ) )
488 // text starting with slashes means absolute file URLs
489 OUString aTemp = INetURLObject::GetScheme( eBaseProt );
491 // file URL must be correctly encoded!
492 OUString aTextURL = INetURLObject::encode( aText, INetURLObject::PART_FPATH,
493 '%', INetURLObject::ENCODE_ALL );
494 aTemp += aTextURL;
496 INetURLObject aTmp( aTemp );
497 if ( !aTmp.HasError() && aTmp.GetProtocol() != INET_PROT_NOT_VALID )
498 aMatch = aTmp.GetMainURL( INetURLObject::NO_DECODE );
500 else
502 OUString aSmart( aText );
503 INetURLObject aObj( aBaseURL );
505 // HRO: I suppose this hack should only be done for Windows !!!???
506 #ifdef WNT
507 // HRO: INetURLObject::smatRel2Abs does not recognize '\\' as a relative path
508 // but in case of "\\\\" INetURLObject is right - this is an absolute path !
510 if( aText.startsWith("\\") && (aText.getLength() < 2 || aText[ 1 ] != '\\') )
512 // cut to first segment
513 OUString aTmp = INetURLObject::GetScheme( eBaseProt );
514 aTmp += "/";
515 aTmp += aObj.getName( 0, true, INetURLObject::DECODE_WITH_CHARSET );
516 aObj.SetURL( aTmp );
518 aSmart = aSmart.copy(1);
520 #endif
521 // base URL must be a directory !
522 aObj.setFinalSlash();
524 // take base URL and append current input
525 bool bWasAbsolute = sal_False;
526 #ifdef UNX
527 // don't support FSYS_MAC under Unix, because here ':' is a valid character for a filename
528 INetURLObject::FSysStyle eStyle = static_cast< INetURLObject::FSysStyle >( INetURLObject::FSYS_VOS | INetURLObject::FSYS_UNX | INetURLObject::FSYS_DOS );
529 // encode file URL correctly
530 aSmart = INetURLObject::encode( aSmart, INetURLObject::PART_FPATH, '%', INetURLObject::ENCODE_ALL );
531 INetURLObject aTmp( aObj.smartRel2Abs(
532 aSmart, bWasAbsolute, false, INetURLObject::WAS_ENCODED, RTL_TEXTENCODING_UTF8, false, eStyle ) );
533 #else
534 INetURLObject aTmp( aObj.smartRel2Abs( aSmart, bWasAbsolute ) );
535 #endif
537 if ( aText.endsWith(".") )
538 // INetURLObject appends a final slash for the directories "." and "..", this is a bug!
539 // Remove it as a workaround
540 aTmp.removeFinalSlash();
541 if ( !aTmp.HasError() && aTmp.GetProtocol() != INET_PROT_NOT_VALID )
542 aMatch = aTmp.GetMainURL( INetURLObject::NO_DECODE );
545 else
547 OUString aTmpMatch;
548 ::utl::LocalFileHelper::ConvertSystemPathToURL( aText, aWorkDir, aTmpMatch );
549 aMatch = aTmpMatch;
552 return aMatch;
555 //-------------------------------------------------------------------------
556 void SvtMatchContext_Impl::doExecute()
558 ::osl::MutexGuard aGuard( theSvtMatchContextMutex::get() );
560 // have we been stopped while we were waiting for the mutex?
561 osl::MutexGuard g(mutex_);
562 if (stopped_) {
563 return;
567 // Reset match lists
568 aCompletions.clear();
569 aURLs.clear();
571 // check for input
572 sal_uInt16 nTextLen = aText.getLength();
573 if ( !nTextLen )
574 return;
576 if( aText.indexOf( '*' ) != -1 || aText.indexOf( '?' ) != -1 )
577 // no autocompletion for wildcards
578 return;
580 OUString aMatch;
581 OUString aWorkDir( SvtPathOptions().GetWorkPath() );
582 INetProtocol eProt = INetURLObject::CompareProtocolScheme( aText );
583 INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL );
584 if ( aBaseURL.isEmpty() )
585 eBaseProt = INetURLObject::CompareProtocolScheme( aWorkDir );
586 INetProtocol eSmartProt = pBox->GetSmartProtocol();
588 // if the user input is a valid URL, go on with it
589 // otherwise it could be parsed smart with a predefined smart protocol
590 // ( or if this is not set with the protocol of a predefined base URL )
591 if( eProt == INET_PROT_NOT_VALID || eProt == eSmartProt || (eSmartProt == INET_PROT_NOT_VALID && eProt == eBaseProt) )
593 // not stopped yet ?
594 if( schedule() )
596 if ( eProt == INET_PROT_NOT_VALID )
597 aMatch = SvtURLBox::ParseSmart( aText, aBaseURL, aWorkDir );
598 else
599 aMatch = aText;
600 if ( !aMatch.isEmpty() )
602 INetURLObject aURLObject( aMatch );
603 OUString aMainURL( aURLObject.GetMainURL( INetURLObject::NO_DECODE ) );
604 // Disable autocompletion for anything but the (local) file
605 // system (for which access is hopefully fast), as the logic of
606 // how SvtMatchContext_Impl is used requires this code to run to
607 // completion before further user input is processed, and even
608 // SvtMatchContext_Impl::Stop does not guarantee a speedy
609 // return:
610 if ( !aMainURL.isEmpty()
611 && aURLObject.GetProtocol() == INET_PROT_FILE )
613 // if text input is a directory, it must be part of the match list! Until then it is scanned
614 bool folder = false;
615 if (aURLObject.hasFinalSlash()) {
616 try {
617 css::uno::Reference< css::uno::XComponentContext >
618 ctx(comphelper::getProcessComponentContext());
619 css::uno::Reference<
620 css::ucb::XUniversalContentBroker > ucb(
621 css::ucb::UniversalContentBroker::create(
622 ctx));
623 css::uno::Sequence< css::beans::Property > prop(1);
624 prop[0].Name = "IsFolder";
625 prop[0].Handle = -1;
626 prop[0].Type = cppu::UnoType< bool >::get();
627 css::uno::Any res;
628 css::uno::Reference< css::ucb::XCommandProcessor >
629 proc(
630 ucb->queryContent(
631 ucb->createContentIdentifier(aMainURL)),
632 css::uno::UNO_QUERY_THROW);
633 css::uno::Reference< css::ucb::XCommandProcessor2 >
634 proc2(proc, css::uno::UNO_QUERY);
635 sal_Int32 id = proc->createCommandIdentifier();
636 try {
638 osl::MutexGuard g(mutex_);
639 processor_ = proc;
640 commandId_ = id;
642 res = proc->execute(
643 css::ucb::Command(
644 "getPropertyValues", -1,
645 css::uno::makeAny(prop)),
647 css::uno::Reference<
648 css::ucb::XCommandEnvironment >());
649 } catch (...) {
650 if (proc2.is()) {
651 try {
652 proc2->releaseCommandIdentifier(id);
653 } catch (css::uno::RuntimeException & e) {
654 SAL_WARN(
655 "svtools.control",
656 "ignoring UNO RuntimeException "
657 << e.Message);
660 throw;
662 if (proc2.is()) {
663 proc2->releaseCommandIdentifier(id);
666 osl::MutexGuard g(mutex_);
667 processor_.clear();
668 // At least the neon-based WebDAV UCP does not
669 // properly support aborting commands, so return
670 // anyway now if an abort request had been
671 // ignored and the command execution only
672 // returned "successfully" after some timeout:
673 if (stopped_) {
674 return;
677 css::uno::Reference< css::sdbc::XRow > row(
678 res, css::uno::UNO_QUERY_THROW);
679 folder = row->getBoolean(1) && !row->wasNull();
680 } catch (css::uno::Exception & e) {
681 SAL_WARN(
682 "svtools.control",
683 "ignoring UNO Exception " << typeid(*&e).name()
684 << ": " << e.Message);
685 return;
688 if ( folder )
689 Insert( aText, aMatch );
690 else
691 // otherwise the parent folder will be taken
692 aURLObject.removeSegment();
694 // scan directory and insert all matches
695 ReadFolder( aURLObject.GetMainURL( INetURLObject::NO_DECODE ), aMatch, eProt == INET_PROT_NOT_VALID );
701 if ( bOnlyDirectories )
702 // don't scan history picklist if only directories are allowed, picklist contains only files
703 return;
705 sal_Bool bFull = sal_False;
707 INetURLObject aCurObj;
708 OUString aEmpty, aCurString, aCurMainURL;
709 INetURLObject aObj;
710 aObj.SetSmartProtocol( eSmartProt == INET_PROT_NOT_VALID ? INET_PROT_HTTP : eSmartProt );
711 for( ;; )
713 for(std::vector<OUString>::iterator i = aPickList.begin(); schedule() && i != aPickList.end(); ++i)
715 aCurObj.SetURL(*i);
716 aCurObj.SetSmartURL( aCurObj.GetURLNoPass());
717 aCurMainURL = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
719 if( eProt != INET_PROT_NOT_VALID && aCurObj.GetProtocol() != eProt )
720 continue;
722 if( eSmartProt != INET_PROT_NOT_VALID && aCurObj.GetProtocol() != eSmartProt )
723 continue;
725 switch( aCurObj.GetProtocol() )
727 case INET_PROT_HTTP:
728 case INET_PROT_HTTPS:
729 case INET_PROT_FTP:
731 if( eProt == INET_PROT_NOT_VALID && !bFull )
733 aObj.SetSmartURL( aText );
734 if( aObj.GetURLPath().getLength() > 1 )
735 continue;
738 aCurString = aCurMainURL;
739 if( eProt == INET_PROT_NOT_VALID )
741 // try if text matches the scheme
742 OUString aScheme( INetURLObject::GetScheme( aCurObj.GetProtocol() ) );
743 if ( aScheme.startsWithIgnoreAsciiCase( aText ) && aText.getLength() < aScheme.getLength() )
745 if( bFull )
746 aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
747 else
749 aCurObj.SetMark( aEmpty );
750 aCurObj.SetParam( aEmpty );
751 aCurObj.SetURLPath( aEmpty );
752 aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
755 Insert( aMatch, aMatch );
758 // now try smart matching
759 aCurString = aCurString.copy( aScheme.getLength() );
762 if( aCurString.startsWithIgnoreAsciiCase( aText ) )
764 if( bFull )
765 aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
766 else
768 aCurObj.SetMark( aEmpty );
769 aCurObj.SetParam( aEmpty );
770 aCurObj.SetURLPath( aEmpty );
771 aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
774 OUString aURL( aMatch );
775 if( eProt == INET_PROT_NOT_VALID )
776 aMatch = aMatch.copy( INetURLObject::GetScheme( aCurObj.GetProtocol() ).getLength() );
778 if( aText.getLength() < aMatch.getLength() )
779 Insert( aMatch, aURL );
781 continue;
783 break;
785 default:
787 if( bFull )
788 continue;
790 if( aCurMainURL.startsWith(aText) )
792 if( aText.getLength() < aCurMainURL.getLength() )
793 Insert( aCurMainURL, aCurMainURL );
795 continue;
797 break;
802 if( !bFull )
803 bFull = sal_True;
804 else
805 break;
808 return;
811 void SvtURLBox::TryAutoComplete()
813 if( Application::AnyInput( VCL_INPUT_KEYBOARD ) ) return;
815 OUString aCurText = GetText();
816 Selection aSelection( GetSelection() );
817 if( aSelection.Max() != aCurText.getLength() )
818 return;
819 sal_uInt16 nLen = (sal_uInt16)aSelection.Min();
820 aCurText = aCurText.copy( 0, nLen );
821 if( !aCurText.isEmpty() && bIsAutoCompleteEnabled )
823 if ( pCtx.is() )
825 pCtx->Stop();
826 pCtx->join();
827 pCtx.clear();
829 pCtx = new SvtMatchContext_Impl( this, aCurText );
830 pCtx->launch();
834 //-------------------------------------------------------------------------
835 SvtURLBox::SvtURLBox( Window* pParent, INetProtocol eSmart, bool bSetDefaultHelpID )
836 : ComboBox( pParent , WB_DROPDOWN | WB_AUTOSIZE | WB_AUTOHSCROLL ),
837 eSmartProtocol( eSmart ),
838 bAutoCompleteMode( sal_False ),
839 bOnlyDirectories( sal_False ),
840 bCtrlClick( sal_False ),
841 bHistoryDisabled( sal_False ),
842 bNoSelection( sal_False ),
843 bIsAutoCompleteEnabled( sal_True )
845 Init(bSetDefaultHelpID);
847 if ( GetDesktopRectPixel().GetWidth() > 800 )
848 SetSizePixel( Size( 300, 240 ) );
849 else
850 SetSizePixel( Size( 225, 240 ) );
853 //-------------------------------------------------------------------------
854 SvtURLBox::SvtURLBox( Window* pParent, WinBits _nStyle, INetProtocol eSmart,
855 bool bSetDefaultHelpID )
856 : ComboBox( pParent, _nStyle ),
857 eSmartProtocol( eSmart ),
858 bAutoCompleteMode( sal_False ),
859 bOnlyDirectories( sal_False ),
860 bCtrlClick( sal_False ),
861 bHistoryDisabled( sal_False ),
862 bNoSelection( sal_False ),
863 bIsAutoCompleteEnabled( sal_True )
865 Init(bSetDefaultHelpID);
868 extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeSvtURLBox(Window *pParent, VclBuilder::stringmap &)
870 WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP|
871 WB_DROPDOWN|WB_AUTOSIZE|WB_AUTOHSCROLL;
872 SvtURLBox* pListBox = new SvtURLBox(pParent, nWinBits, INET_PROT_NOT_VALID, false);
873 pListBox->EnableAutoSize(true);
874 return pListBox;
877 //-------------------------------------------------------------------------
878 SvtURLBox::SvtURLBox( Window* pParent, const ResId& _rResId, INetProtocol eSmart,
879 bool bSetDefaultHelpID )
880 : ComboBox( pParent , _rResId ),
881 eSmartProtocol( eSmart ),
882 bAutoCompleteMode( sal_False ),
883 bOnlyDirectories( sal_False ),
884 bCtrlClick( sal_False ),
885 bHistoryDisabled( sal_False ),
886 bNoSelection( sal_False ),
887 bIsAutoCompleteEnabled( sal_True )
889 Init(bSetDefaultHelpID);
892 void SvtURLBox::Init(bool bSetDefaultHelpID)
894 pImp = new SvtURLBox_Impl();
896 if (bSetDefaultHelpID && GetHelpId().isEmpty())
897 SetHelpId( ".uno:OpenURL" );
898 EnableAutocomplete( sal_False );
900 SetText( OUString() );
902 GetSubEdit()->SetAutocompleteHdl( LINK( this, SvtURLBox, AutoCompleteHdl_Impl ) );
903 UpdatePicklistForSmartProtocol_Impl();
905 EnableAutoSize(GetStyle() & WB_AUTOSIZE);
908 SvtURLBox::~SvtURLBox()
910 if( pCtx.is() )
912 pCtx->Stop();
913 pCtx->join();
916 delete pImp;
919 void SvtURLBox::UpdatePickList( )
921 if( pCtx.is() )
923 pCtx->Stop();
924 pCtx->join();
925 pCtx.clear();
928 OUString sText = GetText();
929 if ( !sText.isEmpty() && bIsAutoCompleteEnabled )
931 pCtx = new SvtMatchContext_Impl( this, sText );
932 pCtx->launch();
936 void SvtURLBox::SetSmartProtocol( INetProtocol eProt )
938 if ( eSmartProtocol != eProt )
940 eSmartProtocol = eProt;
941 UpdatePicklistForSmartProtocol_Impl();
945 void SvtURLBox::UpdatePicklistForSmartProtocol_Impl()
947 Clear();
948 if ( !bHistoryDisabled )
950 // read history pick list
951 Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( eHISTORY );
952 sal_uInt32 nCount = seqPicklist.getLength();
953 INetURLObject aCurObj;
955 for( sal_uInt32 nItem=0; nItem < nCount; nItem++ )
957 Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
959 OUString sURL;
961 sal_uInt32 nPropertyCount = seqPropertySet.getLength();
963 for( sal_uInt32 nProperty=0; nProperty < nPropertyCount; nProperty++ )
965 if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_URL )
967 seqPropertySet[nProperty].Value >>= sURL;
968 aCurObj.SetURL( sURL );
970 if ( !sURL.isEmpty() && ( eSmartProtocol != INET_PROT_NOT_VALID ) )
972 if( aCurObj.GetProtocol() != eSmartProtocol )
973 break;
976 OUString aURL( aCurObj.GetMainURL( INetURLObject::DECODE_WITH_CHARSET ) );
978 if ( !aURL.isEmpty() )
980 sal_Bool bFound = aURL.endsWith("/");
981 if ( !bFound )
983 OUString aUpperURL( aURL );
984 aUpperURL = aUpperURL.toAsciiUpperCase();
986 bFound
987 = (::std::find_if(
988 pImp->m_aFilters.begin(),
989 pImp->m_aFilters.end(),
990 FilterMatch( aUpperURL ) )
991 != pImp->m_aFilters.end());
993 if ( bFound )
995 OUString aFile;
996 if (::utl::LocalFileHelper::ConvertURLToSystemPath(aURL,aFile))
997 InsertEntry(aFile);
998 else
999 InsertEntry(aURL);
1002 break;
1009 //-------------------------------------------------------------------------
1010 sal_Bool SvtURLBox::ProcessKey( const KeyCode& rKey )
1012 // every key input stops the current matching thread
1013 if( pCtx.is() )
1015 pCtx->Stop();
1016 pCtx->join();
1017 pCtx.clear();
1020 KeyCode aCode( rKey.GetCode() );
1021 if ( aCode == KEY_RETURN && !GetText().isEmpty() )
1023 // wait for completion of matching thread
1024 ::osl::MutexGuard aGuard( theSvtMatchContextMutex::get() );
1026 if ( bAutoCompleteMode )
1028 // reset picklist
1029 bAutoCompleteMode = sal_False;
1030 Selection aSelection( GetSelection() );
1031 SetSelection( Selection( aSelection.Min(), aSelection.Min() ) );
1032 if ( bOnlyDirectories )
1033 Clear();
1034 else
1035 UpdatePicklistForSmartProtocol_Impl();
1036 Resize();
1039 bCtrlClick = rKey.IsMod1();
1040 sal_Bool bHandled = sal_False;
1041 if ( GetOpenHdl().IsSet() )
1043 bHandled = sal_True;
1044 GetOpenHdl().Call(this);
1046 else if ( GetSelectHdl().IsSet() )
1048 bHandled = sal_True;
1049 GetSelectHdl().Call(this);
1052 bCtrlClick = sal_False;
1054 ClearModifyFlag();
1055 return bHandled;
1057 else if ( aCode == KEY_RETURN && GetText().isEmpty() && GetOpenHdl().IsSet() )
1059 // for file dialog
1060 bAutoCompleteMode = sal_False;
1061 GetOpenHdl().Call(this);
1062 return sal_True;
1064 else if( aCode == KEY_ESCAPE )
1066 Selection aSelection( GetSelection() );
1067 if ( bAutoCompleteMode || aSelection.Min() != aSelection.Max() )
1069 SetSelection( Selection( aSelection.Min(), aSelection.Min() ) );
1070 if ( bOnlyDirectories )
1071 Clear();
1072 else
1073 UpdatePicklistForSmartProtocol_Impl();
1074 Resize();
1076 else
1078 return sal_False;
1081 bAutoCompleteMode = sal_False;
1082 return sal_True;
1084 else
1086 return sal_False;
1090 //-------------------------------------------------------------------------
1091 void SvtURLBox::Modify()
1093 ComboBox::Modify();
1096 //-------------------------------------------------------------------------
1097 long SvtURLBox::PreNotify( NotifyEvent& rNEvt )
1099 if( rNEvt.GetWindow() == GetSubEdit() && rNEvt.GetType() == EVENT_KEYINPUT )
1102 const KeyEvent& rEvent = *rNEvt.GetKeyEvent();
1103 const KeyCode& rKey = rEvent.GetKeyCode();
1104 KeyCode aCode( rKey.GetCode() );
1105 if( ProcessKey( rKey ) )
1107 return sal_True;
1109 else if( ( aCode == KEY_UP || aCode == KEY_DOWN ) && !rKey.IsMod2() )
1111 Selection aSelection( GetSelection() );
1112 sal_uInt16 nLen = (sal_uInt16)aSelection.Min();
1113 GetSubEdit()->KeyInput( rEvent );
1114 SetSelection( Selection( nLen, GetText().getLength() ) );
1115 return sal_True;
1118 if ( MatchesPlaceHolder( GetText() ) )
1120 // set the selection so a key stroke will overwrite
1121 // the placeholder rather than edit it
1122 SetSelection( Selection( 0, GetText().getLength() ) );
1126 return ComboBox::PreNotify( rNEvt );
1129 //-------------------------------------------------------------------------
1130 IMPL_LINK_NOARG(SvtURLBox, AutoCompleteHdl_Impl)
1132 if ( GetSubEdit()->GetAutocompleteAction() == AUTOCOMPLETE_KEYINPUT )
1134 TryAutoComplete();
1135 return 1L;
1138 return 0L;
1141 //-------------------------------------------------------------------------
1142 long SvtURLBox::Notify( NotifyEvent &rEvt )
1144 if ( EVENT_GETFOCUS == rEvt.GetType() )
1146 #ifndef UNX
1147 // pb: don't select automatically on unix #93251#
1148 SetSelection( Selection( 0, GetText().getLength() ) );
1149 #endif
1151 else if ( EVENT_LOSEFOCUS == rEvt.GetType() )
1153 if( GetText().isEmpty() )
1154 ClearModifyFlag();
1155 if ( pCtx.is() )
1157 pCtx->Stop();
1158 pCtx->join();
1159 pCtx.clear();
1163 return ComboBox::Notify( rEvt );
1166 //-------------------------------------------------------------------------
1167 void SvtURLBox::Select()
1169 ComboBox::Select();
1170 ClearModifyFlag();
1173 //-------------------------------------------------------------------------
1174 void SvtURLBox::SetOnlyDirectories( sal_Bool bDir )
1176 bOnlyDirectories = bDir;
1177 if ( bOnlyDirectories )
1178 Clear();
1181 //-------------------------------------------------------------------------
1182 void SvtURLBox::SetNoURLSelection( sal_Bool bSet )
1184 bNoSelection = bSet;
1187 //-------------------------------------------------------------------------
1188 OUString SvtURLBox::GetURL()
1190 // wait for end of autocompletion
1191 ::osl::MutexGuard aGuard( theSvtMatchContextMutex::get() );
1193 OUString aText( GetText() );
1194 if ( MatchesPlaceHolder( aText ) )
1195 return aPlaceHolder;
1197 // try to get the right case preserving URL from the list of URLs
1198 for(std::vector<OUString>::iterator i = pImp->aCompletions.begin(), j = pImp->aURLs.begin(); i != pImp->aCompletions.end() && j != pImp->aURLs.end(); ++i, ++j)
1200 if((*i).equals(aText))
1201 return *j;
1204 #ifdef WNT
1205 // erase trailing spaces on Windows since thay are invalid on this OS and
1206 // most of the time they are inserted by accident via copy / paste
1207 aText = comphelper::string::stripEnd(aText, ' ');
1208 if ( aText.isEmpty() )
1209 return aText;
1210 // #i9739#
1211 #endif
1213 INetURLObject aObj( aText );
1214 if( aText.indexOf( '*' ) != -1 || aText.indexOf( '?' ) != -1 )
1216 // no autocompletion for wildcards
1217 INetURLObject aTempObj;
1218 if ( eSmartProtocol != INET_PROT_NOT_VALID )
1219 aTempObj.SetSmartProtocol( eSmartProtocol );
1220 if ( aTempObj.SetSmartURL( aText ) )
1221 return aTempObj.GetMainURL( INetURLObject::NO_DECODE );
1222 else
1223 return aText;
1226 if ( aObj.GetProtocol() == INET_PROT_NOT_VALID )
1228 OUString aName = ParseSmart( aText, aBaseURL, SvtPathOptions().GetWorkPath() );
1229 aObj.SetURL(aName);
1230 OUString aURL( aObj.GetMainURL( INetURLObject::NO_DECODE ) );
1231 if ( aURL.isEmpty() )
1232 // aText itself is invalid, and even together with aBaseURL, it could not
1233 // made valid -> no chance
1234 return aText;
1236 bool bSlash = aObj.hasFinalSlash();
1238 const OUString aPropName("CasePreservingURL");
1240 OUString aFileURL;
1242 Any aAny = UCBContentHelper::GetProperty(aURL, aPropName);
1243 sal_Bool success = (aAny >>= aFileURL);
1244 OUString aTitle;
1245 if(success)
1246 aTitle = INetURLObject(aFileURL).getName(
1247 INetURLObject::LAST_SEGMENT,
1248 true,
1249 INetURLObject::DECODE_WITH_CHARSET );
1250 else
1251 success =
1252 UCBContentHelper::GetTitle(aURL,&aTitle);
1254 if( success && aTitle != "/" && aTitle != "." )
1256 aObj.SetName( aTitle );
1257 if ( bSlash )
1258 aObj.setFinalSlash();
1263 return aObj.GetMainURL( INetURLObject::NO_DECODE );
1266 void SvtURLBox::DisableHistory()
1268 bHistoryDisabled = sal_True;
1269 UpdatePicklistForSmartProtocol_Impl();
1272 void SvtURLBox::SetBaseURL( const OUString& rURL )
1274 ::osl::MutexGuard aGuard( theSvtMatchContextMutex::get() );
1276 // Reset match lists
1277 pImp->aCompletions.clear();
1278 pImp->aURLs.clear();
1280 aBaseURL = rURL;
1283 /** Parse leading ~ for Unix systems,
1284 does nothing for Windows
1286 sal_Bool SvtURLBox_Impl::TildeParsing(
1287 OUString&
1288 #ifdef UNX
1289 aText
1290 #endif
1291 , OUString&
1292 #ifdef UNX
1293 aBaseURL
1294 #endif
1297 #ifdef UNX
1298 if( aText.startsWith( "~" ) )
1300 OUString aParseTilde;
1301 sal_Bool bTrailingSlash = sal_True; // use trailing slash
1303 if( aText.getLength() == 1 || aText[ 1 ] == '/' )
1305 // covers "~" or "~/..." cases
1306 const char* aHomeLocation = getenv( "HOME" );
1307 if( !aHomeLocation )
1308 aHomeLocation = "";
1310 aParseTilde = OUString::createFromAscii(aHomeLocation);
1312 // in case the whole path is just "~" then there should
1313 // be no trailing slash at the end
1314 if( aText.getLength() == 1 )
1315 bTrailingSlash = sal_False;
1317 else
1319 // covers "~username" and "~username/..." cases
1320 sal_Int32 nNameEnd = aText.indexOf( '/' );
1321 OUString aUserName = aText.copy( 1, ( nNameEnd != -1 ) ? nNameEnd : ( aText.getLength() - 1 ) );
1323 struct passwd* pPasswd = NULL;
1324 #ifdef SOLARIS
1325 Sequence< sal_Int8 > sBuf( 1024 );
1326 struct passwd aTmp;
1327 sal_Int32 nRes = getpwnam_r( OUStringToOString( aUserName, RTL_TEXTENCODING_ASCII_US ).getStr(),
1328 &aTmp,
1329 (char*)sBuf.getArray(),
1330 1024,
1331 &pPasswd );
1332 if( !nRes && pPasswd )
1333 aParseTilde = OUString::createFromAscii(pPasswd->pw_dir);
1334 else
1335 return sal_False; // no such user
1336 #else
1337 pPasswd = getpwnam( OUStringToOString( aUserName, RTL_TEXTENCODING_ASCII_US ).getStr() );
1338 if( pPasswd )
1339 aParseTilde = OUString::createFromAscii(pPasswd->pw_dir);
1340 else
1341 return sal_False; // no such user
1342 #endif
1344 // in case the path is "~username" then there should
1345 // be no trailing slash at the end
1346 if( nNameEnd == -1 )
1347 bTrailingSlash = sal_False;
1350 if( !bTrailingSlash )
1352 if( aParseTilde.isEmpty() || aParseTilde == "/" )
1354 // "/" path should be converted to "/."
1355 aParseTilde = "/.";
1357 else
1359 // "blabla/" path should be converted to "blabla"
1360 aParseTilde = comphelper::string::stripEnd(aParseTilde, '/');
1363 else
1365 if( !aParseTilde.endsWith("/") )
1366 aParseTilde += "/";
1367 if( aText.getLength() > 2 )
1368 aParseTilde += aText.copy( 2 );
1371 aText = aParseTilde;
1372 aBaseURL = ""; // tilde provide absolute path
1374 #endif
1376 return sal_True;
1379 void SvtURLBox::SetFilter(const OUString& _sFilter)
1381 pImp->m_aFilters.clear();
1382 FilterMatch::createWildCardFilterList(_sFilter,pImp->m_aFilters);
1385 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */