Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : *
9 : * This file incorporates work covered by the following license notice:
10 : *
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 .
18 : */
19 :
20 : #ifdef UNX
21 : #include <pwd.h>
22 : #include <sys/types.h>
23 : #endif
24 :
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>
62 :
63 : #include <vector>
64 : #include <algorithm>
65 :
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;
76 :
77 0 : class SvtURLBox_Impl
78 : {
79 : public:
80 : std::vector<OUString> aURLs;
81 : std::vector<OUString> aCompletions;
82 : std::vector<WildCard> m_aFilters;
83 :
84 : static bool TildeParsing( OUString& aText, OUString& aBaseUrl );
85 :
86 0 : inline SvtURLBox_Impl( )
87 0 : {
88 0 : FilterMatch::createWildCardFilterList(OUString(),m_aFilters);
89 0 : }
90 : };
91 :
92 : class SvtMatchContext_Impl: public salhelper::Thread
93 : {
94 : static ::osl::Mutex* pDirMutex;
95 :
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 : bool bOnlyDirectories;
104 : bool bNoSelection;
105 :
106 : osl::Mutex mutex_;
107 : bool stopped_;
108 : css::uno::Reference< css::ucb::XCommandProcessor > processor_;
109 : sal_Int32 commandId_;
110 :
111 : DECL_STATIC_LINK( SvtMatchContext_Impl, Select_Impl, void* );
112 :
113 : virtual ~SvtMatchContext_Impl();
114 : virtual void execute() SAL_OVERRIDE;
115 : void doExecute();
116 : void Insert( const OUString& rCompletion, const OUString& rURL, bool bForce = false);
117 : void ReadFolder( const OUString& rURL, const OUString& rMatch, bool bSmart );
118 : void FillPicklist(std::vector<OUString>& rPickList);
119 :
120 : public:
121 : SvtMatchContext_Impl( SvtURLBox* pBoxP, const OUString& rText );
122 : void Stop();
123 : };
124 :
125 : namespace
126 : {
127 : struct theSvtMatchContextMutex
128 : : public rtl::Static< ::osl::Mutex, theSvtMatchContextMutex > {};
129 : }
130 :
131 0 : 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 0 : , commandId_(0)
142 : {
143 0 : aLink.CreateMutex();
144 :
145 0 : FillPicklist( aPickList );
146 0 : }
147 :
148 0 : SvtMatchContext_Impl::~SvtMatchContext_Impl()
149 : {
150 0 : aLink.ClearPendingCall();
151 0 : }
152 :
153 0 : void SvtMatchContext_Impl::FillPicklist(std::vector<OUString>& rPickList)
154 : {
155 : // Einlesung der Historypickliste
156 0 : Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( eHISTORY );
157 0 : sal_uInt32 nCount = seqPicklist.getLength();
158 :
159 0 : for( sal_uInt32 nItem=0; nItem < nCount; nItem++ )
160 : {
161 0 : Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
162 :
163 0 : OUString sTitle;
164 0 : INetURLObject aURL;
165 :
166 0 : sal_uInt32 nPropertyCount = seqPropertySet.getLength();
167 :
168 0 : for( sal_uInt32 nProperty=0; nProperty < nPropertyCount; nProperty++ )
169 : {
170 0 : if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_TITLE )
171 : {
172 0 : seqPropertySet[nProperty].Value >>= sTitle;
173 0 : aURL.SetURL( sTitle );
174 0 : rPickList.insert(rPickList.begin() + nItem, aURL.GetMainURL(INetURLObject::DECODE_WITH_CHARSET));
175 0 : break;
176 : }
177 : }
178 0 : }
179 0 : }
180 :
181 0 : void SvtMatchContext_Impl::Stop()
182 : {
183 0 : css::uno::Reference< css::ucb::XCommandProcessor > proc;
184 0 : sal_Int32 id(0);
185 : {
186 0 : osl::MutexGuard g(mutex_);
187 0 : if (!stopped_) {
188 0 : stopped_ = true;
189 0 : proc = processor_;
190 0 : id = commandId_;
191 0 : }
192 : }
193 0 : if (proc.is()) {
194 0 : proc->abort(id);
195 : }
196 0 : terminate();
197 0 : }
198 :
199 0 : void SvtMatchContext_Impl::execute( )
200 : {
201 0 : doExecute();
202 0 : aLink.Call( this );
203 0 : }
204 :
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.
211 :
212 0 : IMPL_STATIC_LINK( SvtMatchContext_Impl, Select_Impl, void*, )
213 : {
214 : // avoid recursion through cancel button
215 : {
216 0 : osl::MutexGuard g(pThis->mutex_);
217 0 : if (pThis->stopped_) {
218 : // Completion was stopped, no display:
219 0 : return 0;
220 0 : }
221 : }
222 :
223 0 : SvtURLBox* pBox = pThis->pBox;
224 0 : pBox->bAutoCompleteMode = true;
225 :
226 : // did we filter completions which otherwise would have been valid?
227 : // (to be filled below)
228 0 : bool bValidCompletionsFiltered = false;
229 :
230 : // insert all completed strings into the listbox
231 0 : pBox->Clear();
232 :
233 0 : for(std::vector<OUString>::iterator i = pThis->aCompletions.begin(); i != pThis->aCompletions.end(); ++i)
234 : {
235 0 : OUString sCompletion(*i);
236 :
237 : // convert the file into an URL
238 0 : OUString sURL( sCompletion );
239 0 : ::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
242 :
243 0 : if ( !sURL.isEmpty() && !sURL.endsWith("/") )
244 : {
245 0 : OUString sUpperURL( sURL.toAsciiUpperCase() );
246 :
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 )
252 0 : );
253 0 : if ( aMatchingFilter == pBox->pImp->m_aFilters.end() )
254 :
255 : { // this URL is not allowed
256 0 : bValidCompletionsFiltered = true;
257 0 : continue;
258 0 : }
259 : }
260 :
261 0 : pBox->InsertEntry( sCompletion );
262 0 : }
263 :
264 0 : if( !pThis->bNoSelection && !pThis->aCompletions.empty() && !bValidCompletionsFiltered )
265 : {
266 : // select the first one
267 0 : OUString aTmp( pBox->GetEntry(0) );
268 0 : pBox->SetText( aTmp );
269 0 : pBox->SetSelection( Selection( pThis->aText.getLength(), aTmp.getLength() ) );
270 : }
271 :
272 : // transfer string lists to listbox and forget them
273 0 : pBox->pImp->aURLs = pThis->aURLs;
274 0 : pBox->pImp->aCompletions = pThis->aCompletions;
275 0 : pThis->aURLs.clear();
276 0 : pThis->aCompletions.clear();
277 :
278 : // force listbox to resize ( it may be open )
279 0 : pBox->Resize();
280 :
281 : // the box has this control as a member so we have to set that member
282 : // to zero before deleting ourself.
283 0 : pBox->pCtx.clear();
284 :
285 0 : return 0;
286 : }
287 :
288 :
289 0 : void SvtMatchContext_Impl::Insert( const OUString& rCompletion,
290 : const OUString& rURL,
291 : bool bForce )
292 : {
293 0 : if( !bForce )
294 : {
295 : // avoid doubles
296 0 : if(find(aCompletions.begin(), aCompletions.end(), OUString(rCompletion)) != aCompletions.end())
297 0 : return;
298 : }
299 :
300 0 : aCompletions.push_back(rCompletion);
301 0 : aURLs.push_back(rURL);
302 : }
303 :
304 :
305 0 : void SvtMatchContext_Impl::ReadFolder( const OUString& rURL,
306 : const OUString& rMatch,
307 : bool bSmart )
308 : {
309 : // check folder to scan
310 0 : if( !UCBContentHelper::IsFolder( rURL ) )
311 0 : return;
312 :
313 0 : bool bPureHomePath = false;
314 : #ifdef UNX
315 0 : bPureHomePath = aText.startsWith( "~" ) && aText.indexOf( '/' ) == -1;
316 : #endif
317 :
318 : bool bExectMatch = bPureHomePath
319 0 : || aText == "."
320 0 : || aText.endsWith("/.")
321 0 : || aText.endsWith("/..");
322 :
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 0 : if ( bPureHomePath && rMatch == "file:///." )
327 : {
328 : // a home that refers to /
329 :
330 0 : OUString aNewText( aText );
331 0 : aNewText += "/";
332 0 : Insert( aNewText, rURL, true );
333 :
334 0 : return;
335 : }
336 :
337 : // string to match with
338 0 : INetURLObject aMatchObj( rMatch );
339 0 : OUString aMatchName;
340 :
341 0 : if ( rURL != aMatchObj.GetMainURL( INetURLObject::NO_DECODE ) )
342 : {
343 0 : aMatchName = aMatchObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
344 :
345 : // matching is always done case insensitive, but completion will be case sensitive and case preserving
346 0 : aMatchName = aMatchName.toAsciiLowerCase();
347 :
348 : // if the matchstring ends with a slash, we must search for this also
349 0 : if ( rMatch.endsWith("/") )
350 0 : aMatchName += "/";
351 : }
352 :
353 0 : sal_Int32 nMatchLen = aMatchName.getLength();
354 :
355 0 : INetURLObject aFolderObj( rURL );
356 : DBG_ASSERT( aFolderObj.GetProtocol() != INET_PROT_NOT_VALID, "Invalid URL!" );
357 :
358 : try
359 : {
360 : Content aCnt( aFolderObj.GetMainURL( INetURLObject::NO_DECODE ),
361 : new ::ucbhelper::CommandEnvironment( uno::Reference< XInteractionHandler >(),
362 0 : uno::Reference< XProgressHandler >() ),
363 0 : comphelper::getProcessComponentContext() );
364 0 : uno::Reference< XResultSet > xResultSet;
365 0 : Sequence< OUString > aProps(2);
366 0 : OUString* pProps = aProps.getArray();
367 0 : pProps[0] = "Title";
368 0 : pProps[1] = "IsFolder";
369 :
370 : try
371 : {
372 0 : uno::Reference< XDynamicResultSet > xDynResultSet;
373 0 : ResultSetInclude eInclude = INCLUDE_FOLDERS_AND_DOCUMENTS;
374 0 : if ( bOnlyDirectories )
375 0 : eInclude = INCLUDE_FOLDERS_ONLY;
376 :
377 0 : xDynResultSet = aCnt.createDynamicCursor( aProps, eInclude );
378 :
379 0 : uno::Reference < XAnyCompareFactory > xCompare;
380 : uno::Reference < XSortedDynamicResultSetFactory > xSRSFac =
381 0 : SortedDynamicResultSetFactory::create( ::comphelper::getProcessComponentContext() );
382 :
383 0 : Sequence< NumberedSortingInfo > aSortInfo( 2 );
384 0 : NumberedSortingInfo* pInfo = aSortInfo.getArray();
385 0 : pInfo[ 0 ].ColumnIndex = 2;
386 0 : pInfo[ 0 ].Ascending = false;
387 0 : pInfo[ 1 ].ColumnIndex = 1;
388 0 : pInfo[ 1 ].Ascending = true;
389 :
390 0 : uno::Reference< XDynamicResultSet > xDynamicResultSet;
391 0 : xDynamicResultSet =
392 0 : xSRSFac->createSortedDynamicResultSet( xDynResultSet, aSortInfo, xCompare );
393 :
394 0 : if ( xDynamicResultSet.is() )
395 : {
396 0 : xResultSet = xDynamicResultSet->getStaticResultSet();
397 0 : }
398 : }
399 0 : catch( ::com::sun::star::uno::Exception& ) {}
400 :
401 0 : if ( xResultSet.is() )
402 : {
403 0 : uno::Reference< XRow > xRow( xResultSet, UNO_QUERY );
404 0 : uno::Reference< XContentAccess > xContentAccess( xResultSet, UNO_QUERY );
405 :
406 : try
407 : {
408 0 : while ( schedule() && xResultSet->next() )
409 : {
410 0 : OUString aURL = xContentAccess->queryContentIdentifierString();
411 0 : OUString aTitle = xRow->getString(1);
412 0 : bool bIsFolder = xRow->getBoolean(2);
413 :
414 : // matching is always done case insensitive, but completion will be case sensitive and case preserving
415 0 : aTitle = aTitle.toAsciiLowerCase();
416 :
417 0 : if (
418 0 : !nMatchLen ||
419 0 : (bExectMatch && aMatchName == aTitle) ||
420 0 : (!bExectMatch && aMatchName.compareTo(aTitle, nMatchLen) == 0)
421 : )
422 : {
423 : // all names fit if matchstring is empty
424 0 : INetURLObject aObj( aURL );
425 0 : sal_Unicode aDelimiter = '/';
426 0 : if ( bSmart )
427 : // when parsing is done "smart", the delimiter must be "guessed"
428 0 : aObj.getFSysPath( (INetURLObject::FSysStyle)(INetURLObject::FSYS_DETECT & ~INetURLObject::FSYS_VOS), &aDelimiter );
429 :
430 0 : if ( bIsFolder )
431 0 : aObj.setFinalSlash();
432 :
433 : // get the last name of the URL
434 0 : OUString aMatch = aObj.getName( INetURLObject::LAST_SEGMENT, true, INetURLObject::DECODE_WITH_CHARSET );
435 0 : OUString aInput( aText );
436 0 : if ( nMatchLen )
437 : {
438 0 : if (aText.endsWith(".") || bPureHomePath)
439 : {
440 : // if a "special folder" URL was typed, don't touch the user input
441 0 : aMatch = aMatch.copy( nMatchLen );
442 : }
443 : else
444 : {
445 : // make the user input case preserving
446 : DBG_ASSERT( aInput.getLength() >= nMatchLen, "Suspicious Matching!" );
447 0 : aInput = aInput.copy( 0, aInput.getLength() - nMatchLen );
448 : }
449 : }
450 :
451 0 : aInput += aMatch;
452 :
453 : // folders should get a final slash automatically
454 0 : if ( bIsFolder )
455 0 : aInput += OUString(aDelimiter);
456 :
457 0 : Insert( aInput, aObj.GetMainURL( INetURLObject::NO_DECODE ), true );
458 : }
459 0 : }
460 : }
461 0 : catch( ::com::sun::star::uno::Exception& )
462 : {
463 0 : }
464 0 : }
465 : }
466 0 : catch( ::com::sun::star::uno::Exception& )
467 : {
468 0 : }
469 : }
470 :
471 :
472 0 : OUString SvtURLBox::ParseSmart( const OUString& _aText, const OUString& _aBaseURL, const OUString& aWorkDir )
473 : {
474 0 : OUString aMatch;
475 0 : OUString aText = _aText;
476 0 : OUString aBaseURL = _aBaseURL;
477 :
478 : // parse ~ for Unix systems
479 : // does nothing for Windows
480 0 : if( !SvtURLBox_Impl::TildeParsing( aText, aBaseURL ) )
481 0 : return OUString();
482 :
483 0 : if( !aBaseURL.isEmpty() )
484 : {
485 0 : INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL );
486 :
487 : // if a base URL is set the string may be parsed relative
488 0 : if( aText.startsWith( "/" ) )
489 : {
490 : // text starting with slashes means absolute file URLs
491 0 : OUString aTemp = INetURLObject::GetScheme( eBaseProt );
492 :
493 : // file URL must be correctly encoded!
494 : OUString aTextURL = INetURLObject::encode( aText, INetURLObject::PART_FPATH,
495 0 : '%', INetURLObject::ENCODE_ALL );
496 0 : aTemp += aTextURL;
497 :
498 0 : INetURLObject aTmp( aTemp );
499 0 : if ( !aTmp.HasError() && aTmp.GetProtocol() != INET_PROT_NOT_VALID )
500 0 : aMatch = aTmp.GetMainURL( INetURLObject::NO_DECODE );
501 : }
502 : else
503 : {
504 0 : OUString aSmart( aText );
505 0 : INetURLObject aObj( aBaseURL );
506 :
507 : // HRO: I suppose this hack should only be done for Windows !!!???
508 : #ifdef WNT
509 : // HRO: INetURLObject::smatRel2Abs does not recognize '\\' as a relative path
510 : // but in case of "\\\\" INetURLObject is right - this is an absolute path !
511 :
512 : if( aText.startsWith("\\") && (aText.getLength() < 2 || aText[ 1 ] != '\\') )
513 : {
514 : // cut to first segment
515 : OUString aTmp = INetURLObject::GetScheme( eBaseProt );
516 : aTmp += "/";
517 : aTmp += aObj.getName( 0, true, INetURLObject::DECODE_WITH_CHARSET );
518 : aObj.SetURL( aTmp );
519 :
520 : aSmart = aSmart.copy(1);
521 : }
522 : #endif
523 : // base URL must be a directory !
524 0 : aObj.setFinalSlash();
525 :
526 : // take base URL and append current input
527 0 : bool bWasAbsolute = false;
528 : #ifdef UNX
529 0 : INetURLObject::FSysStyle eStyle = static_cast< INetURLObject::FSysStyle >( INetURLObject::FSYS_VOS | INetURLObject::FSYS_UNX | INetURLObject::FSYS_DOS );
530 : // encode file URL correctly
531 0 : aSmart = INetURLObject::encode( aSmart, INetURLObject::PART_FPATH, '%', INetURLObject::ENCODE_ALL );
532 : INetURLObject aTmp( aObj.smartRel2Abs(
533 0 : aSmart, bWasAbsolute, false, INetURLObject::WAS_ENCODED, RTL_TEXTENCODING_UTF8, false, eStyle ) );
534 : #else
535 : INetURLObject aTmp( aObj.smartRel2Abs( aSmart, bWasAbsolute ) );
536 : #endif
537 :
538 0 : if ( aText.endsWith(".") )
539 : // INetURLObject appends a final slash for the directories "." and "..", this is a bug!
540 : // Remove it as a workaround
541 0 : aTmp.removeFinalSlash();
542 0 : if ( !aTmp.HasError() && aTmp.GetProtocol() != INET_PROT_NOT_VALID )
543 0 : aMatch = aTmp.GetMainURL( INetURLObject::NO_DECODE );
544 : }
545 : }
546 : else
547 : {
548 0 : OUString aTmpMatch;
549 0 : ::utl::LocalFileHelper::ConvertSystemPathToURL( aText, aWorkDir, aTmpMatch );
550 0 : aMatch = aTmpMatch;
551 : }
552 :
553 0 : return aMatch;
554 : }
555 :
556 :
557 0 : void SvtMatchContext_Impl::doExecute()
558 : {
559 0 : ::osl::MutexGuard aGuard( theSvtMatchContextMutex::get() );
560 : {
561 : // have we been stopped while we were waiting for the mutex?
562 0 : osl::MutexGuard g(mutex_);
563 0 : if (stopped_) {
564 0 : return;
565 0 : }
566 : }
567 :
568 : // Reset match lists
569 0 : aCompletions.clear();
570 0 : aURLs.clear();
571 :
572 : // check for input
573 0 : sal_uInt16 nTextLen = aText.getLength();
574 0 : if ( !nTextLen )
575 0 : return;
576 :
577 0 : if( aText.indexOf( '*' ) != -1 || aText.indexOf( '?' ) != -1 )
578 : // no autocompletion for wildcards
579 0 : return;
580 :
581 0 : OUString aMatch;
582 0 : OUString aWorkDir( SvtPathOptions().GetWorkPath() );
583 0 : INetProtocol eProt = INetURLObject::CompareProtocolScheme( aText );
584 0 : INetProtocol eBaseProt = INetURLObject::CompareProtocolScheme( aBaseURL );
585 0 : if ( aBaseURL.isEmpty() )
586 0 : eBaseProt = INetURLObject::CompareProtocolScheme( aWorkDir );
587 0 : INetProtocol eSmartProt = pBox->GetSmartProtocol();
588 :
589 : // if the user input is a valid URL, go on with it
590 : // otherwise it could be parsed smart with a predefined smart protocol
591 : // ( or if this is not set with the protocol of a predefined base URL )
592 0 : if( eProt == INET_PROT_NOT_VALID || eProt == eSmartProt || (eSmartProt == INET_PROT_NOT_VALID && eProt == eBaseProt) )
593 : {
594 : // not stopped yet ?
595 0 : if( schedule() )
596 : {
597 0 : if ( eProt == INET_PROT_NOT_VALID )
598 0 : aMatch = SvtURLBox::ParseSmart( aText, aBaseURL, aWorkDir );
599 : else
600 0 : aMatch = aText;
601 0 : if ( !aMatch.isEmpty() )
602 : {
603 0 : INetURLObject aURLObject( aMatch );
604 0 : OUString aMainURL( aURLObject.GetMainURL( INetURLObject::NO_DECODE ) );
605 : // Disable autocompletion for anything but the (local) file
606 : // system (for which access is hopefully fast), as the logic of
607 : // how SvtMatchContext_Impl is used requires this code to run to
608 : // completion before further user input is processed, and even
609 : // SvtMatchContext_Impl::Stop does not guarantee a speedy
610 : // return:
611 0 : if ( !aMainURL.isEmpty()
612 0 : && aURLObject.GetProtocol() == INET_PROT_FILE )
613 : {
614 : // if text input is a directory, it must be part of the match list! Until then it is scanned
615 0 : bool folder = false;
616 0 : if (aURLObject.hasFinalSlash()) {
617 : try {
618 : css::uno::Reference< css::uno::XComponentContext >
619 0 : ctx(comphelper::getProcessComponentContext());
620 : css::uno::Reference<
621 : css::ucb::XUniversalContentBroker > ucb(
622 : css::ucb::UniversalContentBroker::create(
623 0 : ctx));
624 0 : css::uno::Sequence< css::beans::Property > prop(1);
625 0 : prop[0].Name = "IsFolder";
626 0 : prop[0].Handle = -1;
627 0 : prop[0].Type = cppu::UnoType< bool >::get();
628 0 : css::uno::Any res;
629 : css::uno::Reference< css::ucb::XCommandProcessor >
630 : proc(
631 0 : ucb->queryContent(
632 0 : ucb->createContentIdentifier(aMainURL)),
633 0 : css::uno::UNO_QUERY_THROW);
634 : css::uno::Reference< css::ucb::XCommandProcessor2 >
635 0 : proc2(proc, css::uno::UNO_QUERY);
636 0 : sal_Int32 id = proc->createCommandIdentifier();
637 : try {
638 : {
639 0 : osl::MutexGuard g(mutex_);
640 0 : processor_ = proc;
641 0 : commandId_ = id;
642 : }
643 0 : res = proc->execute(
644 : css::ucb::Command(
645 : "getPropertyValues", -1,
646 : css::uno::makeAny(prop)),
647 : id,
648 : css::uno::Reference<
649 0 : css::ucb::XCommandEnvironment >());
650 0 : } catch (...) {
651 0 : if (proc2.is()) {
652 : try {
653 0 : proc2->releaseCommandIdentifier(id);
654 0 : } catch (css::uno::RuntimeException & e) {
655 : SAL_WARN(
656 : "svtools.control",
657 : "ignoring UNO RuntimeException "
658 : << e.Message);
659 : }
660 : }
661 0 : throw;
662 : }
663 0 : if (proc2.is()) {
664 0 : proc2->releaseCommandIdentifier(id);
665 : }
666 : {
667 0 : osl::MutexGuard g(mutex_);
668 0 : processor_.clear();
669 : // At least the neon-based WebDAV UCP does not
670 : // properly support aborting commands, so return
671 : // anyway now if an abort request had been
672 : // ignored and the command execution only
673 : // returned "successfully" after some timeout:
674 0 : if (stopped_) {
675 0 : return;
676 0 : }
677 : }
678 : css::uno::Reference< css::sdbc::XRow > row(
679 0 : res, css::uno::UNO_QUERY_THROW);
680 0 : folder = row->getBoolean(1) && !row->wasNull();
681 0 : } catch (css::uno::Exception & e) {
682 : SAL_WARN(
683 : "svtools.control",
684 : "ignoring UNO Exception " << typeid(*&e).name()
685 : << ": " << e.Message);
686 0 : return;
687 : }
688 : }
689 0 : if ( folder )
690 0 : Insert( aText, aMatch );
691 : else
692 : // otherwise the parent folder will be taken
693 0 : aURLObject.removeSegment();
694 :
695 : // scan directory and insert all matches
696 0 : ReadFolder( aURLObject.GetMainURL( INetURLObject::NO_DECODE ), aMatch, eProt == INET_PROT_NOT_VALID );
697 0 : }
698 : }
699 : }
700 : }
701 :
702 0 : if ( bOnlyDirectories )
703 : // don't scan history picklist if only directories are allowed, picklist contains only files
704 0 : return;
705 :
706 0 : bool bFull = false;
707 :
708 0 : INetURLObject aCurObj;
709 0 : OUString aEmpty, aCurString, aCurMainURL;
710 0 : INetURLObject aObj;
711 0 : aObj.SetSmartProtocol( eSmartProt == INET_PROT_NOT_VALID ? INET_PROT_HTTP : eSmartProt );
712 : for( ;; )
713 : {
714 0 : for(std::vector<OUString>::iterator i = aPickList.begin(); schedule() && i != aPickList.end(); ++i)
715 : {
716 0 : aCurObj.SetURL(*i);
717 0 : aCurObj.SetSmartURL( aCurObj.GetURLNoPass());
718 0 : aCurMainURL = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
719 :
720 0 : if( eProt != INET_PROT_NOT_VALID && aCurObj.GetProtocol() != eProt )
721 0 : continue;
722 :
723 0 : if( eSmartProt != INET_PROT_NOT_VALID && aCurObj.GetProtocol() != eSmartProt )
724 0 : continue;
725 :
726 0 : switch( aCurObj.GetProtocol() )
727 : {
728 : case INET_PROT_HTTP:
729 : case INET_PROT_HTTPS:
730 : case INET_PROT_FTP:
731 : {
732 0 : if( eProt == INET_PROT_NOT_VALID && !bFull )
733 : {
734 0 : aObj.SetSmartURL( aText );
735 0 : if( aObj.GetURLPath().getLength() > 1 )
736 0 : continue;
737 : }
738 :
739 0 : aCurString = aCurMainURL;
740 0 : if( eProt == INET_PROT_NOT_VALID )
741 : {
742 : // try if text matches the scheme
743 0 : OUString aScheme( INetURLObject::GetScheme( aCurObj.GetProtocol() ) );
744 0 : if ( aScheme.startsWithIgnoreAsciiCase( aText ) && aText.getLength() < aScheme.getLength() )
745 : {
746 0 : if( bFull )
747 0 : aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
748 : else
749 : {
750 0 : aCurObj.SetMark( aEmpty );
751 0 : aCurObj.SetParam( aEmpty );
752 0 : aCurObj.SetURLPath( aEmpty );
753 0 : aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
754 : }
755 :
756 0 : Insert( aMatch, aMatch );
757 : }
758 :
759 : // now try smart matching
760 0 : aCurString = aCurString.copy( aScheme.getLength() );
761 : }
762 :
763 0 : if( aCurString.startsWithIgnoreAsciiCase( aText ) )
764 : {
765 0 : if( bFull )
766 0 : aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
767 : else
768 : {
769 0 : aCurObj.SetMark( aEmpty );
770 0 : aCurObj.SetParam( aEmpty );
771 0 : aCurObj.SetURLPath( aEmpty );
772 0 : aMatch = aCurObj.GetMainURL( INetURLObject::NO_DECODE );
773 : }
774 :
775 0 : OUString aURL( aMatch );
776 0 : if( eProt == INET_PROT_NOT_VALID )
777 0 : aMatch = aMatch.copy( INetURLObject::GetScheme( aCurObj.GetProtocol() ).getLength() );
778 :
779 0 : if( aText.getLength() < aMatch.getLength() )
780 0 : Insert( aMatch, aURL );
781 :
782 0 : continue;
783 : }
784 0 : break;
785 : }
786 : default:
787 : {
788 0 : if( bFull )
789 0 : continue;
790 :
791 0 : if( aCurMainURL.startsWith(aText) )
792 : {
793 0 : if( aText.getLength() < aCurMainURL.getLength() )
794 0 : Insert( aCurMainURL, aCurMainURL );
795 :
796 0 : continue;
797 : }
798 0 : break;
799 : }
800 : }
801 : }
802 :
803 0 : if( !bFull )
804 0 : bFull = true;
805 : else
806 0 : break;
807 0 : }
808 :
809 0 : return;
810 : }
811 :
812 0 : void SvtURLBox::TryAutoComplete()
813 : {
814 0 : if( Application::AnyInput( VCL_INPUT_KEYBOARD ) ) return;
815 :
816 0 : OUString aCurText = GetText();
817 0 : Selection aSelection( GetSelection() );
818 0 : if( aSelection.Max() != aCurText.getLength() )
819 0 : return;
820 0 : sal_uInt16 nLen = (sal_uInt16)aSelection.Min();
821 0 : aCurText = aCurText.copy( 0, nLen );
822 0 : if( !aCurText.isEmpty() && bIsAutoCompleteEnabled )
823 : {
824 0 : if ( pCtx.is() )
825 : {
826 0 : pCtx->Stop();
827 0 : pCtx->join();
828 0 : pCtx.clear();
829 : }
830 0 : pCtx = new SvtMatchContext_Impl( this, aCurText );
831 0 : pCtx->launch();
832 0 : }
833 : }
834 :
835 :
836 0 : SvtURLBox::SvtURLBox( Window* pParent, INetProtocol eSmart, bool bSetDefaultHelpID )
837 : : ComboBox( pParent , WB_DROPDOWN | WB_AUTOSIZE | WB_AUTOHSCROLL ),
838 : eSmartProtocol( eSmart ),
839 : bAutoCompleteMode( false ),
840 : bOnlyDirectories( false ),
841 : bCtrlClick( false ),
842 : bHistoryDisabled( false ),
843 : bNoSelection( false ),
844 0 : bIsAutoCompleteEnabled( true )
845 : {
846 0 : Init(bSetDefaultHelpID);
847 :
848 0 : if ( GetDesktopRectPixel().GetWidth() > 800 )
849 0 : SetSizePixel( Size( 300, 240 ) );
850 : else
851 0 : SetSizePixel( Size( 225, 240 ) );
852 0 : }
853 :
854 :
855 0 : SvtURLBox::SvtURLBox( Window* pParent, WinBits _nStyle, INetProtocol eSmart,
856 : bool bSetDefaultHelpID )
857 : : ComboBox( pParent, _nStyle ),
858 : eSmartProtocol( eSmart ),
859 : bAutoCompleteMode( false ),
860 : bOnlyDirectories( false ),
861 : bCtrlClick( false ),
862 : bHistoryDisabled( false ),
863 : bNoSelection( false ),
864 0 : bIsAutoCompleteEnabled( true )
865 : {
866 0 : Init(bSetDefaultHelpID);
867 0 : }
868 :
869 0 : extern "C" SAL_DLLPUBLIC_EXPORT Window* SAL_CALL makeSvtURLBox(Window *pParent, VclBuilder::stringmap &)
870 : {
871 : WinBits nWinBits = WB_LEFT|WB_VCENTER|WB_3DLOOK|WB_TABSTOP|
872 0 : WB_DROPDOWN|WB_AUTOSIZE|WB_AUTOHSCROLL;
873 0 : SvtURLBox* pListBox = new SvtURLBox(pParent, nWinBits, INET_PROT_NOT_VALID, false);
874 0 : pListBox->EnableAutoSize(true);
875 0 : return pListBox;
876 : }
877 :
878 :
879 0 : SvtURLBox::SvtURLBox( Window* pParent, const ResId& _rResId, INetProtocol eSmart,
880 : bool bSetDefaultHelpID )
881 : : ComboBox( pParent , _rResId ),
882 : eSmartProtocol( eSmart ),
883 : bAutoCompleteMode( false ),
884 : bOnlyDirectories( false ),
885 : bCtrlClick( false ),
886 : bHistoryDisabled( false ),
887 : bNoSelection( false ),
888 0 : bIsAutoCompleteEnabled( true )
889 : {
890 0 : Init(bSetDefaultHelpID);
891 0 : }
892 :
893 0 : void SvtURLBox::Init(bool bSetDefaultHelpID)
894 : {
895 0 : pImp = new SvtURLBox_Impl();
896 :
897 0 : if (bSetDefaultHelpID && GetHelpId().isEmpty())
898 0 : SetHelpId( ".uno:OpenURL" );
899 0 : EnableAutocomplete( false );
900 :
901 0 : SetText( OUString() );
902 :
903 0 : GetSubEdit()->SetAutocompleteHdl( LINK( this, SvtURLBox, AutoCompleteHdl_Impl ) );
904 0 : UpdatePicklistForSmartProtocol_Impl();
905 :
906 0 : EnableAutoSize(GetStyle() & WB_AUTOSIZE);
907 0 : }
908 :
909 0 : SvtURLBox::~SvtURLBox()
910 : {
911 0 : if( pCtx.is() )
912 : {
913 0 : pCtx->Stop();
914 0 : pCtx->join();
915 : }
916 :
917 0 : delete pImp;
918 0 : }
919 :
920 0 : void SvtURLBox::UpdatePickList( )
921 : {
922 0 : if( pCtx.is() )
923 : {
924 0 : pCtx->Stop();
925 0 : pCtx->join();
926 0 : pCtx.clear();
927 : }
928 :
929 0 : OUString sText = GetText();
930 0 : if ( !sText.isEmpty() && bIsAutoCompleteEnabled )
931 : {
932 0 : pCtx = new SvtMatchContext_Impl( this, sText );
933 0 : pCtx->launch();
934 0 : }
935 0 : }
936 :
937 0 : void SvtURLBox::SetSmartProtocol( INetProtocol eProt )
938 : {
939 0 : if ( eSmartProtocol != eProt )
940 : {
941 0 : eSmartProtocol = eProt;
942 0 : UpdatePicklistForSmartProtocol_Impl();
943 : }
944 0 : }
945 :
946 0 : void SvtURLBox::UpdatePicklistForSmartProtocol_Impl()
947 : {
948 0 : Clear();
949 0 : if ( !bHistoryDisabled )
950 : {
951 : // read history pick list
952 0 : Sequence< Sequence< PropertyValue > > seqPicklist = SvtHistoryOptions().GetList( eHISTORY );
953 0 : sal_uInt32 nCount = seqPicklist.getLength();
954 0 : INetURLObject aCurObj;
955 :
956 0 : for( sal_uInt32 nItem=0; nItem < nCount; nItem++ )
957 : {
958 0 : Sequence< PropertyValue > seqPropertySet = seqPicklist[ nItem ];
959 :
960 0 : OUString sURL;
961 :
962 0 : sal_uInt32 nPropertyCount = seqPropertySet.getLength();
963 :
964 0 : for( sal_uInt32 nProperty=0; nProperty < nPropertyCount; nProperty++ )
965 : {
966 0 : if( seqPropertySet[nProperty].Name == HISTORY_PROPERTYNAME_URL )
967 : {
968 0 : seqPropertySet[nProperty].Value >>= sURL;
969 0 : aCurObj.SetURL( sURL );
970 :
971 0 : if ( !sURL.isEmpty() && ( eSmartProtocol != INET_PROT_NOT_VALID ) )
972 : {
973 0 : if( aCurObj.GetProtocol() != eSmartProtocol )
974 0 : break;
975 : }
976 :
977 0 : OUString aURL( aCurObj.GetMainURL( INetURLObject::DECODE_WITH_CHARSET ) );
978 :
979 0 : if ( !aURL.isEmpty() )
980 : {
981 0 : bool bFound = aURL.endsWith("/");
982 0 : if ( !bFound )
983 : {
984 0 : OUString aUpperURL( aURL );
985 0 : aUpperURL = aUpperURL.toAsciiUpperCase();
986 :
987 : bFound
988 : = (::std::find_if(
989 : pImp->m_aFilters.begin(),
990 : pImp->m_aFilters.end(),
991 0 : FilterMatch( aUpperURL ) )
992 0 : != pImp->m_aFilters.end());
993 : }
994 0 : if ( bFound )
995 : {
996 0 : OUString aFile;
997 0 : if (::utl::LocalFileHelper::ConvertURLToSystemPath(aURL,aFile))
998 0 : InsertEntry(aFile);
999 : else
1000 0 : InsertEntry(aURL);
1001 : }
1002 : }
1003 0 : break;
1004 : }
1005 : }
1006 0 : }
1007 : }
1008 0 : }
1009 :
1010 :
1011 0 : bool SvtURLBox::ProcessKey( const KeyCode& rKey )
1012 : {
1013 : // every key input stops the current matching thread
1014 0 : if( pCtx.is() )
1015 : {
1016 0 : pCtx->Stop();
1017 0 : pCtx->join();
1018 0 : pCtx.clear();
1019 : }
1020 :
1021 0 : KeyCode aCode( rKey.GetCode() );
1022 0 : if ( aCode == KEY_RETURN && !GetText().isEmpty() )
1023 : {
1024 : // wait for completion of matching thread
1025 0 : ::osl::MutexGuard aGuard( theSvtMatchContextMutex::get() );
1026 :
1027 0 : if ( bAutoCompleteMode )
1028 : {
1029 : // reset picklist
1030 0 : bAutoCompleteMode = false;
1031 0 : Selection aSelection( GetSelection() );
1032 0 : SetSelection( Selection( aSelection.Min(), aSelection.Min() ) );
1033 0 : if ( bOnlyDirectories )
1034 0 : Clear();
1035 : else
1036 0 : UpdatePicklistForSmartProtocol_Impl();
1037 0 : Resize();
1038 : }
1039 :
1040 0 : bCtrlClick = rKey.IsMod1();
1041 0 : bool bHandled = false;
1042 0 : if ( GetOpenHdl().IsSet() )
1043 : {
1044 0 : bHandled = true;
1045 0 : GetOpenHdl().Call(this);
1046 : }
1047 0 : else if ( GetSelectHdl().IsSet() )
1048 : {
1049 0 : bHandled = true;
1050 0 : GetSelectHdl().Call(this);
1051 : }
1052 :
1053 0 : bCtrlClick = false;
1054 :
1055 0 : ClearModifyFlag();
1056 0 : return bHandled;
1057 : }
1058 0 : else if ( aCode == KEY_RETURN && GetText().isEmpty() && GetOpenHdl().IsSet() )
1059 : {
1060 : // for file dialog
1061 0 : bAutoCompleteMode = false;
1062 0 : GetOpenHdl().Call(this);
1063 0 : return true;
1064 : }
1065 0 : else if( aCode == KEY_ESCAPE )
1066 : {
1067 0 : Selection aSelection( GetSelection() );
1068 0 : if ( bAutoCompleteMode || aSelection.Min() != aSelection.Max() )
1069 : {
1070 0 : SetSelection( Selection( aSelection.Min(), aSelection.Min() ) );
1071 0 : if ( bOnlyDirectories )
1072 0 : Clear();
1073 : else
1074 0 : UpdatePicklistForSmartProtocol_Impl();
1075 0 : Resize();
1076 : }
1077 : else
1078 : {
1079 0 : return false;
1080 : }
1081 :
1082 0 : bAutoCompleteMode = false;
1083 0 : return true;
1084 : }
1085 : else
1086 : {
1087 0 : return false;
1088 : }
1089 : }
1090 :
1091 :
1092 0 : void SvtURLBox::Modify()
1093 : {
1094 0 : ComboBox::Modify();
1095 0 : }
1096 :
1097 :
1098 0 : bool SvtURLBox::PreNotify( NotifyEvent& rNEvt )
1099 : {
1100 0 : if( rNEvt.GetWindow() == GetSubEdit() && rNEvt.GetType() == EVENT_KEYINPUT )
1101 : {
1102 :
1103 0 : const KeyEvent& rEvent = *rNEvt.GetKeyEvent();
1104 0 : const KeyCode& rKey = rEvent.GetKeyCode();
1105 0 : KeyCode aCode( rKey.GetCode() );
1106 0 : if( ProcessKey( rKey ) )
1107 : {
1108 0 : return true;
1109 : }
1110 0 : else if( ( aCode == KEY_UP || aCode == KEY_DOWN ) && !rKey.IsMod2() )
1111 : {
1112 0 : Selection aSelection( GetSelection() );
1113 0 : sal_uInt16 nLen = (sal_uInt16)aSelection.Min();
1114 0 : GetSubEdit()->KeyInput( rEvent );
1115 0 : SetSelection( Selection( nLen, GetText().getLength() ) );
1116 0 : return true;
1117 : }
1118 :
1119 0 : if ( MatchesPlaceHolder( GetText() ) )
1120 : {
1121 : // set the selection so a key stroke will overwrite
1122 : // the placeholder rather than edit it
1123 0 : SetSelection( Selection( 0, GetText().getLength() ) );
1124 : }
1125 : }
1126 :
1127 0 : return ComboBox::PreNotify( rNEvt );
1128 : }
1129 :
1130 :
1131 0 : IMPL_LINK_NOARG(SvtURLBox, AutoCompleteHdl_Impl)
1132 : {
1133 0 : if ( GetSubEdit()->GetAutocompleteAction() == AUTOCOMPLETE_KEYINPUT )
1134 : {
1135 0 : TryAutoComplete();
1136 0 : return 1L;
1137 : }
1138 :
1139 0 : return 0L;
1140 : }
1141 :
1142 :
1143 0 : bool SvtURLBox::Notify( NotifyEvent &rEvt )
1144 : {
1145 0 : if ( EVENT_GETFOCUS == rEvt.GetType() )
1146 : {
1147 : #ifndef UNX
1148 : // pb: don't select automatically on unix #93251#
1149 : SetSelection( Selection( 0, GetText().getLength() ) );
1150 : #endif
1151 : }
1152 0 : else if ( EVENT_LOSEFOCUS == rEvt.GetType() )
1153 : {
1154 0 : if( GetText().isEmpty() )
1155 0 : ClearModifyFlag();
1156 0 : if ( pCtx.is() )
1157 : {
1158 0 : pCtx->Stop();
1159 0 : pCtx->join();
1160 0 : pCtx.clear();
1161 : }
1162 : }
1163 :
1164 0 : return ComboBox::Notify( rEvt );
1165 : }
1166 :
1167 :
1168 0 : void SvtURLBox::Select()
1169 : {
1170 0 : ComboBox::Select();
1171 0 : ClearModifyFlag();
1172 0 : }
1173 :
1174 :
1175 0 : void SvtURLBox::SetOnlyDirectories( bool bDir )
1176 : {
1177 0 : bOnlyDirectories = bDir;
1178 0 : if ( bOnlyDirectories )
1179 0 : Clear();
1180 0 : }
1181 :
1182 :
1183 0 : void SvtURLBox::SetNoURLSelection( bool bSet )
1184 : {
1185 0 : bNoSelection = bSet;
1186 0 : }
1187 :
1188 :
1189 0 : OUString SvtURLBox::GetURL()
1190 : {
1191 : // wait for end of autocompletion
1192 0 : ::osl::MutexGuard aGuard( theSvtMatchContextMutex::get() );
1193 :
1194 0 : OUString aText( GetText() );
1195 0 : if ( MatchesPlaceHolder( aText ) )
1196 0 : return aPlaceHolder;
1197 :
1198 : // try to get the right case preserving URL from the list of URLs
1199 0 : for(std::vector<OUString>::iterator i = pImp->aCompletions.begin(), j = pImp->aURLs.begin(); i != pImp->aCompletions.end() && j != pImp->aURLs.end(); ++i, ++j)
1200 : {
1201 0 : if((*i).equals(aText))
1202 0 : return *j;
1203 : }
1204 :
1205 : #ifdef WNT
1206 : // erase trailing spaces on Windows since thay are invalid on this OS and
1207 : // most of the time they are inserted by accident via copy / paste
1208 : aText = comphelper::string::stripEnd(aText, ' ');
1209 : if ( aText.isEmpty() )
1210 : return aText;
1211 : // #i9739#
1212 : #endif
1213 :
1214 0 : INetURLObject aObj( aText );
1215 0 : if( aText.indexOf( '*' ) != -1 || aText.indexOf( '?' ) != -1 )
1216 : {
1217 : // no autocompletion for wildcards
1218 0 : INetURLObject aTempObj;
1219 0 : if ( eSmartProtocol != INET_PROT_NOT_VALID )
1220 0 : aTempObj.SetSmartProtocol( eSmartProtocol );
1221 0 : if ( aTempObj.SetSmartURL( aText ) )
1222 0 : return aTempObj.GetMainURL( INetURLObject::NO_DECODE );
1223 : else
1224 0 : return aText;
1225 : }
1226 :
1227 0 : if ( aObj.GetProtocol() == INET_PROT_NOT_VALID )
1228 : {
1229 0 : OUString aName = ParseSmart( aText, aBaseURL, SvtPathOptions().GetWorkPath() );
1230 0 : aObj.SetURL(aName);
1231 0 : OUString aURL( aObj.GetMainURL( INetURLObject::NO_DECODE ) );
1232 0 : if ( aURL.isEmpty() )
1233 : // aText itself is invalid, and even together with aBaseURL, it could not
1234 : // made valid -> no chance
1235 0 : return aText;
1236 :
1237 0 : bool bSlash = aObj.hasFinalSlash();
1238 : {
1239 0 : const OUString aPropName("CasePreservingURL");
1240 :
1241 0 : OUString aFileURL;
1242 :
1243 0 : Any aAny = UCBContentHelper::GetProperty(aURL, aPropName);
1244 0 : bool success = (aAny >>= aFileURL);
1245 0 : OUString aTitle;
1246 0 : if(success)
1247 0 : aTitle = INetURLObject(aFileURL).getName(
1248 : INetURLObject::LAST_SEGMENT,
1249 : true,
1250 0 : INetURLObject::DECODE_WITH_CHARSET );
1251 : else
1252 : success =
1253 0 : UCBContentHelper::GetTitle(aURL,&aTitle);
1254 :
1255 0 : if( success && aTitle != "/" && aTitle != "." )
1256 : {
1257 0 : aObj.SetName( aTitle );
1258 0 : if ( bSlash )
1259 0 : aObj.setFinalSlash();
1260 0 : }
1261 0 : }
1262 : }
1263 :
1264 0 : return aObj.GetMainURL( INetURLObject::NO_DECODE );
1265 : }
1266 :
1267 0 : void SvtURLBox::DisableHistory()
1268 : {
1269 0 : bHistoryDisabled = true;
1270 0 : UpdatePicklistForSmartProtocol_Impl();
1271 0 : }
1272 :
1273 0 : void SvtURLBox::SetBaseURL( const OUString& rURL )
1274 : {
1275 0 : ::osl::MutexGuard aGuard( theSvtMatchContextMutex::get() );
1276 :
1277 : // Reset match lists
1278 0 : pImp->aCompletions.clear();
1279 0 : pImp->aURLs.clear();
1280 :
1281 0 : aBaseURL = rURL;
1282 0 : }
1283 :
1284 : /** Parse leading ~ for Unix systems,
1285 : does nothing for Windows
1286 : */
1287 0 : bool SvtURLBox_Impl::TildeParsing(
1288 : OUString&
1289 : #ifdef UNX
1290 : aText
1291 : #endif
1292 : , OUString&
1293 : #ifdef UNX
1294 : aBaseURL
1295 : #endif
1296 : )
1297 : {
1298 : #ifdef UNX
1299 0 : if( aText.startsWith( "~" ) )
1300 : {
1301 0 : OUString aParseTilde;
1302 0 : bool bTrailingSlash = true; // use trailing slash
1303 :
1304 0 : if( aText.getLength() == 1 || aText[ 1 ] == '/' )
1305 : {
1306 : // covers "~" or "~/..." cases
1307 0 : const char* aHomeLocation = getenv( "HOME" );
1308 0 : if( !aHomeLocation )
1309 0 : aHomeLocation = "";
1310 :
1311 0 : aParseTilde = OUString::createFromAscii(aHomeLocation);
1312 :
1313 : // in case the whole path is just "~" then there should
1314 : // be no trailing slash at the end
1315 0 : if( aText.getLength() == 1 )
1316 0 : bTrailingSlash = false;
1317 : }
1318 : else
1319 : {
1320 : // covers "~username" and "~username/..." cases
1321 0 : sal_Int32 nNameEnd = aText.indexOf( '/' );
1322 0 : OUString aUserName = aText.copy( 1, ( nNameEnd != -1 ) ? nNameEnd : ( aText.getLength() - 1 ) );
1323 :
1324 0 : struct passwd* pPasswd = NULL;
1325 : #ifdef SOLARIS
1326 : Sequence< sal_Int8 > sBuf( 1024 );
1327 : struct passwd aTmp;
1328 : sal_Int32 nRes = getpwnam_r( OUStringToOString( aUserName, RTL_TEXTENCODING_ASCII_US ).getStr(),
1329 : &aTmp,
1330 : (char*)sBuf.getArray(),
1331 : 1024,
1332 : &pPasswd );
1333 : if( !nRes && pPasswd )
1334 : aParseTilde = OUString::createFromAscii(pPasswd->pw_dir);
1335 : else
1336 : return false; // no such user
1337 : #else
1338 0 : pPasswd = getpwnam( OUStringToOString( aUserName, RTL_TEXTENCODING_ASCII_US ).getStr() );
1339 0 : if( pPasswd )
1340 0 : aParseTilde = OUString::createFromAscii(pPasswd->pw_dir);
1341 : else
1342 0 : return false; // no such user
1343 : #endif
1344 :
1345 : // in case the path is "~username" then there should
1346 : // be no trailing slash at the end
1347 0 : if( nNameEnd == -1 )
1348 0 : bTrailingSlash = false;
1349 : }
1350 :
1351 0 : if( !bTrailingSlash )
1352 : {
1353 0 : if( aParseTilde.isEmpty() || aParseTilde == "/" )
1354 : {
1355 : // "/" path should be converted to "/."
1356 0 : aParseTilde = "/.";
1357 : }
1358 : else
1359 : {
1360 : // "blabla/" path should be converted to "blabla"
1361 0 : aParseTilde = comphelper::string::stripEnd(aParseTilde, '/');
1362 : }
1363 : }
1364 : else
1365 : {
1366 0 : if( !aParseTilde.endsWith("/") )
1367 0 : aParseTilde += "/";
1368 0 : if( aText.getLength() > 2 )
1369 0 : aParseTilde += aText.copy( 2 );
1370 : }
1371 :
1372 0 : aText = aParseTilde;
1373 0 : aBaseURL = ""; // tilde provide absolute path
1374 : }
1375 : #endif
1376 :
1377 0 : return true;
1378 : }
1379 :
1380 0 : void SvtURLBox::SetFilter(const OUString& _sFilter)
1381 : {
1382 0 : pImp->m_aFilters.clear();
1383 0 : FilterMatch::createWildCardFilterList(_sFilter,pImp->m_aFilters);
1384 0 : }
1385 :
1386 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|