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