00001 /* 00002 * Copyright (C) 2003-2009 Olivier Boudeville 00003 * 00004 * This file is part of the Ceylan library. 00005 * 00006 * The Ceylan library is free software: you can redistribute it and/or modify 00007 * it under the terms of either the GNU Lesser General Public License or 00008 * the GNU General Public License, as they are published by the Free Software 00009 * Foundation, either version 3 of these Licenses, or (at your option) 00010 * any later version. 00011 * 00012 * The Ceylan library is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00015 * GNU Lesser General Public License and the GNU General Public License 00016 * for more details. 00017 * 00018 * You should have received a copy of the GNU Lesser General Public 00019 * License and the GNU General Public License along with the Ceylan library. 00020 * If not, see <http://www.gnu.org/licenses/>. 00021 * 00022 * Author: Olivier Boudeville (olivier.boudeville@esperide.com) 00023 * 00024 */ 00025 00026 00027 #ifndef CEYLAN_GENERIC_MODEL_H_ 00028 #define CEYLAN_GENERIC_MODEL_H_ 00029 00030 00031 #include "CeylanGenericMVCDefines.h" // for GenericMVCException 00032 #include "CeylanTextDisplayable.h" // for inheritance 00033 #include "CeylanOperators.h" // for toString 00034 #include "CeylanStringUtils.h" // for formatStringList 00035 00036 00037 #include <string> 00038 #include <list> 00039 00040 00041 00042 /* 00043 * See the CeylanGenericMVCDefines.h file for detailed design explanations 00044 * about this light-weight generic (template-based) MVC framework. 00045 * 00046 */ 00047 00048 00049 /* 00050 * Here the base model (BaseModel) and all necessary templated variations of 00051 * models are defined: 00052 * 00053 * - a model with no view and no controller: NoViewGenericModel 00054 * - a model with a single view and no controller: SingleViewGenericModel<View> 00055 * - a model with multiple (any number of) views and no controller: 00056 * MultipleViewGenericModel<View> 00057 * - a model with no view and a single controller: 00058 * SingleControllerNoViewGenericModel<Controller> 00059 * 00060 * 00061 */ 00062 00063 00064 /* 00065 * Actually there is apparently little need for a model to know the 00066 * specific class of its view(s), as a model will just manage their life-cycle. 00067 * Hence view-templated models are not strictly necessary: they just deal with 00068 * (not necessarily known) BaseView instances. 00069 * 00070 * On the contrary, a view has to know the actual model class it corresponds 00071 * to (i.e. a view has to be model-templated), as the view needs, to perform 00072 * its rendering, to call class-specific (const) methods from its model(s) 00073 * (to know its state). 00074 * 00075 * Therefore here view-templated models have non-template counterparts, which 00076 * are easier to integrate in user's code and should be nevertheless suitable 00077 * for most usages: 00078 * 00079 * - a model with a single view and no controller: SingleViewGenericModel 00080 * - a model with multiple (any number of) views and no controller: 00081 * MultipleViewGenericModel 00082 * 00083 * @note SingleViewModel could not be named SingleViewGenericModel as the 00084 * compiler would find an ambiguity with the SingleViewGenericModel template. 00085 * However SingleViewModel and al should not by confused with the 00086 * Ceylan::MVC::Model class, which belongs to a different (event-based) MVC 00087 * framework. 00088 * 00089 */ 00090 00091 00092 00093 00094 00095 namespace Ceylan 00096 { 00097 00098 00099 namespace MVC 00100 { 00101 00102 00103 00104 // A model may know its view(s): 00105 class BaseView ; 00106 00107 00108 // A model knows its controller(s): 00109 class BaseController ; 00110 00111 00112 00113 00114 00115 // BaseModel mother class. 00116 00117 00142 class CEYLAN_DLL BaseModel : public TextDisplayable 00143 { 00144 00145 00146 public: 00147 00148 00149 00154 BaseModel() ; 00155 00156 00157 00159 virtual ~BaseModel() throw() ; 00160 00161 00162 00179 virtual void addView( const BaseView & view ) const = 0 ; 00180 00181 00182 00194 virtual const std::string toString( 00195 Ceylan::VerbosityLevels level = Ceylan::high ) 00196 const ; 00197 00198 00199 00200 00201 private: 00202 00203 00211 BaseModel( const BaseModel & source ) ; 00212 00213 00221 BaseModel & operator = ( const BaseModel & source ) ; 00222 00223 00224 } ; 00225 00226 00227 00228 00229 00230 00231 // NoViewModel class. No template issues here. 00232 00233 00234 00241 class CEYLAN_DLL NoViewModel : public BaseModel 00242 { 00243 00244 00245 public: 00246 00247 00248 00253 NoViewModel() ; 00254 00255 00256 00258 virtual ~NoViewModel() throw() ; 00259 00260 00261 00273 virtual void addView( const BaseView & view ) const ; 00274 00275 00276 00288 virtual const std::string toString( 00289 Ceylan::VerbosityLevels level = Ceylan::high ) const ; 00290 00291 00292 00293 00294 private: 00295 00296 00304 NoViewModel( const NoViewModel & source ) ; 00305 00306 00314 NoViewModel & operator = ( const NoViewModel & source ) ; 00315 00316 00317 } ; 00318 00319 00320 00321 00322 00323 00324 00325 /* 00326 * SingleViewGenericModel templated class. 00327 * 00328 * @note Usually using this view-templated class is overkill, as 00329 * most, if not all, models do not really need to know the actual class 00330 * of the views they are associated with. 00331 * 00332 */ 00333 00334 00335 00336 00352 template <typename ActualView> 00353 class SingleViewGenericModel: public BaseModel 00354 { 00355 00356 public: 00357 00358 00369 explicit SingleViewGenericModel( const ActualView & view ) ; 00370 00371 00381 SingleViewGenericModel() ; 00382 00383 00384 00391 virtual ~SingleViewGenericModel() throw() ; 00392 00393 00394 00406 virtual void setView( const ActualView & view ) ; 00407 00408 00409 00430 virtual void addView( const ActualView & view ) const ; 00431 00432 00433 00445 virtual const std::string toString( 00446 Ceylan::VerbosityLevels level = Ceylan::high ) const ; 00447 00448 00449 00450 protected: 00451 00452 00461 const ActualView * _view ; 00462 00463 00464 00465 private: 00466 00467 00475 SingleViewGenericModel( 00476 const SingleViewGenericModel & source ) ; 00477 00478 00486 SingleViewGenericModel & operator = ( 00487 const SingleViewGenericModel & source ) ; 00488 00489 00490 } ; 00491 00492 00493 00494 00495 // Implementation of the SingleViewGenericModel templated class. 00496 00497 00498 template <typename ActualView> 00499 SingleViewGenericModel<ActualView>::SingleViewGenericModel( 00500 const ActualView & view ) : 00501 _view( & view ) 00502 { 00503 00504 } 00505 00506 00507 00508 template <typename ActualView> 00509 SingleViewGenericModel<ActualView>::SingleViewGenericModel() : 00510 _view( 0 ) 00511 { 00512 00513 } 00514 00515 00516 00517 template <typename ActualView> 00518 SingleViewGenericModel<ActualView>::~SingleViewGenericModel() throw() 00519 { 00520 00521 if ( _view != 0 ) 00522 { 00523 00524 // View owned here: 00525 delete _view ; 00526 00527 } 00528 00529 } 00530 00531 00532 00533 template <typename ActualView> 00534 void 00535 SingleViewGenericModel<ActualView>::setView( const ActualView & view ) 00536 { 00537 00538 addView( view ) ; 00539 00540 } 00541 00542 00543 00544 template <typename ActualView> 00545 void 00546 SingleViewGenericModel<ActualView>::addView( const ActualView & view ) 00547 const 00548 { 00549 00550 if ( _view != 0 ) 00551 throw GenericMVCException( 00552 "SingleViewGenericModel<ActualView>::addView failed: " 00553 "a view was already registered." ) ; 00554 00555 // Do as if this instance had not to be 'const': 00556 const_cast< SingleViewGenericModel<ActualView> *>(this)->_view = 00557 & view ; 00558 00559 } 00560 00561 00562 00563 template <typename ActualView> 00564 const std::string 00565 SingleViewGenericModel<ActualView>::toString( 00566 Ceylan::VerbosityLevels level ) const 00567 { 00568 00569 if ( _view != 0 ) 00570 { 00571 00572 /* 00573 * Beware to infinite recursion: 00574 * (the view may display in turn this model) 00575 * 00576 */ 00577 00578 if ( level == Ceylan::low ) 00579 return "Single-view controller-less generic model " 00580 "owning a view" ; 00581 else 00582 return "Single-view controller-less generic model " 00583 "associated to " + _view->toString( level ) ; 00584 00585 } 00586 else 00587 { 00588 00589 return "Single-view controller-less generic model " 00590 "not associated to any view" ; 00591 00592 } 00593 00594 } 00595 00596 00597 00598 00599 00600 /* 00601 * SingleViewModel non-templated class. 00602 * 00603 * Simpler than the SingleViewGenericModel view-templated 00604 * counterpart, but deals with BaseView instances instead of an actual 00605 * view child class. 00606 * 00607 * Once the actual relationships between a model and its views 00608 * are taken into account, using a non-templated model should not be 00609 * a problem in general. 00610 * 00611 */ 00612 00613 00614 00615 00626 class CEYLAN_DLL SingleViewModel: public BaseModel 00627 { 00628 00629 public: 00630 00631 00632 00643 explicit SingleViewModel( const BaseView & view ) ; 00644 00645 00646 00656 SingleViewModel() ; 00657 00658 00659 00666 virtual ~SingleViewModel() throw() ; 00667 00668 00669 00687 virtual void setView( const BaseView & view ) ; 00688 00689 00690 00711 virtual void addView( const BaseView & view ) const ; 00712 00713 00714 00726 virtual const std::string toString( 00727 Ceylan::VerbosityLevels level = Ceylan::high ) const ; 00728 00729 00730 00731 protected: 00732 00733 00742 const BaseView * _view ; 00743 00744 00745 00746 private: 00747 00748 00756 SingleViewModel( const SingleViewModel & source ) ; 00757 00758 00766 SingleViewModel & operator = ( 00767 const SingleViewModel & source ) ; 00768 00769 00770 } ; 00771 00772 00773 00774 00775 00776 00777 /* 00778 * MultipleViewGenericModel templated class. 00779 * 00780 * @note Usually using this view-templated class is overkill, as 00781 * most if not all models do not really need to know the actual class 00782 * of the views they are associated with. 00783 * 00784 */ 00785 00786 00787 00796 template <typename ActualView> 00797 class MultipleViewGenericModel: public BaseModel 00798 { 00799 00800 00801 public: 00802 00803 00804 00815 explicit MultipleViewGenericModel( const ActualView & view ) ; 00816 00817 00818 00829 explicit MultipleViewGenericModel( 00830 const std::list<const ActualView *> & views ) ; 00831 00832 00833 00844 MultipleViewGenericModel() ; 00845 00846 00847 00854 virtual ~MultipleViewGenericModel() throw() ; 00855 00856 00857 00868 virtual void setViews( 00869 const std::list<const ActualView *> & views ) ; 00870 00871 00872 00887 virtual void addView( const ActualView & view ) const ; 00888 00889 00890 00902 virtual const std::string toString( 00903 Ceylan::VerbosityLevels level = Ceylan::high ) const ; 00904 00905 00906 00907 protected: 00908 00909 00911 virtual void deleteViews() ; 00912 00913 00915 std::list<const ActualView *> _views ; 00916 00917 00918 00919 private: 00920 00921 00929 MultipleViewGenericModel( 00930 const MultipleViewGenericModel & source ) ; 00931 00932 00940 MultipleViewGenericModel & operator = ( 00941 const MultipleViewGenericModel & source ) ; 00942 00943 00944 } ; 00945 00946 00947 00948 00949 // Implementation of the MultipleViewGenericModel templated class. 00950 00951 00952 template <typename ActualView> 00953 MultipleViewGenericModel<ActualView>::MultipleViewGenericModel( 00954 const ActualView & view ) 00955 { 00956 00957 _views.push_back( view ) ; 00958 00959 } 00960 00961 00962 template <typename ActualView> 00963 MultipleViewGenericModel<ActualView>::MultipleViewGenericModel( 00964 const std::list<const ActualView *> & views ) 00965 { 00966 00967 _views = views ; 00968 00969 } 00970 00971 00972 00973 template <typename ActualView> 00974 MultipleViewGenericModel<ActualView>::MultipleViewGenericModel() 00975 { 00976 00977 } 00978 00979 00980 00981 template <typename ActualView> 00982 MultipleViewGenericModel<ActualView>::~MultipleViewGenericModel() 00983 throw() 00984 { 00985 00986 deleteViews() ; 00987 00988 } 00989 00990 00991 00992 template <typename ActualView> 00993 void MultipleViewGenericModel<ActualView>::setViews( 00994 const std::list<const ActualView *> & views ) 00995 { 00996 00997 if ( ! _views.empty() ) 00998 throw GenericMVCException( 00999 "MultipleViewGenericModel<ActualView>::setViews failed: " 01000 "there was at least one view registered." ) ; 01001 01002 _views = views ; 01003 01004 } 01005 01006 01007 01008 template <typename ActualView> 01009 void 01010 MultipleViewGenericModel<ActualView>::addView( const ActualView & view ) 01011 const 01012 { 01013 01014 _views.push_back( & view ) ; 01015 01016 } 01017 01018 01019 01020 template <typename ActualView> 01021 const std::string 01022 MultipleViewGenericModel<ActualView>::toString( 01023 Ceylan::VerbosityLevels level ) const 01024 { 01025 01026 if ( _views.empty() ) 01027 return "Multiple-view controller-less generic model " 01028 "not associated to any view" ; 01029 01030 /* 01031 * Beware to infinite recursion: 01032 * (the view may display in turn this model) 01033 * 01034 */ 01035 01036 if ( level == Ceylan::low ) 01037 return "Multiple-view controller-less generic model " 01038 "owning " + Ceylan::toString( _views.size() ) + " view(s)" ; 01039 01040 01041 std::list<std::string> res ; 01042 01043 for ( typename std::list<const ActualView *>::const_iterator it = 01044 _views.begin(); it != _views.end() ; it++ ) 01045 { 01046 01047 res.push_back( (*it)->toString( level ) ) ; 01048 01049 } 01050 01051 return "Multiple-view controller-less generic model " 01052 "associated to following view(s): " 01053 + Ceylan::formatStringList( res ) ; 01054 01055 } 01056 01057 01058 01059 template <typename ActualView> 01060 void MultipleViewGenericModel<ActualView>::deleteViews() 01061 { 01062 01063 for ( typename std::list<const ActualView *>::const_iterator it = 01064 _views.begin(); it != _views.end(); it++ ) 01065 { 01066 01067 delete *it ; 01068 01069 } 01070 01071 _views.clear() ; 01072 01073 } 01074 01075 01076 01077 01078 01079 /* 01080 * MultipleViewModel non-templated class. 01081 * 01082 * Simpler than the MultipleViewGenericModel view-templated 01083 * counterpart, but deals with BaseView instances instead of an actual 01084 * view child class. 01085 * 01086 * Once the actual relationships between a model and its views 01087 * are taken into account, using a non-templated model should not be 01088 * a problem in general. 01089 * 01090 */ 01091 01092 01093 01102 class CEYLAN_DLL MultipleViewModel: public BaseModel 01103 { 01104 01105 01106 public: 01107 01108 01109 01120 explicit MultipleViewModel( const BaseView & view ) ; 01121 01122 01123 01134 explicit MultipleViewModel( 01135 const std::list<const BaseView *> & views ) ; 01136 01137 01138 01149 MultipleViewModel() ; 01150 01151 01152 01159 virtual ~MultipleViewModel() throw() ; 01160 01161 01162 01173 virtual void setViews( 01174 const std::list<const BaseView *> & views ) ; 01175 01176 01177 01192 virtual void addView( const BaseView & view ) 01193 const ; 01194 01195 01196 01208 virtual const std::string toString( 01209 Ceylan::VerbosityLevels level = Ceylan::high ) const ; 01210 01211 01212 01213 protected: 01214 01215 01217 virtual void deleteViews() ; 01218 01219 01221 std::list<const BaseView *> _views ; 01222 01223 01224 01225 private: 01226 01227 01235 MultipleViewModel( const MultipleViewModel & source ) ; 01236 01237 01245 MultipleViewModel & operator = ( 01246 const MultipleViewModel & source ) ; 01247 01248 01249 } ; 01250 01251 01252 01253 01254 01255 01256 01257 // SingleControllerNoViewGenericModel templated class. 01258 01259 01260 01273 template <typename ActualController> 01274 class SingleControllerNoViewGenericModel: public BaseModel 01275 { 01276 01277 01278 public: 01279 01280 01281 01295 explicit SingleControllerNoViewGenericModel( 01296 const ActualController & controller ) ; 01297 01298 01299 01310 SingleControllerNoViewGenericModel() ; 01311 01312 01313 01318 virtual ~SingleControllerNoViewGenericModel() throw() ; 01319 01320 01321 01333 virtual const std::string toString( 01334 Ceylan::VerbosityLevels level = Ceylan::high ) const ; 01335 01336 01337 01338 protected: 01339 01340 01349 const ActualController * _controller ; 01350 01351 01352 01353 private: 01354 01355 01363 SingleControllerNoViewGenericModel( 01364 const SingleControllerNoViewGenericModel & source ) ; 01365 01366 01374 SingleControllerNoViewGenericModel & operator = ( 01375 const SingleControllerNoViewGenericModel & source ) ; 01376 01377 01378 } ; 01379 01380 01381 01382 /* 01383 * Implementation of the SingleControllerNoViewGenericModel templated 01384 * class. 01385 * 01386 */ 01387 01388 01389 template <typename ActualController> 01390 SingleControllerNoViewGenericModel<ActualController>::SingleControllerNoViewGenericModel( const ActualController & controller ) : 01391 _controller( & controller ) 01392 { 01393 01394 } 01395 01396 01397 01398 template <typename ActualController> 01399 SingleControllerNoViewGenericModel<ActualController>::SingleControllerNoViewGenericModel() : 01400 _controller( 0 ) 01401 { 01402 01403 } 01404 01405 01406 01407 template <typename ActualController> 01408 SingleControllerNoViewGenericModel<ActualController>::~SingleControllerNoViewGenericModel() throw() 01409 { 01410 01411 if ( _controller != 0 ) 01412 { 01413 01414 // Controller owned here: 01415 delete _controller ; 01416 01417 } 01418 01419 } 01420 01421 01422 01423 template <typename ActualController> 01424 const std::string 01425 SingleControllerNoViewGenericModel<ActualController>::toString( 01426 Ceylan::VerbosityLevels level ) const 01427 { 01428 01429 if ( _controller != 0 ) 01430 { 01431 01432 /* 01433 * Beware to infinite recursion: 01434 * (the controller may display in turn this model) 01435 * 01436 */ 01437 01438 if ( level == Ceylan::low ) 01439 return "Single-controller view-less generic model " 01440 "owning a view" ; 01441 else 01442 return "Single-controller view-less generic model " 01443 "associated to " + _controller->toString( level ) ; 01444 01445 } 01446 else 01447 return "Single-controller view-less generic model " 01448 "not associated to any controller" ; 01449 01450 } 01451 01452 01453 01454 } // MVC namespace 01455 01456 01457 } // Ceylan namespace 01458 01459 01460 01461 #endif // CEYLAN_GENERIC_MODEL_H_ 01462