Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*************************************************************************
3 : *
4 : * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 : *
6 : * Copyright 2000, 2010 Oracle and/or its affiliates.
7 : *
8 : * OpenOffice.org - a multi-platform office productivity suite
9 : *
10 : * This file is part of OpenOffice.org.
11 : *
12 : * OpenOffice.org is free software: you can redistribute it and/or modify
13 : * it under the terms of the GNU Lesser General Public License version 3
14 : * only, as published by the Free Software Foundation.
15 : *
16 : * OpenOffice.org is distributed in the hope that it will be useful,
17 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : * GNU Lesser General Public License version 3 for more details
20 : * (a copy is included in the LICENSE file that accompanied this code).
21 : *
22 : * You should have received a copy of the GNU Lesser General Public License
23 : * version 3 along with OpenOffice.org. If not, see
24 : * <http://www.openoffice.org/license.html>
25 : * for a copy of the LGPLv3 License.
26 : *
27 : ************************************************************************/
28 :
29 : #undef LANGUAGE_NONE
30 : #define WINAPI __stdcall
31 : #define LoadInverseLib FALSE
32 : #define LoadLanguageLib FALSE
33 : #ifdef SYSTEM_LPSOLVE
34 : #include <lpsolve/lp_lib.h>
35 : #else
36 : #include <lp_lib.h>
37 : #endif
38 : #undef LANGUAGE_NONE
39 :
40 : #include "solver.hxx"
41 : #include "solver.hrc"
42 :
43 : #include <com/sun/star/beans/XPropertySet.hpp>
44 : #include <com/sun/star/container/XIndexAccess.hpp>
45 : #include <com/sun/star/frame/XModel.hpp>
46 : #include <com/sun/star/lang/XMultiServiceFactory.hpp>
47 : #include <com/sun/star/sheet/XSpreadsheetDocument.hpp>
48 : #include <com/sun/star/sheet/XSpreadsheet.hpp>
49 : #include <com/sun/star/table/CellAddress.hpp>
50 : #include <com/sun/star/table/CellRangeAddress.hpp>
51 : #include <com/sun/star/text/XTextRange.hpp>
52 :
53 : #include <rtl/math.hxx>
54 : #include <rtl/ustrbuf.hxx>
55 : #include <cppuhelper/factory.hxx>
56 : #include <vector>
57 : #include <boost/unordered_map.hpp>
58 :
59 : #include <tools/resmgr.hxx>
60 :
61 : using namespace com::sun::star;
62 :
63 : using ::rtl::OUString;
64 :
65 : #define C2U(constAsciiStr) (::rtl::OUString( constAsciiStr ))
66 :
67 : #define STR_NONNEGATIVE "NonNegative"
68 : #define STR_INTEGER "Integer"
69 : #define STR_TIMEOUT "Timeout"
70 : #define STR_EPSILONLEVEL "EpsilonLevel"
71 : #define STR_LIMITBBDEPTH "LimitBBDepth"
72 :
73 : // -----------------------------------------------------------------------
74 : // Resources from tools are used for translated strings
75 :
76 : static ResMgr* pSolverResMgr = NULL;
77 :
78 0 : static OUString lcl_GetResourceString( sal_uInt32 nId )
79 : {
80 0 : if (!pSolverResMgr)
81 0 : pSolverResMgr = ResMgr::CreateResMgr("solver");
82 :
83 0 : return String( ResId( nId, *pSolverResMgr ) );
84 : }
85 :
86 : // -----------------------------------------------------------------------
87 :
88 : namespace
89 : {
90 : enum
91 : {
92 : PROP_NONNEGATIVE,
93 : PROP_INTEGER,
94 : PROP_TIMEOUT,
95 : PROP_EPSILONLEVEL,
96 : PROP_LIMITBBDEPTH
97 : };
98 : }
99 :
100 : // -----------------------------------------------------------------------
101 :
102 : // hash map for the coefficients of a dependent cell (objective or constraint)
103 : // The size of each vector is the number of columns (variable cells) plus one, first entry is initial value.
104 :
105 : struct ScSolverCellHash
106 : {
107 0 : size_t operator()( const table::CellAddress& rAddress ) const
108 : {
109 0 : return ( rAddress.Sheet << 24 ) | ( rAddress.Column << 16 ) | rAddress.Row;
110 : }
111 : };
112 :
113 0 : inline bool AddressEqual( const table::CellAddress& rAddr1, const table::CellAddress& rAddr2 )
114 : {
115 0 : return rAddr1.Sheet == rAddr2.Sheet && rAddr1.Column == rAddr2.Column && rAddr1.Row == rAddr2.Row;
116 : }
117 :
118 : struct ScSolverCellEqual
119 : {
120 0 : bool operator()( const table::CellAddress& rAddr1, const table::CellAddress& rAddr2 ) const
121 : {
122 0 : return AddressEqual( rAddr1, rAddr2 );
123 : }
124 : };
125 :
126 : typedef boost::unordered_map< table::CellAddress, std::vector<double>, ScSolverCellHash, ScSolverCellEqual > ScSolverCellHashMap;
127 :
128 : // -----------------------------------------------------------------------
129 :
130 0 : static uno::Reference<table::XCell> lcl_GetCell( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc,
131 : const table::CellAddress& rPos )
132 : {
133 0 : uno::Reference<container::XIndexAccess> xSheets( xDoc->getSheets(), uno::UNO_QUERY );
134 0 : uno::Reference<sheet::XSpreadsheet> xSheet( xSheets->getByIndex( rPos.Sheet ), uno::UNO_QUERY );
135 0 : return xSheet->getCellByPosition( rPos.Column, rPos.Row );
136 : }
137 :
138 0 : static void lcl_SetValue( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc,
139 : const table::CellAddress& rPos, double fValue )
140 : {
141 0 : lcl_GetCell( xDoc, rPos )->setValue( fValue );
142 0 : }
143 :
144 0 : static double lcl_GetValue( const uno::Reference<sheet::XSpreadsheetDocument>& xDoc,
145 : const table::CellAddress& rPos )
146 : {
147 0 : return lcl_GetCell( xDoc, rPos )->getValue();
148 : }
149 :
150 : // -------------------------------------------------------------------------
151 :
152 0 : SolverComponent::SolverComponent( const uno::Reference<uno::XComponentContext>& /* rSMgr */ ) :
153 0 : OPropertyContainer( GetBroadcastHelper() ),
154 : mbMaximize( sal_True ),
155 : mbNonNegative( sal_False ),
156 : mbInteger( sal_False ),
157 : mnTimeout( 100 ),
158 : mnEpsilonLevel( 0 ),
159 : mbLimitBBDepth( sal_True ),
160 : mbSuccess( sal_False ),
161 0 : mfResultValue( 0.0 )
162 : {
163 : // for XPropertySet implementation:
164 0 : registerProperty( C2U(STR_NONNEGATIVE), PROP_NONNEGATIVE, 0, &mbNonNegative, getCppuType( &mbNonNegative ) );
165 0 : registerProperty( C2U(STR_INTEGER), PROP_INTEGER, 0, &mbInteger, getCppuType( &mbInteger ) );
166 0 : registerProperty( C2U(STR_TIMEOUT), PROP_TIMEOUT, 0, &mnTimeout, getCppuType( &mnTimeout ) );
167 0 : registerProperty( C2U(STR_EPSILONLEVEL), PROP_EPSILONLEVEL, 0, &mnEpsilonLevel, getCppuType( &mnEpsilonLevel ) );
168 0 : registerProperty( C2U(STR_LIMITBBDEPTH), PROP_LIMITBBDEPTH, 0, &mbLimitBBDepth, getCppuType( &mbLimitBBDepth ) );
169 0 : }
170 :
171 0 : SolverComponent::~SolverComponent()
172 : {
173 0 : }
174 :
175 0 : IMPLEMENT_FORWARD_XINTERFACE2( SolverComponent, SolverComponent_Base, OPropertyContainer )
176 0 : IMPLEMENT_FORWARD_XTYPEPROVIDER2( SolverComponent, SolverComponent_Base, OPropertyContainer )
177 :
178 0 : cppu::IPropertyArrayHelper* SolverComponent::createArrayHelper() const
179 : {
180 0 : uno::Sequence<beans::Property> aProps;
181 0 : describeProperties( aProps );
182 0 : return new cppu::OPropertyArrayHelper( aProps );
183 : }
184 :
185 0 : cppu::IPropertyArrayHelper& SAL_CALL SolverComponent::getInfoHelper()
186 : {
187 0 : return *getArrayHelper();
188 : }
189 :
190 0 : uno::Reference<beans::XPropertySetInfo> SAL_CALL SolverComponent::getPropertySetInfo() throw(uno::RuntimeException)
191 : {
192 0 : return createPropertySetInfo( getInfoHelper() );
193 : }
194 :
195 : // XSolverDescription
196 :
197 0 : OUString SAL_CALL SolverComponent::getComponentDescription() throw (uno::RuntimeException)
198 : {
199 0 : return lcl_GetResourceString( RID_SOLVER_COMPONENT );
200 : }
201 :
202 0 : OUString SAL_CALL SolverComponent::getStatusDescription() throw (uno::RuntimeException)
203 : {
204 0 : return maStatus;
205 : }
206 :
207 0 : OUString SAL_CALL SolverComponent::getPropertyDescription( const OUString& rPropertyName ) throw (uno::RuntimeException)
208 : {
209 0 : sal_uInt32 nResId = 0;
210 0 : sal_Int32 nHandle = getInfoHelper().getHandleByName( rPropertyName );
211 0 : switch (nHandle)
212 : {
213 : case PROP_NONNEGATIVE:
214 0 : nResId = RID_PROPERTY_NONNEGATIVE;
215 0 : break;
216 : case PROP_INTEGER:
217 0 : nResId = RID_PROPERTY_INTEGER;
218 0 : break;
219 : case PROP_TIMEOUT:
220 0 : nResId = RID_PROPERTY_TIMEOUT;
221 0 : break;
222 : case PROP_EPSILONLEVEL:
223 0 : nResId = RID_PROPERTY_EPSILONLEVEL;
224 0 : break;
225 : case PROP_LIMITBBDEPTH:
226 0 : nResId = RID_PROPERTY_LIMITBBDEPTH;
227 0 : break;
228 : default:
229 : {
230 : // unknown - leave empty
231 : }
232 : }
233 0 : OUString aRet;
234 0 : if ( nResId )
235 0 : aRet = lcl_GetResourceString( nResId );
236 0 : return aRet;
237 : }
238 :
239 : // XSolver: settings
240 :
241 0 : uno::Reference<sheet::XSpreadsheetDocument> SAL_CALL SolverComponent::getDocument() throw(uno::RuntimeException)
242 : {
243 0 : return mxDoc;
244 : }
245 :
246 0 : void SAL_CALL SolverComponent::setDocument( const uno::Reference<sheet::XSpreadsheetDocument>& _document )
247 : throw(uno::RuntimeException)
248 : {
249 0 : mxDoc = _document;
250 0 : }
251 :
252 0 : table::CellAddress SAL_CALL SolverComponent::getObjective() throw(uno::RuntimeException)
253 : {
254 0 : return maObjective;
255 : }
256 :
257 0 : void SAL_CALL SolverComponent::setObjective( const table::CellAddress& _objective ) throw(uno::RuntimeException)
258 : {
259 0 : maObjective = _objective;
260 0 : }
261 :
262 0 : uno::Sequence<table::CellAddress> SAL_CALL SolverComponent::getVariables() throw(uno::RuntimeException)
263 : {
264 0 : return maVariables;
265 : }
266 :
267 0 : void SAL_CALL SolverComponent::setVariables( const uno::Sequence<table::CellAddress>& _variables )
268 : throw(uno::RuntimeException)
269 : {
270 0 : maVariables = _variables;
271 0 : }
272 :
273 0 : uno::Sequence<sheet::SolverConstraint> SAL_CALL SolverComponent::getConstraints() throw(uno::RuntimeException)
274 : {
275 0 : return maConstraints;
276 : }
277 :
278 0 : void SAL_CALL SolverComponent::setConstraints( const uno::Sequence<sheet::SolverConstraint>& _constraints )
279 : throw(uno::RuntimeException)
280 : {
281 0 : maConstraints = _constraints;
282 0 : }
283 :
284 0 : sal_Bool SAL_CALL SolverComponent::getMaximize() throw(uno::RuntimeException)
285 : {
286 0 : return mbMaximize;
287 : }
288 :
289 0 : void SAL_CALL SolverComponent::setMaximize( sal_Bool _maximize ) throw(uno::RuntimeException)
290 : {
291 0 : mbMaximize = _maximize;
292 0 : }
293 :
294 : // XSolver: get results
295 :
296 0 : sal_Bool SAL_CALL SolverComponent::getSuccess() throw(uno::RuntimeException)
297 : {
298 0 : return mbSuccess;
299 : }
300 :
301 0 : double SAL_CALL SolverComponent::getResultValue() throw(uno::RuntimeException)
302 : {
303 0 : return mfResultValue;
304 : }
305 :
306 0 : uno::Sequence<double> SAL_CALL SolverComponent::getSolution() throw(uno::RuntimeException)
307 : {
308 0 : return maSolution;
309 : }
310 :
311 : // -------------------------------------------------------------------------
312 :
313 0 : void SAL_CALL SolverComponent::solve() throw(uno::RuntimeException)
314 : {
315 0 : uno::Reference<frame::XModel> xModel( mxDoc, uno::UNO_QUERY );
316 0 : if ( !xModel.is() )
317 0 : throw uno::RuntimeException();
318 :
319 0 : maStatus = OUString();
320 0 : mbSuccess = false;
321 :
322 0 : if ( mnEpsilonLevel < EPS_TIGHT || mnEpsilonLevel > EPS_BAGGY )
323 : {
324 0 : maStatus = lcl_GetResourceString( RID_ERROR_EPSILONLEVEL );
325 : return;
326 : }
327 :
328 0 : xModel->lockControllers();
329 :
330 : // collect variables in vector (?)
331 :
332 0 : std::vector<table::CellAddress> aVariableCells;
333 0 : for (sal_Int32 nPos=0; nPos<maVariables.getLength(); nPos++)
334 0 : aVariableCells.push_back( maVariables[nPos] );
335 0 : size_t nVariables = aVariableCells.size();
336 0 : size_t nVar = 0;
337 :
338 : // collect all dependent cells
339 :
340 0 : ScSolverCellHashMap aCellsHash;
341 0 : aCellsHash[maObjective].reserve( nVariables + 1 ); // objective function
342 :
343 0 : for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos)
344 : {
345 0 : table::CellAddress aCellAddr = maConstraints[nConstrPos].Left;
346 0 : aCellsHash[aCellAddr].reserve( nVariables + 1 ); // constraints: left hand side
347 :
348 0 : if ( maConstraints[nConstrPos].Right >>= aCellAddr )
349 0 : aCellsHash[aCellAddr].reserve( nVariables + 1 ); // constraints: right hand side
350 : }
351 :
352 : // set all variables to zero
353 : //! store old values?
354 : //! use old values as initial values?
355 0 : std::vector<table::CellAddress>::const_iterator aVarIter;
356 0 : for ( aVarIter = aVariableCells.begin(); aVarIter != aVariableCells.end(); ++aVarIter )
357 : {
358 0 : lcl_SetValue( mxDoc, *aVarIter, 0.0 );
359 : }
360 :
361 : // read initial values from all dependent cells
362 0 : ScSolverCellHashMap::iterator aCellsIter;
363 0 : for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter )
364 : {
365 0 : double fValue = lcl_GetValue( mxDoc, aCellsIter->first );
366 0 : aCellsIter->second.push_back( fValue ); // store as first element, as-is
367 : }
368 :
369 : // loop through variables
370 0 : for ( aVarIter = aVariableCells.begin(); aVarIter != aVariableCells.end(); ++aVarIter )
371 : {
372 0 : lcl_SetValue( mxDoc, *aVarIter, 1.0 ); // set to 1 to examine influence
373 :
374 : // read value change from all dependent cells
375 0 : for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter )
376 : {
377 0 : double fChanged = lcl_GetValue( mxDoc, aCellsIter->first );
378 0 : double fInitial = aCellsIter->second.front();
379 0 : aCellsIter->second.push_back( fChanged - fInitial );
380 : }
381 :
382 0 : lcl_SetValue( mxDoc, *aVarIter, 2.0 ); // minimal test for linearity
383 :
384 0 : for ( aCellsIter = aCellsHash.begin(); aCellsIter != aCellsHash.end(); ++aCellsIter )
385 : {
386 0 : double fInitial = aCellsIter->second.front();
387 0 : double fCoeff = aCellsIter->second.back(); // last appended: coefficient for this variable
388 0 : double fTwo = lcl_GetValue( mxDoc, aCellsIter->first );
389 :
390 0 : bool bLinear = rtl::math::approxEqual( fTwo, fInitial + 2.0 * fCoeff ) ||
391 0 : rtl::math::approxEqual( fInitial, fTwo - 2.0 * fCoeff );
392 : // second comparison is needed in case fTwo is zero
393 0 : if ( !bLinear )
394 0 : maStatus = lcl_GetResourceString( RID_ERROR_NONLINEAR );
395 : }
396 :
397 0 : lcl_SetValue( mxDoc, *aVarIter, 0.0 ); // set back to zero for examining next variable
398 : }
399 :
400 0 : xModel->unlockControllers();
401 :
402 0 : if ( !maStatus.isEmpty() )
403 : return;
404 :
405 : //
406 : // build lp_solve model
407 : //
408 :
409 0 : lprec* lp = make_lp( 0, nVariables );
410 0 : if ( !lp )
411 : return;
412 :
413 0 : set_outputfile( lp, const_cast<char*>( "" ) ); // no output
414 :
415 : // set objective function
416 :
417 0 : const std::vector<double>& rObjCoeff = aCellsHash[maObjective];
418 0 : REAL* pObjVal = new REAL[nVariables+1];
419 0 : pObjVal[0] = 0.0; // ignored
420 0 : for (nVar=0; nVar<nVariables; nVar++)
421 0 : pObjVal[nVar+1] = rObjCoeff[nVar+1];
422 0 : set_obj_fn( lp, pObjVal );
423 0 : delete[] pObjVal;
424 0 : set_rh( lp, 0, rObjCoeff[0] ); // constant term of objective
425 :
426 : // add rows
427 :
428 0 : set_add_rowmode(lp, TRUE);
429 :
430 0 : for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos)
431 : {
432 : // integer constraints are set later
433 0 : sheet::SolverConstraintOperator eOp = maConstraints[nConstrPos].Operator;
434 0 : if ( eOp == sheet::SolverConstraintOperator_LESS_EQUAL ||
435 : eOp == sheet::SolverConstraintOperator_GREATER_EQUAL ||
436 : eOp == sheet::SolverConstraintOperator_EQUAL )
437 : {
438 0 : double fDirectValue = 0.0;
439 0 : bool bRightCell = false;
440 0 : table::CellAddress aRightAddr;
441 0 : const uno::Any& rRightAny = maConstraints[nConstrPos].Right;
442 0 : if ( rRightAny >>= aRightAddr )
443 0 : bRightCell = true; // cell specified as right-hand side
444 : else
445 0 : rRightAny >>= fDirectValue; // constant value
446 :
447 0 : table::CellAddress aLeftAddr = maConstraints[nConstrPos].Left;
448 :
449 0 : const std::vector<double>& rLeftCoeff = aCellsHash[aLeftAddr];
450 0 : REAL* pValues = new REAL[nVariables+1];
451 0 : pValues[0] = 0.0; // ignored?
452 0 : for (nVar=0; nVar<nVariables; nVar++)
453 0 : pValues[nVar+1] = rLeftCoeff[nVar+1];
454 :
455 : // if left hand cell has a constant term, put into rhs value
456 0 : double fRightValue = -rLeftCoeff[0];
457 :
458 0 : if ( bRightCell )
459 : {
460 0 : const std::vector<double>& rRightCoeff = aCellsHash[aRightAddr];
461 : // modify pValues with rhs coefficients
462 0 : for (nVar=0; nVar<nVariables; nVar++)
463 0 : pValues[nVar+1] -= rRightCoeff[nVar+1];
464 :
465 0 : fRightValue += rRightCoeff[0]; // constant term
466 : }
467 : else
468 0 : fRightValue += fDirectValue;
469 :
470 0 : int nConstrType = LE;
471 0 : switch ( eOp )
472 : {
473 0 : case sheet::SolverConstraintOperator_LESS_EQUAL: nConstrType = LE; break;
474 0 : case sheet::SolverConstraintOperator_GREATER_EQUAL: nConstrType = GE; break;
475 0 : case sheet::SolverConstraintOperator_EQUAL: nConstrType = EQ; break;
476 : default:
477 : OSL_FAIL( "unexpected enum type" );
478 : }
479 0 : add_constraint( lp, pValues, nConstrType, fRightValue );
480 :
481 0 : delete[] pValues;
482 : }
483 : }
484 :
485 0 : set_add_rowmode(lp, FALSE);
486 :
487 : // apply settings to all variables
488 :
489 0 : for (nVar=0; nVar<nVariables; nVar++)
490 : {
491 0 : if ( !mbNonNegative )
492 0 : set_unbounded(lp, nVar+1); // allow negative (default is non-negative)
493 : //! collect bounds from constraints?
494 0 : if ( mbInteger )
495 0 : set_int(lp, nVar+1, TRUE);
496 : }
497 :
498 : // apply single-var integer constraints
499 :
500 0 : for (sal_Int32 nConstrPos = 0; nConstrPos < maConstraints.getLength(); ++nConstrPos)
501 : {
502 0 : sheet::SolverConstraintOperator eOp = maConstraints[nConstrPos].Operator;
503 0 : if ( eOp == sheet::SolverConstraintOperator_INTEGER ||
504 : eOp == sheet::SolverConstraintOperator_BINARY )
505 : {
506 0 : table::CellAddress aLeftAddr = maConstraints[nConstrPos].Left;
507 : // find variable index for cell
508 0 : for (nVar=0; nVar<nVariables; nVar++)
509 0 : if ( AddressEqual( aVariableCells[nVar], aLeftAddr ) )
510 : {
511 0 : if ( eOp == sheet::SolverConstraintOperator_INTEGER )
512 0 : set_int(lp, nVar+1, TRUE);
513 : else
514 0 : set_binary(lp, nVar+1, TRUE);
515 : }
516 : }
517 : }
518 :
519 0 : if ( mbMaximize )
520 0 : set_maxim(lp);
521 : else
522 0 : set_minim(lp);
523 :
524 0 : if ( !mbLimitBBDepth )
525 0 : set_bb_depthlimit( lp, 0 );
526 :
527 0 : set_epslevel( lp, mnEpsilonLevel );
528 0 : set_timeout( lp, mnTimeout );
529 :
530 : // solve model
531 :
532 0 : int nResult = ::solve( lp );
533 :
534 0 : mbSuccess = ( nResult == OPTIMAL );
535 0 : if ( mbSuccess )
536 : {
537 : // get solution
538 :
539 0 : maSolution.realloc( nVariables );
540 :
541 0 : REAL* pResultVar = NULL;
542 0 : get_ptr_variables( lp, &pResultVar );
543 0 : for (nVar=0; nVar<nVariables; nVar++)
544 0 : maSolution[nVar] = pResultVar[nVar];
545 :
546 0 : mfResultValue = get_objective( lp );
547 : }
548 0 : else if ( nResult == INFEASIBLE )
549 0 : maStatus = lcl_GetResourceString( RID_ERROR_INFEASIBLE );
550 0 : else if ( nResult == UNBOUNDED )
551 0 : maStatus = lcl_GetResourceString( RID_ERROR_UNBOUNDED );
552 0 : else if ( nResult == TIMEOUT || nResult == SUBOPTIMAL )
553 0 : maStatus = lcl_GetResourceString( RID_ERROR_TIMEOUT );
554 : // SUBOPTIMAL is assumed to be caused by a timeout, and reported as an error
555 :
556 0 : delete_lp( lp );
557 : }
558 :
559 : // -------------------------------------------------------------------------
560 :
561 : // XServiceInfo
562 :
563 0 : uno::Sequence< OUString > SolverComponent_getSupportedServiceNames()
564 : {
565 0 : uno::Sequence< OUString > aServiceNames( 1 );
566 0 : aServiceNames[ 0 ] = OUString("com.sun.star.sheet.Solver" );
567 0 : return aServiceNames;
568 : }
569 :
570 0 : OUString SolverComponent_getImplementationName()
571 : {
572 0 : return OUString("com.sun.star.comp.Calc.Solver" );
573 : }
574 :
575 0 : OUString SAL_CALL SolverComponent::getImplementationName() throw(uno::RuntimeException)
576 : {
577 0 : return SolverComponent_getImplementationName();
578 : }
579 :
580 0 : sal_Bool SAL_CALL SolverComponent::supportsService( const OUString& rServiceName ) throw(uno::RuntimeException)
581 : {
582 0 : const uno::Sequence< OUString > aServices = SolverComponent_getSupportedServiceNames();
583 0 : const OUString* pArray = aServices.getConstArray();
584 0 : const OUString* pArrayEnd = pArray + aServices.getLength();
585 0 : return ::std::find( pArray, pArrayEnd, rServiceName ) != pArrayEnd;
586 : }
587 :
588 0 : uno::Sequence<OUString> SAL_CALL SolverComponent::getSupportedServiceNames() throw(uno::RuntimeException)
589 : {
590 0 : return SolverComponent_getSupportedServiceNames();
591 : }
592 :
593 0 : uno::Reference<uno::XInterface> SolverComponent_createInstance( const uno::Reference<uno::XComponentContext>& rSMgr )
594 : throw(uno::Exception)
595 : {
596 0 : return (cppu::OWeakObject*) new SolverComponent( rSMgr );
597 : }
598 :
599 : // -------------------------------------------------------------------------
600 :
601 : extern "C"
602 : {
603 0 : SAL_DLLPUBLIC_EXPORT void* SAL_CALL solver_component_getFactory( const sal_Char * pImplName, void * pServiceManager, void * /*pRegistryKey*/ )
604 : {
605 0 : OUString aImplName( OUString::createFromAscii( pImplName ) );
606 0 : void* pRet = 0;
607 :
608 0 : if( pServiceManager )
609 : {
610 0 : uno::Reference< lang::XSingleComponentFactory > xFactory;
611 0 : if( aImplName.equals( SolverComponent_getImplementationName() ) )
612 : xFactory = cppu::createSingleComponentFactory(
613 : SolverComponent_createInstance,
614 : OUString::createFromAscii( pImplName ),
615 0 : SolverComponent_getSupportedServiceNames() );
616 :
617 0 : if( xFactory.is() )
618 : {
619 0 : xFactory->acquire();
620 0 : pRet = xFactory.get();
621 0 : }
622 : }
623 0 : return pRet;
624 : }
625 : }
626 :
627 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|