1 /* 2 * 3 * Copyright (C) 1998-2017, OFFIS e.V. 4 * All rights reserved. See COPYRIGHT file for details. 5 * 6 * This software and supporting documentation were developed by 7 * 8 * OFFIS e.V. 9 * R&D Division Health 10 * Escherweg 2 11 * D-26121 Oldenburg, Germany 12 * 13 * 14 * Module: dcmpstat 15 * 16 * Author: Joerg Riesmeier 17 * 18 * Purpose: Classes for caching of the image database (Header/Source) 19 * 20 */ 21 22 23 #ifndef DVCACHE_H 24 #define DVCACHE_H 25 26 #include "dcmtk/config/osconfig.h" 27 28 #include "dcmtk/ofstd/oflist.h" 29 #include "dcmtk/ofstd/ofstring.h" 30 #include "dcmtk/dcmqrdb/dcmqrdbi.h" /* for DVIFhierarchyStatus */ 31 32 33 /*--------------------* 34 * type definitions * 35 *--------------------*/ 36 37 /** describes the different types of instances stored in the database 38 */ 39 enum DVPSInstanceType 40 { 41 /// image object 42 DVPSI_image, 43 /// presentation state object 44 DVPSI_presentationState, 45 /// structured reporting document 46 DVPSI_structuredReport, 47 /// stored print object 48 DVPSI_storedPrint, 49 /// hardcopy grayscale object 50 DVPSI_hardcopyGrayscale 51 }; 52 53 54 /*---------------------* 55 * class declaration * 56 *---------------------*/ 57 58 /** A class to handle an instance cache (list of items). 59 * This is the lowest level in the hierarchical cache structure. 60 * Images are handled as well as presentation states. This class 61 * is used by DVSeriesCache. 62 */ 63 class DCMTK_DCMPSTAT_EXPORT DVInstanceCache 64 { 65 66 public: 67 68 /** Internal structure defining the list items. 69 */ 70 struct DCMTK_DCMPSTAT_EXPORT ItemStruct 71 { 72 /** Constructor. 73 * sets internal member variables. 74 * 75 ** @param uid unique identifier 76 * @param pos file position in index file 77 * @param status review status 78 * @param type type of instance 79 * @param size image size (in bytes) 80 * @param filename filename of instance 81 */ ItemStructItemStruct82 ItemStruct(const OFString &uid, 83 const int pos, 84 const DVIFhierarchyStatus status, 85 const DVPSInstanceType type, 86 const int size, 87 const OFString &filename) 88 : UID(uid), 89 Pos(pos), 90 Status(status), 91 Type(type), 92 ImageSize(size), 93 Filename(filename), 94 Checked(OFFalse), 95 Description(), 96 Label(), 97 List() 98 {} 99 100 /// instance UID 101 OFString UID; 102 /// position in the index file 103 int Pos; 104 /// review status 105 DVIFhierarchyStatus Status; 106 /// type of instance 107 DVPSInstanceType Type; 108 /// image size (in bytes) 109 int ImageSize; 110 /// filename of instance 111 OFString Filename; 112 /// status flag to avoid double checking of referencing pstates 113 OFBool Checked; 114 /// instance description 115 OFString Description; 116 /// instance label 117 OFString Label; 118 /// list of referencing pstates 119 OFList<ItemStruct *> List; 120 }; 121 122 /** Constructor 123 */ DVInstanceCache()124 DVInstanceCache() 125 : List(), 126 Iterator(), 127 OldIterator() 128 { 129 Iterator = OldIterator = List.end(); 130 } 131 132 /** Destructor 133 */ ~DVInstanceCache()134 virtual ~DVInstanceCache() 135 { 136 clear(); 137 } 138 139 /** reset all member variables to initial state. 140 * delete all list items. 141 */ clear()142 inline void clear() 143 { 144 Iterator = List.begin(); 145 OFListIterator(ItemStruct *) last = List.end(); 146 while (Iterator != last) 147 { 148 delete (*Iterator); 149 Iterator = List.erase(Iterator); 150 } 151 List.clear(); 152 Iterator = OldIterator = List.end(); 153 } 154 155 /** checks whether instance cache is empty 156 * 157 ** @result OFTrue if cache is empty, OFFalse otherwise 158 */ empty()159 inline OFBool empty() const 160 { 161 return List.empty(); 162 } 163 164 /** gets number of cache entries 165 * 166 ** @return number of cache entries 167 */ getCount()168 inline Uint32 getCount() const 169 { 170 return OFstatic_cast(Uint32, List.size()); 171 } 172 173 /** sets internal cursor to specified position in cache list 174 * 175 ** @param idx index position in cache list (starting with 0) 176 * 177 ** @return OFTrue if successful, OFFalse if 'idx' is invalid 178 */ gotoItem(Uint32 idx)179 inline OFBool gotoItem(Uint32 idx) 180 { 181 OFBool result = OFFalse; 182 Iterator = List.begin(); 183 OFListIterator(ItemStruct *) last = List.end(); 184 while (Iterator != last) 185 { 186 if (idx == 0) 187 { 188 result = OFTrue; 189 break; 190 } 191 idx--; 192 ++Iterator; 193 } 194 return result; 195 } 196 197 /** sets internal cursor to first position in cache list 198 * 199 ** @return OFTrue if successful, OFFalse if list is empty 200 */ gotoFirst()201 inline OFBool gotoFirst() 202 { 203 OldIterator = Iterator; 204 Iterator = List.begin(); 205 return (Iterator != List.end()); 206 } 207 208 /** sets internal cursor to next position in cache list 209 * 210 ** @return OFTrue if successful, OFFalse if new position is invalid 211 */ gotoNext()212 inline OFBool gotoNext() 213 { 214 OFListIterator(ItemStruct *) last = List.end(); 215 if (Iterator != last) 216 Iterator++; 217 return (Iterator != last); 218 } 219 220 /** sets internal cursor to last visited position in cache list 221 * 222 ** @return OFTrue if successful, 223 * OFFalse if last visited position was invalid or the last one in the list 224 */ reset()225 inline OFBool reset() 226 { 227 OFBool result = OFFalse; 228 OFListIterator(ItemStruct *) last = List.end(); 229 if (OldIterator != last) 230 { 231 Iterator = OldIterator; 232 OldIterator = last; 233 result = OFTrue; 234 } 235 return result; 236 } 237 238 /** checks whether an item with the specified UID exists in the cache list 239 * 240 ** @param uid UID which should be checked 241 * 242 ** @return OFTrue if such an item exists, OFFalse otherwise 243 */ isElem(const OFString & uid)244 inline OFBool isElem(const OFString &uid) 245 { 246 OFBool result = OFFalse; 247 Iterator = List.begin(); 248 OFListIterator(ItemStruct *) last = List.end(); 249 while (Iterator != last) 250 { 251 const ItemStruct *item = (*Iterator); 252 if (item != NULL) 253 { 254 if (item->UID == uid) 255 { 256 result = OFTrue; 257 break; 258 } 259 } 260 ++Iterator; 261 } 262 return result; 263 } 264 265 /** gets the file position of the current (selected) instance 266 * 267 ** @return file position if successful, 0 otherwise 268 */ getPos()269 inline int getPos() const 270 { 271 const ItemStruct *item = getItem(); 272 return (item != NULL) ? item->Pos : 0; 273 } 274 275 /** gets review status of the current (selected) instance 276 * 277 ** @return hierarchical status code if successful, 'isNew' otherwise 278 */ getStatus()279 inline DVIFhierarchyStatus getStatus() const 280 { 281 const ItemStruct *item = getItem(); 282 return (item != NULL) ? item->Status : DVIF_objectIsNew; 283 } 284 285 /** gets type of the instance 286 * 287 ** @return type of instance 288 */ getType()289 inline DVPSInstanceType getType() const 290 { 291 const ItemStruct *item = getItem(); 292 return (item != NULL) ? item->Type : DVPSI_image; 293 } 294 295 /** gets image size of current (selected) instance 296 * 297 ** @return image size in bytes if successful, 0 otherwise 298 */ getImageSize()299 inline int getImageSize() const 300 { 301 const ItemStruct *item = getItem(); 302 return (item != NULL) ? item->ImageSize : 0; 303 } 304 305 /** gets filename of current (selected) instance 306 * 307 ** @return filename if successful, NULL otherwise 308 */ getFilename()309 inline const char *getFilename() const 310 { 311 const ItemStruct *item = getItem(); 312 return (item != NULL) ? item->Filename.c_str() : (const char *)NULL; 313 } 314 315 /** gets reference to current (selected) instance 316 * 317 ** @return pointer to ItemStruct if successful, NULL otherwise 318 */ getItem()319 inline ItemStruct *getItem() const 320 { 321 OFListConstIterator(ItemStruct *) it = Iterator; 322 return (it != List.end()) ? (*Iterator) : (ItemStruct *)NULL; 323 } 324 325 /** adds a new item to the cache list. 326 * sets internal cursor to new position. 327 * 328 ** @param uid unique identifier 329 * @param pos file position in index file 330 * @param status review status 331 * @param type type of instance 332 * @param size image size (in bytes) 333 * @param filename filename of instance 334 */ addItem(const OFString & uid,const int pos,const DVIFhierarchyStatus status,const DVPSInstanceType type,const int size,const OFString & filename)335 inline void addItem(const OFString &uid, 336 const int pos, 337 const DVIFhierarchyStatus status, 338 const DVPSInstanceType type, 339 const int size, 340 const OFString &filename) 341 { 342 ItemStruct *item = new ItemStruct(uid, pos, status, type, size, filename); 343 List.push_back(item); 344 Iterator = --List.end(); // set to new position 345 } 346 347 /** updates hierarchical/review status for all list items. 348 * 349 ** @return resulting review status (summary of all items) 350 */ updateStatus()351 inline DVIFhierarchyStatus updateStatus() 352 { 353 OFListIterator(ItemStruct *) first = List.begin(); 354 OFListIterator(ItemStruct *) last = List.end(); 355 OFListIterator(ItemStruct *) iter = first; 356 DVIFhierarchyStatus status = DVIF_objectIsNew; 357 while (iter != last) 358 { 359 ItemStruct *item = (*iter); 360 if (item != NULL) 361 { 362 switch (item->Status) 363 { 364 case DVIF_objectIsNew: 365 if (status == DVIF_objectIsNotNew) 366 status = DVIF_objectContainsNewSubobjects; 367 break; 368 case DVIF_objectIsNotNew: 369 case DVIF_objectContainsNewSubobjects: 370 if (iter == first) 371 status = DVIF_objectIsNotNew; 372 else if (status == DVIF_objectIsNew) 373 status = DVIF_objectContainsNewSubobjects; 374 break; 375 } 376 } 377 ++iter; 378 } 379 return status; 380 } 381 382 383 protected: 384 385 /// list of instances 386 OFList<ItemStruct *> List; 387 /// internal cursor to current (selected) list item 388 OFListIterator(ItemStruct *) Iterator; 389 /// last visited position in item list 390 OFListIterator(ItemStruct *) OldIterator; 391 }; 392 393 394 /* ------------------------------ */ 395 396 397 /** A class to handle a series cache (list of items). 398 * This is the middle level in the hierarchical cache structure. 399 * This class is used by DVStudyCache. The internal structure 400 * is a list of DVInstanceCache. 401 */ 402 class DCMTK_DCMPSTAT_EXPORT DVSeriesCache 403 { 404 405 public: 406 407 /** Internal structure defining the list items. 408 */ 409 struct DCMTK_DCMPSTAT_EXPORT ItemStruct 410 { 411 /** Constructor. 412 * sets internal member variables. 413 * 414 ** @param uid unique identifier 415 * @param status review status (optional) 416 * @param type type of series 417 */ 418 ItemStruct(const OFString &uid, 419 const DVIFhierarchyStatus status = DVIF_objectIsNew, 420 const DVPSInstanceType type = DVPSI_image) UIDItemStruct421 : UID(uid), 422 Status(status), 423 Type(type), 424 List() 425 {} 426 427 /// instance UID 428 OFString UID; 429 /// review status for the series 430 DVIFhierarchyStatus Status; 431 /// type of all instances within this series 432 DVPSInstanceType Type; 433 /// list of instances within this series 434 DVInstanceCache List; 435 }; 436 437 /** Constructor. 438 */ DVSeriesCache()439 DVSeriesCache() 440 : List(), 441 Iterator(), 442 OldIterator() 443 { 444 Iterator = OldIterator = List.end(); 445 } 446 447 /** Destructor 448 */ ~DVSeriesCache()449 virtual ~DVSeriesCache() 450 { 451 clear(); 452 } 453 454 /** reset all member variables to initial state 455 * delete all list items. 456 */ clear()457 inline void clear() 458 { 459 Iterator = List.begin(); 460 OFListIterator(ItemStruct *) last = List.end(); 461 while (Iterator != last) 462 { 463 delete (*Iterator); 464 Iterator = List.erase(Iterator); 465 } 466 List.clear(); 467 Iterator = OldIterator = List.end(); 468 } 469 470 /** checks whether instance cache is empty 471 * 472 ** @return OFTrue if cache is empty, OFFalse otherwise 473 */ empty()474 inline OFBool empty() const 475 { 476 return List.empty(); 477 } 478 479 /** gets number of cache entries 480 * 481 ** @return number of cache entries 482 */ getCount()483 inline Uint32 getCount() const 484 { 485 return OFstatic_cast(Uint32, List.size()); 486 } 487 488 /** sets internal cursor to specified position in cache list 489 * 490 ** @param idx index position in cache list (starting with 0) 491 * 492 ** @return OFTrue if successful, OFFalse if 'idx' is invalid 493 */ gotoItem(Uint32 idx)494 inline OFBool gotoItem(Uint32 idx) 495 { 496 OFBool result = OFFalse; 497 Iterator = List.begin(); 498 OFListIterator(ItemStruct *) last = List.end(); 499 while (Iterator != last) 500 { 501 if (idx == 0) 502 { 503 result = OFTrue; 504 break; 505 } 506 idx--; 507 ++Iterator; 508 } 509 return result; 510 } 511 512 /** sets internal cursor to first position in cache list 513 * 514 ** @return OFTrue if successful, OFFalse if list is empty 515 */ gotoFirst()516 inline OFBool gotoFirst() 517 { 518 OldIterator = Iterator; 519 Iterator = List.begin(); 520 return (Iterator != List.end()); 521 } 522 523 /** sets internal cursor to next position in cache list 524 * 525 ** @return OFTrue if successful, OFFalse if new position is invalid 526 */ gotoNext()527 inline OFBool gotoNext() 528 { 529 OFListIterator(ItemStruct *) last = List.end(); 530 if (Iterator != last) 531 Iterator++; 532 return (Iterator != last); 533 } 534 535 /** sets internal cursor to last visited position in cache list 536 * 537 ** @return OFTrue if successful, 538 * OFFalse if last visited position was invalid or the last one in the list 539 */ reset()540 inline OFBool reset() 541 { 542 OFBool result = OFFalse; 543 OFListIterator(ItemStruct *) last = List.end(); 544 if (OldIterator != last) 545 { 546 Iterator = OldIterator; 547 OldIterator = last; 548 result = OFTrue; 549 } 550 return result; 551 } 552 553 /** checks whether an item with the specified UID exists in the cache list 554 * 555 ** @param uid UID which should be checked 556 * 557 ** @return OFTrue if such an item exists, OFFalse otherwise 558 */ isElem(const OFString & uid)559 inline OFBool isElem(const OFString &uid) 560 { 561 OFBool result = OFFalse; 562 Iterator = List.begin(); 563 OFListIterator(ItemStruct *) last = List.end(); 564 while (Iterator != last) 565 { 566 const ItemStruct *item = (*Iterator); 567 if (item != NULL) 568 { 569 if (item->UID == uid) 570 { 571 result = OFTrue; 572 break; 573 } 574 } 575 ++Iterator; 576 } 577 return result; 578 } 579 580 /** gets review status of the current (selected) series 581 * 582 ** @return hierarchical status code if successful, 'isNew' otherwise 583 */ getStatus()584 inline DVIFhierarchyStatus getStatus() const 585 { 586 const ItemStruct *item = getItem(); 587 return (item != NULL) ? item->Status : DVIF_objectIsNew; 588 } 589 590 /** gets type of all instances in the series 591 * 592 ** @return type of all instances 593 */ getType()594 inline DVPSInstanceType getType() const 595 { 596 const ItemStruct *item = getItem(); 597 return (item != NULL) ? item->Type : DVPSI_image; 598 } 599 600 /** gets reference to current (selected) series 601 * 602 ** @return pointer to ItemStruct if successful, NULL otherwise 603 */ getItem()604 inline ItemStruct *getItem() const 605 { 606 OFListConstIterator(ItemStruct *) it = Iterator; 607 return (it != List.end()) ? (*Iterator) : (ItemStruct *)NULL; 608 } 609 610 /** adds a new item to the cache list. 611 * sets internal cursor to new position. 612 * 613 ** @param uid unique identifier 614 * @param status review status (optional) 615 */ 616 inline void addItem(const OFString &uid, 617 const DVIFhierarchyStatus status = DVIF_objectIsNew) 618 { 619 ItemStruct *item = new ItemStruct(uid, status); 620 List.push_back(item); 621 Iterator = --List.end(); // set to new position 622 } 623 624 /** updates hierarchical/review status for all list items. 625 * 626 ** @return resulting review status (summary of all items) 627 */ updateStatus()628 inline DVIFhierarchyStatus updateStatus() 629 { 630 OFListIterator(ItemStruct *) first = List.begin(); 631 OFListIterator(ItemStruct *) last = List.end(); 632 OFListIterator(ItemStruct *) iter = first; 633 DVIFhierarchyStatus status = DVIF_objectIsNew; 634 while (iter != last) 635 { 636 ItemStruct *item = (*iter); 637 if (item != NULL) 638 { 639 item->Status = item->List.updateStatus(); 640 switch (item->Status) 641 { 642 case DVIF_objectIsNew: 643 if (status == DVIF_objectIsNotNew) 644 status = DVIF_objectContainsNewSubobjects; 645 break; 646 case DVIF_objectIsNotNew: 647 if (iter == first) 648 status = DVIF_objectIsNotNew; 649 else if (status == DVIF_objectIsNew) 650 status = DVIF_objectContainsNewSubobjects; 651 break; 652 case DVIF_objectContainsNewSubobjects: 653 status = DVIF_objectContainsNewSubobjects; 654 break; 655 } 656 } 657 ++iter; 658 } 659 return status; 660 } 661 662 663 protected: 664 665 /// list of series 666 OFList<ItemStruct *> List; 667 /// internal cursor to current (selected) list item 668 OFListIterator(ItemStruct *) Iterator; 669 /// last visited position in item list 670 OFListIterator(ItemStruct *) OldIterator; 671 }; 672 673 674 /* ------------------------------ */ 675 676 677 /** A class to handle a study cache (list of items). 678 * This is the highest level in the hierarchical cache structure. 679 * This class is used by DVInterface. The internal structure 680 * is a list of DVSeriesCache. 681 */ 682 class DCMTK_DCMPSTAT_EXPORT DVStudyCache 683 { 684 685 public: 686 687 /** Internal structure defining the list items. 688 */ 689 struct DCMTK_DCMPSTAT_EXPORT ItemStruct 690 { 691 /** Constructor. 692 * sets internal member variables. 693 * 694 ** @param uid unique identifier 695 * @param status review status (optional) 696 */ 697 ItemStruct(const OFString &uid, 698 const DVIFhierarchyStatus status = DVIF_objectIsNew) UIDItemStruct699 : UID(uid), 700 Status(status), 701 List() 702 {} 703 704 /// instance UID 705 OFString UID; 706 /// review status for the series 707 DVIFhierarchyStatus Status; 708 /// list of series within this study 709 DVSeriesCache List; 710 }; 711 712 /** Constructor. 713 */ DVStudyCache()714 DVStudyCache() 715 : List(), 716 Iterator() 717 { 718 Iterator = List.end(); 719 } 720 721 /** Destructor 722 */ ~DVStudyCache()723 virtual ~DVStudyCache() 724 { 725 clear(); 726 } 727 728 /** reset all member variables to initial state 729 * delete all list items. 730 */ clear()731 inline void clear() 732 { 733 Iterator = List.begin(); 734 OFListIterator(ItemStruct *) last = List.end(); 735 while (Iterator != last) 736 { 737 delete (*Iterator); 738 Iterator = List.erase(Iterator); 739 } 740 List.clear(); 741 Iterator = List.end(); 742 } 743 744 /** checks whether study cache is empty 745 * 746 ** @return OFTrue if cache is empty, OFFalse otherwise 747 */ empty()748 inline OFBool empty() const 749 { 750 return List.empty(); 751 } 752 753 /** gets number of cache entries 754 * 755 ** @return number of cache entries 756 */ getCount()757 inline Uint32 getCount() const 758 { 759 return OFstatic_cast(Uint32, List.size()); 760 } 761 762 /** sets internal cursor to specified position in cache list 763 * 764 ** @param idx index position in cache list (starting with 0) 765 * 766 ** @return OFTrue if successful, OFFalse if 'idx' is invalid 767 */ gotoItem(Uint32 idx)768 inline OFBool gotoItem(Uint32 idx) 769 { 770 OFBool result = OFFalse; 771 Iterator = List.begin(); 772 OFListIterator(ItemStruct *) last = List.end(); 773 while (Iterator != last) 774 { 775 if (idx == 0) 776 { 777 result = OFTrue; 778 break; 779 } 780 idx--; 781 ++Iterator; 782 } 783 return result; 784 } 785 786 /** sets internal cursor to first position in cache list 787 * 788 ** @return OFTrue if successful, OFFalse if list is empty 789 */ gotoFirst()790 inline OFBool gotoFirst() 791 { 792 //OldIterator = Iterator; 793 Iterator = List.begin(); 794 return (Iterator != List.end()); 795 } 796 797 /** sets internal cursor to next position in cache list 798 * 799 ** @return OFTrue if successful, OFFalse if new position is invalid 800 */ gotoNext()801 inline OFBool gotoNext() 802 { 803 OFListIterator(ItemStruct *) last = List.end(); 804 if (Iterator != last) 805 Iterator++; 806 return (Iterator != last); 807 } 808 809 /** checks whether an item with the specified UID exists in the cache list 810 * 811 ** @param uid UID which should be checked 812 * 813 ** @return OFTrue if such an item exists, OFFalse otherwise 814 */ isElem(const OFString & uid)815 inline OFBool isElem(const OFString &uid) 816 { 817 OFBool result = OFFalse; 818 Iterator = List.begin(); 819 OFListIterator(ItemStruct *) last = List.end(); 820 while (Iterator != last) 821 { 822 const ItemStruct *item = (*Iterator); 823 if (item != NULL) 824 { 825 if (item->UID == uid) 826 { 827 result= OFTrue; 828 break; 829 } 830 } 831 ++Iterator; 832 } 833 return result; 834 } 835 836 /** gets review status of the current (selected) sstudy 837 * 838 ** @return hierarchical status code if successful, 'isNew' otherwise 839 */ getStatus()840 inline DVIFhierarchyStatus getStatus() const 841 { 842 const ItemStruct *item = getItem(); 843 return (item != NULL) ? item->Status : DVIF_objectIsNew; 844 } 845 846 /** gets reference to current (selected) study 847 * 848 ** @return pointer to ItemStruct if successful, NULL otherwise 849 */ getItem()850 inline ItemStruct *getItem() const 851 { 852 OFListConstIterator(ItemStruct *) it = Iterator; 853 return (it != List.end()) ? (*Iterator) : (ItemStruct *)NULL; 854 } 855 856 /** adds a new item to the cache list. 857 * sets internal cursor to new position. 858 * 859 ** @param uid unique identifier 860 * @param status review status (optional) 861 */ 862 inline void addItem(const OFString &uid, 863 const DVIFhierarchyStatus status = DVIF_objectIsNew) 864 { 865 ItemStruct *item = new ItemStruct(uid, status); 866 List.push_back(item); 867 Iterator = --List.end(); // set to new position 868 } 869 870 /** updates hierarchical/review status for all list items. 871 * 872 ** @return resulting review status (summary of all items) 873 */ updateStatus()874 inline void updateStatus() 875 { 876 OFListIterator(ItemStruct *) iter = List.begin(); 877 OFListIterator(ItemStruct *) last = List.end(); 878 while (iter != last) 879 { 880 ItemStruct *item = (*iter); 881 if (item != NULL) 882 item->Status = item->List.updateStatus(); 883 ++iter; 884 } 885 } 886 887 888 protected: 889 890 /// list of studies 891 OFList<ItemStruct *> List; 892 /// internal cursor to current (selected) list item 893 OFListIterator(ItemStruct *) Iterator; 894 }; 895 896 897 #endif 898