1 /* 2 * "GEDKeeper", the personal genealogical database editor. 3 * Copyright (C) 2009-2021 by Sergey V. Zhdanovskih. 4 * 5 * This file is part of "GEDKeeper". 6 * 7 * This program is free software: you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation, either version 3 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 using GDModel; 22 23 namespace GKCore.Operations 24 { 25 public enum OperationType 26 { 27 otNOP, 28 29 otIndividualParentsAttach, 30 otIndividualParentsDetach, 31 32 otFamilySpouseAttach, 33 otFamilySpouseDetach, 34 35 otGroupMemberAttach, 36 otGroupMemberDetach, 37 38 otSourceRepositoryCitationAdd, 39 otSourceRepositoryCitationRemove, 40 41 otResearchTaskAdd, 42 otResearchTaskRemove, 43 otResearchCommunicationAdd, 44 otResearchCommunicationRemove, 45 otResearchGroupAdd, 46 otResearchGroupRemove, 47 48 otRecordNoteAdd, 49 otRecordNoteRemove, 50 51 otRecordMediaAdd, 52 otRecordMediaRemove, 53 54 otRecordSourceCitAdd, 55 otRecordSourceCitRemove, 56 57 otRecordEventAdd, 58 otRecordEventRemove, 59 60 otIndividualAssociationAdd, 61 otIndividualAssociationRemove, 62 63 otIndividualNameAdd, 64 otIndividualNameRemove, 65 66 otIndividualURefAdd, 67 otIndividualURefRemove, 68 69 otIndividualPortraitAttach, 70 otIndividualPortraitDetach, 71 72 otIndividualBookmarkChange, 73 otIndividualPatriarchChange, 74 otIndividualSexChange 75 } 76 77 /// <summary> 78 /// Processing operations of change one of the properties of the records. 79 /// </summary> 80 public class OrdinaryOperation : CustomOperation 81 { 82 private readonly OperationType fType; 83 private readonly GDMObject fObj; 84 private object fOldVal; 85 private readonly object fNewVal; 86 OrdinaryOperation(UndoManager manager, OperationType type, GDMObject obj, object newVal)87 public OrdinaryOperation(UndoManager manager, OperationType type, 88 GDMObject obj, object newVal) : base(manager) 89 { 90 fType = type; 91 fObj = obj; 92 fNewVal = newVal; 93 } 94 Redo()95 public override bool Redo() 96 { 97 return ProcessOperation(true); 98 } 99 Undo()100 public override void Undo() 101 { 102 ProcessOperation(false); 103 } 104 ProcessOperation(bool redo)105 private bool ProcessOperation(bool redo) 106 { 107 bool result; 108 109 switch (fType) { 110 case OperationType.otNOP: 111 result = false; 112 break; 113 114 case OperationType.otIndividualParentsAttach: 115 case OperationType.otIndividualParentsDetach: 116 result = ProcessIndividualParents(redo); 117 break; 118 119 case OperationType.otFamilySpouseAttach: 120 case OperationType.otFamilySpouseDetach: 121 result = ProcessFamilySpouse(redo); 122 break; 123 124 case OperationType.otGroupMemberAttach: 125 case OperationType.otGroupMemberDetach: 126 result = ProcessGroupMember(redo); 127 break; 128 129 case OperationType.otSourceRepositoryCitationAdd: 130 case OperationType.otSourceRepositoryCitationRemove: 131 result = ProcessSourceRepositoryCitation(redo); 132 break; 133 134 135 case OperationType.otResearchTaskAdd: 136 case OperationType.otResearchTaskRemove: 137 result = ProcessResearchTask(redo); 138 break; 139 140 case OperationType.otResearchCommunicationAdd: 141 case OperationType.otResearchCommunicationRemove: 142 result = ProcessResearchCommunication(redo); 143 break; 144 145 case OperationType.otResearchGroupAdd: 146 case OperationType.otResearchGroupRemove: 147 result = ProcessResearchGroup(redo); 148 break; 149 150 case OperationType.otRecordNoteAdd: 151 result = ProcessRecordNoteAdd(redo); 152 break; 153 154 case OperationType.otRecordNoteRemove: 155 result = ProcessRecordNoteRemove(redo); 156 break; 157 158 case OperationType.otRecordMediaAdd: 159 result = ProcessRecordMediaAdd(redo); 160 break; 161 162 case OperationType.otRecordMediaRemove: 163 result = ProcessRecordMediaRemove(redo); 164 break; 165 166 case OperationType.otRecordSourceCitAdd: 167 case OperationType.otRecordSourceCitRemove: 168 result = ProcessRecordSourceCit(redo); 169 break; 170 171 case OperationType.otRecordEventAdd: 172 case OperationType.otRecordEventRemove: 173 result = ProcessRecordEvent(redo); 174 break; 175 176 case OperationType.otIndividualAssociationAdd: 177 case OperationType.otIndividualAssociationRemove: 178 result = ProcessIndividualAssociation(redo); 179 break; 180 181 case OperationType.otIndividualNameAdd: 182 case OperationType.otIndividualNameRemove: 183 result = ProcessIndividualName(redo); 184 break; 185 186 case OperationType.otIndividualURefAdd: 187 case OperationType.otIndividualURefRemove: 188 result = ProcessIndividualURef(redo); 189 break; 190 191 case OperationType.otIndividualPortraitAttach: 192 case OperationType.otIndividualPortraitDetach: 193 result = ProcessIndividualPortrait(redo); 194 break; 195 196 case OperationType.otIndividualBookmarkChange: 197 result = ProcessIndividualBookmarkChange(redo); 198 break; 199 200 case OperationType.otIndividualPatriarchChange: 201 result = ProcessIndividualPatriarchChange(redo); 202 break; 203 204 case OperationType.otIndividualSexChange: 205 result = ProcessIndividualSexChange(redo); 206 break; 207 208 default: 209 result = false; 210 break; 211 } 212 213 return result; 214 } 215 ProcessIndividualParents(bool redo)216 private bool ProcessIndividualParents(bool redo) 217 { 218 GDMIndividualRecord iRec = fObj as GDMIndividualRecord; 219 GDMFamilyRecord familyRec = fNewVal as GDMFamilyRecord; 220 221 if (iRec == null || familyRec == null) { 222 return false; 223 } 224 225 if (fType == OperationType.otIndividualParentsDetach) { 226 redo = !redo; 227 } 228 if (redo) { 229 familyRec.AddChild(iRec); 230 } else { 231 familyRec.RemoveChild(iRec); 232 } 233 return true; 234 } 235 ProcessFamilySpouse(bool redo)236 private bool ProcessFamilySpouse(bool redo) 237 { 238 GDMFamilyRecord famRec = fObj as GDMFamilyRecord; 239 GDMIndividualRecord spouseRec = fNewVal as GDMIndividualRecord; 240 241 if (famRec == null || spouseRec == null) { 242 return false; 243 } 244 245 if (fType == OperationType.otFamilySpouseDetach) { 246 redo = !redo; 247 } 248 if (redo) { 249 famRec.AddSpouse(spouseRec); 250 } else { 251 famRec.RemoveSpouse(spouseRec); 252 } 253 return true; 254 } 255 ProcessGroupMember(bool redo)256 private bool ProcessGroupMember(bool redo) 257 { 258 GDMGroupRecord grpRec = fObj as GDMGroupRecord; 259 GDMIndividualRecord mbrRec = fNewVal as GDMIndividualRecord; 260 261 if (grpRec == null || mbrRec == null) { 262 return false; 263 } 264 265 if (fType == OperationType.otGroupMemberDetach) { 266 redo = !redo; 267 } 268 if (redo) { 269 grpRec.AddMember(mbrRec); 270 } else { 271 grpRec.RemoveMember(mbrRec); 272 } 273 return true; 274 } 275 ProcessSourceRepositoryCitation(bool redo)276 private bool ProcessSourceRepositoryCitation(bool redo) 277 { 278 GDMSourceRecord srcRec = fObj as GDMSourceRecord; 279 GDMRepositoryRecord repRec = fNewVal as GDMRepositoryRecord; 280 281 if (srcRec == null || repRec == null) { 282 return false; 283 } 284 285 if (fType == OperationType.otSourceRepositoryCitationRemove) { 286 redo = !redo; 287 } 288 if (redo) { 289 srcRec.AddRepository(repRec); 290 } else { 291 srcRec.RemoveRepository(repRec); 292 } 293 return true; 294 } 295 ProcessResearchTask(bool redo)296 private bool ProcessResearchTask(bool redo) 297 { 298 GDMResearchRecord resRec = fObj as GDMResearchRecord; 299 GDMTaskRecord taskRec = fNewVal as GDMTaskRecord; 300 301 if (resRec == null || taskRec == null) { 302 return false; 303 } 304 305 if (fType == OperationType.otResearchTaskRemove) { 306 redo = !redo; 307 } 308 if (redo) { 309 resRec.AddTask(taskRec); 310 } else { 311 resRec.RemoveTask(taskRec); 312 } 313 return true; 314 } 315 ProcessResearchCommunication(bool redo)316 private bool ProcessResearchCommunication(bool redo) 317 { 318 GDMResearchRecord resRec = fObj as GDMResearchRecord; 319 GDMCommunicationRecord commRec = fNewVal as GDMCommunicationRecord; 320 321 if (resRec == null || commRec == null) { 322 return false; 323 } 324 325 if (fType == OperationType.otResearchCommunicationRemove) { 326 redo = !redo; 327 } 328 if (redo) { 329 resRec.AddCommunication(commRec); 330 } else { 331 resRec.RemoveCommunication(commRec); 332 } 333 return true; 334 } 335 ProcessResearchGroup(bool redo)336 private bool ProcessResearchGroup(bool redo) 337 { 338 GDMResearchRecord resRec = fObj as GDMResearchRecord; 339 GDMGroupRecord grpRec = fNewVal as GDMGroupRecord; 340 341 if (resRec == null || grpRec == null) { 342 return false; 343 } 344 345 if (fType == OperationType.otResearchGroupRemove) { 346 redo = !redo; 347 } 348 if (redo) { 349 resRec.AddGroup(grpRec); 350 } else { 351 resRec.RemoveGroup(grpRec); 352 } 353 return true; 354 } 355 ProcessRecordNoteAdd(bool redo)356 private bool ProcessRecordNoteAdd(bool redo) 357 { 358 var swl = fObj as IGDMStructWithNotes; 359 GDMNoteRecord noteRec = fNewVal as GDMNoteRecord; 360 361 bool result = (swl != null && noteRec != null); 362 if (result) { 363 if (redo) { 364 GDMNotes notes = swl.AddNote(noteRec); 365 fOldVal = notes; 366 } else { 367 GDMNotes notes = fOldVal as GDMNotes; 368 swl.Notes.Delete(notes); 369 } 370 } 371 return result; 372 } 373 ProcessRecordNoteRemove(bool redo)374 private bool ProcessRecordNoteRemove(bool redo) 375 { 376 var swl = fObj as IGDMStructWithNotes; 377 GDMNotes notes = fNewVal as GDMNotes; 378 379 bool result = (swl != null && notes != null); 380 if (result) { 381 if (redo) { 382 swl.Notes.Extract(notes); // bugfix(no delete!) 383 } else { 384 swl.Notes.Add(notes); 385 } 386 } 387 return result; 388 } 389 ProcessRecordMediaAdd(bool redo)390 private bool ProcessRecordMediaAdd(bool redo) 391 { 392 var swl = fObj as IGDMStructWithMultimediaLinks; 393 GDMMultimediaRecord mediaRec = fNewVal as GDMMultimediaRecord; 394 395 bool result = (swl != null && mediaRec != null); 396 if (result) { 397 if (redo) { 398 GDMMultimediaLink mmLink = swl.AddMultimedia(mediaRec); 399 fOldVal = mmLink; 400 } else { 401 GDMMultimediaLink mmLink = fOldVal as GDMMultimediaLink; 402 swl.MultimediaLinks.Delete(mmLink); 403 } 404 } 405 return result; 406 } 407 ProcessRecordMediaRemove(bool redo)408 private bool ProcessRecordMediaRemove(bool redo) 409 { 410 var swl = fObj as IGDMStructWithMultimediaLinks; 411 GDMMultimediaLink mediaLink = fNewVal as GDMMultimediaLink; 412 413 bool result = (swl != null && mediaLink != null); 414 if (result) { 415 if (redo) { 416 swl.MultimediaLinks.Extract(mediaLink); // bugfix(no delete!) 417 } else { 418 swl.MultimediaLinks.Add(mediaLink); 419 } 420 } 421 return result; 422 } 423 ProcessRecordSourceCit(bool redo)424 private bool ProcessRecordSourceCit(bool redo) 425 { 426 var swl = fObj as IGDMStructWithSourceCitations; 427 GDMSourceCitation sourceCit = fNewVal as GDMSourceCitation; 428 429 if (swl == null || sourceCit == null) { 430 return false; 431 } 432 433 if (fType == OperationType.otRecordSourceCitRemove) { 434 redo = !redo; 435 } 436 if (redo) { 437 swl.SourceCitations.Add(sourceCit); 438 } else { 439 swl.SourceCitations.Extract(sourceCit); // bugfix(no delete!) 440 } 441 return true; 442 } 443 ProcessRecordEvent(bool redo)444 private bool ProcessRecordEvent(bool redo) 445 { 446 GDMRecordWithEvents rwe = fObj as GDMRecordWithEvents; 447 GDMCustomEvent evt = fNewVal as GDMCustomEvent; 448 449 if (rwe == null || evt == null) { 450 return false; 451 } 452 453 if (fType == OperationType.otRecordEventRemove) { 454 redo = !redo; 455 } 456 if (redo) { 457 rwe.AddEvent(evt); 458 } else { 459 rwe.Events.Extract(evt); // bugfix(no delete!) 460 } 461 return true; 462 } 463 ProcessIndividualAssociation(bool redo)464 private bool ProcessIndividualAssociation(bool redo) 465 { 466 GDMIndividualRecord iRec = fObj as GDMIndividualRecord; 467 GDMAssociation asso = fNewVal as GDMAssociation; 468 469 if (iRec == null || asso == null) { 470 return false; 471 } 472 473 if (fType == OperationType.otIndividualAssociationRemove) { 474 redo = !redo; 475 } 476 if (redo) { 477 iRec.Associations.Add(asso); 478 } else { 479 iRec.Associations.Extract(asso); 480 } 481 return true; 482 } 483 ProcessIndividualName(bool redo)484 private bool ProcessIndividualName(bool redo) 485 { 486 GDMIndividualRecord iRec = fObj as GDMIndividualRecord; 487 GDMPersonalName persName = fNewVal as GDMPersonalName; 488 489 if (iRec == null || persName == null) { 490 return false; 491 } 492 493 if (fType == OperationType.otIndividualNameRemove) { 494 redo = !redo; 495 } 496 if (redo) { 497 iRec.PersonalNames.Add(persName); 498 } else { 499 iRec.PersonalNames.Extract(persName); 500 } 501 return true; 502 } 503 ProcessIndividualURef(bool redo)504 private bool ProcessIndividualURef(bool redo) 505 { 506 GDMIndividualRecord iRec = fObj as GDMIndividualRecord; 507 GDMUserReference uRef = fNewVal as GDMUserReference; 508 509 if (iRec == null || uRef == null) { 510 return false; 511 } 512 513 if (fType == OperationType.otIndividualURefRemove) { 514 redo = !redo; 515 } 516 if (redo) { 517 iRec.UserReferences.Add(uRef); 518 } else { 519 iRec.UserReferences.Extract(uRef); 520 } 521 return true; 522 } 523 ProcessIndividualPortrait(bool redo)524 private bool ProcessIndividualPortrait(bool redo) 525 { 526 GDMIndividualRecord iRec = fObj as GDMIndividualRecord; 527 GDMMultimediaLink mmLink = fNewVal as GDMMultimediaLink; 528 529 if (iRec == null || mmLink == null) { 530 return false; 531 } 532 533 if (fType == OperationType.otIndividualPortraitDetach) { 534 redo = !redo; 535 } 536 537 if (redo) { 538 mmLink.IsPrimary = true; 539 } else { 540 mmLink.IsPrimary = false; 541 } 542 543 return true; 544 } 545 546 /// <summary> 547 /// Processing of undo/redo operations bookmark change of personal records. 548 /// </summary> 549 /// <param name="redo"></param> 550 /// <returns></returns> ProcessIndividualBookmarkChange(bool redo)551 private bool ProcessIndividualBookmarkChange(bool redo) 552 { 553 GDMIndividualRecord iRec = fObj as GDMIndividualRecord; 554 555 if (iRec == null || fNewVal == null) { 556 return false; 557 } 558 559 if (redo) { 560 fOldVal = iRec.Bookmark; 561 iRec.Bookmark = (bool) fNewVal; 562 } else { 563 iRec.Bookmark = (bool) fOldVal; 564 } 565 return true; 566 } 567 568 /// <summary> 569 /// Processing of undo/redo operations patriarch's bookmark change of personal records. 570 /// </summary> 571 /// <param name="redo"></param> 572 /// <returns></returns> ProcessIndividualPatriarchChange(bool redo)573 private bool ProcessIndividualPatriarchChange(bool redo) 574 { 575 GDMIndividualRecord iRec = fObj as GDMIndividualRecord; 576 577 if (iRec == null || fNewVal == null) { 578 return false; 579 } 580 581 if (redo) { 582 fOldVal = iRec.Patriarch; 583 iRec.Patriarch = (bool) fNewVal; 584 } else { 585 iRec.Patriarch = (bool) fOldVal; 586 } 587 return true; 588 } 589 590 /// <summary> 591 /// Processing of undo/redo operations sex change of personal records. 592 /// </summary> 593 /// <param name="redo"></param> 594 /// <returns></returns> ProcessIndividualSexChange(bool redo)595 private bool ProcessIndividualSexChange(bool redo) 596 { 597 GDMIndividualRecord iRec = fObj as GDMIndividualRecord; 598 599 if (iRec == null || fNewVal == null) { 600 return false; 601 } 602 603 if (redo) { 604 fOldVal = iRec.Sex; 605 iRec.Sex = (GDMSex) fNewVal; 606 } else { 607 iRec.Sex = (GDMSex) fOldVal; 608 } 609 return true; 610 } 611 } 612 } 613