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