"Fossies" - the Fresh Open Source Software Archive 
Member "opengroupware-5.5rc3/WebUI/JobUI/LSWJobEditor.m" (5 Dec 2015, 35647 Bytes) of package /linux/privat/opengroupware-5.5rc3.tar.gz:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Matlab source code syntax highlighting (style:
standard) with prefixed line numbers.
Alternatively you can here
view or
download the uninterpreted source code file.
For more information about "LSWJobEditor.m" see the
Fossies "Dox" file reference documentation and the latest
Fossies "Diffs" side-by-side code changes report:
5.5rc2_vs_5.5rc3.
1 /*
2 Copyright (C) 2000-2005 SKYRIX Software AG
3
4 This file is part of OpenGroupware.org.
5
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
9 later version.
10
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
15
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
19 02111-1307, USA.
20 */
21
22 #include <OGoFoundation/LSWEditorPage.h>
23
24 @class NSString, NSArray, NSMutableArray, NSDictionary;
25
26 @interface LSWJobEditor : LSWEditorPage
27 {
28 @protected
29 id item;
30 int idx;
31 id project;
32 BOOL notifyExecutant;
33 BOOL isImportMode;
34 BOOL isProjectLinkMode;
35 BOOL isEnterpriseLinkMode;
36 NSArray *notifyList;
37 NSArray *teams;
38
39 id team;
40 id executantSelection;
41
42 NSMutableArray *resultList;
43
44 NSString *searchAccount;
45
46 NSDictionary *snapshotCopy;
47 NSArray *notifyLabels;
48
49 BOOL isProjectEnabled;
50 NSString *accountLabelFormat;
51 int noOfCols;
52
53 id referredPerson;
54
55 NSArray *selPrefAccounts;
56 }
57
58 - (void)setProject:(id)_project;
59 - (id)project;
60
61 @end
62
63 #include "LSWJobMailPage.h"
64 #include "NSArray+JobIntNums.h"
65 #include "common.h"
66 #include <NGObjWeb/WOMailDelivery.h>
67 #include <OGoFoundation/LSWNotifications.h>
68 #include <EOControl/EOControl.h>
69 #include <LSFoundation/OGoObjectLinkManager.h>
70 #include <LSFoundation/OGoObjectLink.h>
71 #include <OGoFoundation/LSWMailEditorComponent.h>
72
73 #include <OGoJobs/SkyPersonJobDataSource.h>
74
75 static int compareAccounts(id e1, id e2, void* context) {
76 BOOL isTeam1 = [[e1 valueForKey:@"isTeam"] boolValue];
77 BOOL isTeam2 = [[e2 valueForKey:@"isTeam"] boolValue];
78
79 if (isTeam1) {
80 if (!isTeam2)
81 return NSOrderedAscending;
82
83 return [[e1 valueForKey:@"description"]
84 caseInsensitiveCompare:[e2 objectForKey:@"description"]];
85 }
86 if (isTeam2)
87 return NSOrderedDescending;
88
89 return [[e1 valueForKey:@"name"]
90 caseInsensitiveCompare:[e2 objectForKey:@"name"]];
91 }
92
93 @interface LSWJobEditor(Private)
94 - (id)_save;
95 - (BOOL)preferredExecutantsEnabled;
96 @end /* LSWJobEditor(Private) */
97
98 @implementation LSWJobEditor
99
100 static NSArray *JobAttrsEditor_percentages = nil;
101 static NSArray *JobAttrsEditor_priorities = nil;
102 static NSArray *defNotifyList = nil;
103 static NSArray *defNotifyLabels = nil;
104 static NSString *preferredJobExecutantLinkType = @"Preferred Job Executant";
105
106 static BOOL JobAttributesCollapsible = NO;
107 static BOOL PreferredAccountsEnabled = NO;
108 static BOOL HasSkyProject4Desktop = NO;
109
110 + (void)initialize {
111 NSUserDefaults *ud = [NSUserDefaults standardUserDefaults];
112 NGBundleManager *bm = [NGBundleManager defaultBundleManager];
113 static BOOL didInit = NO;
114 if (didInit) return;
115 didInit = YES;
116
117 JobAttributesCollapsible = [ud boolForKey:@"JobReferredPersonEnabled"];
118 PreferredAccountsEnabled = [ud boolForKey:@"JobPreferredExecutantsEnabled"];
119
120 HasSkyProject4Desktop = [bm bundleProvidingResource:@"SkyProject4Desktop"
121 ofType:@"WOComponents"] != nil ? YES : NO;
122
123 JobAttrsEditor_percentages =
124 [[[ud arrayForKey:@"JobAttrsEditor_percentages"]
125 arrayByConvertingValuesToIntNumbers] copy];
126 JobAttrsEditor_priorities =
127 [[[ud arrayForKey:@"JobAttrsEditor_priorities"]
128 arrayByConvertingValuesToIntNumbers] copy];
129
130 defNotifyList = [[NSArray alloc] initWithObjects:
131 [NSNumber numberWithInt:0],
132 [NSNumber numberWithInt:1],
133 [NSNumber numberWithInt:2],
134 nil];
135 defNotifyLabels = [[NSArray alloc] initWithObjects:@"Never", @"Always",
136 @"OnAcceptDone", nil];
137 }
138
139 - (id)init {
140 if (self == [super init]) {
141 self->isProjectEnabled = HasSkyProject4Desktop;
142 self->noOfCols = -1;
143
144 self->resultList = [[NSMutableArray alloc] initWithCapacity:16];
145 self->selPrefAccounts = [[NSMutableArray alloc] initWithCapacity:16];
146 }
147 return self;
148 }
149
150 - (void)dealloc {
151 [self->item release];
152 [self->project release];
153 [self->notifyList release];
154 [self->teams release];
155 [self->team release];
156 [self->executantSelection release];
157 [self->resultList release];
158 [self->searchAccount release];
159 [self->snapshotCopy release];
160 [self->notifyLabels release];
161 [self->accountLabelFormat release];
162 [self->referredPerson release];
163 [self->selPrefAccounts release];
164 [super dealloc];
165 }
166
167 /* accessors */
168
169 - (NSArray *)sensitivities {
170 // TODO: is it important to have numbers? otherwise we have
171 // JobAttrsEditor_sensitivities
172 return [NSArray arrayWithObjects:
173 [NSNumber numberWithInt:1],
174 [NSNumber numberWithInt:2],
175 [NSNumber numberWithInt:3],
176 [NSNumber numberWithInt:4],
177 nil];
178 }
179
180 - (NSString *)sensitivity {
181 NSString *s;
182
183 s = [@"sensitivity_" stringByAppendingString:[item stringValue]];
184 return [[self labels] valueForKey:s];
185 }
186
187 - (void)setProject:(id)_project {
188 ASSIGN(self->project, _project);
189 }
190 - (id)project {
191 return self->project;
192 }
193
194 - (void)setNotifyExecutant:(BOOL)_notify {
195 self->notifyExecutant = _notify;
196 }
197 - (BOOL)notifyExecutant {
198 return self->notifyExecutant;
199 }
200
201 - (void)setNotifyList:(NSArray *)_notifyList {
202 ASSIGN(self->notifyList, _notifyList);
203 }
204 - (NSArray *)notifyList {
205 return self->notifyList;
206 }
207
208 - (void)setItem:(id)_item {
209 ASSIGN(self->item, _item);
210 }
211 - (id)item {
212 return self->item;
213 }
214
215 - (void)setExecutantSelection:(id)_ex {
216 ASSIGN(self->executantSelection, _ex);
217 }
218 - (id)executantSelection {
219 return self->executantSelection;
220 }
221
222 - (void)setIsSelected:(BOOL)_flag {
223 if (_flag)
224 [self setExecutantSelection:self->item];
225 }
226 - (BOOL)isSelected {
227 return [self->item isEqual:self->executantSelection];
228 }
229
230 - (void)setTeam:(id)_id {
231 ASSIGN(self->team, _id);
232 }
233 - (id)team {
234 return self->team;
235 }
236
237 - (void)setSearchAccount:(NSString *)_str {
238 ASSIGNCOPY(self->searchAccount, _str);
239 }
240 - (NSString *)searchAccount {
241 return self->searchAccount;
242 }
243
244 - (void)setIdx:(int)_idx {
245 self->idx = _idx;
246 }
247 - (int)idx {
248 return self->idx;
249 }
250
251 - (NSString *)priorityName {
252 NSString *pri;
253 char buf[64];
254
255 snprintf(buf, sizeof(buf), "priority_%d", [self->item unsignedIntValue]);
256 pri = [[self labels] valueForKey:[NSString stringWithCString:buf]];
257
258 if (pri == nil)
259 pri = [self->item stringValue];
260 return pri;
261 }
262
263 - (NSString *)notifyItem {
264 NSString *s;
265
266 s = [self->notifyLabels objectAtIndex:[self->item intValue]];
267 return [[self labels] valueForKey:s];
268 }
269
270 - (NSDictionary *)job {
271 return [self snapshot];
272 }
273
274 - (BOOL)isCommentMode {
275 return ([self isInNewMode] || self->isImportMode);
276 }
277
278 - (NSString *)jobUrl:(id)_job {
279 WOContext *ctx;
280 NSString *urlPrefix;
281 NSString *url;
282
283 // TODO: use the WOContext URL generation methods!
284 ctx = [self context];
285 urlPrefix = [ctx urlSessionPrefix];
286 url = [[ctx request] headerForKey:@"x-webobjects-server-url"];
287
288 if (url != nil && [url length] > 0) {
289 return [NSString stringWithFormat:
290 @"%@%@/wa/LSWViewAction/viewJob?jobId=%@",
291 url, urlPrefix, [_job valueForKey:@"jobId"]];
292 }
293 else {
294 return [NSString stringWithFormat:
295 @"http://%@%@/wa/LSWViewAction/viewJob?jobId=%@",
296 [[ctx request] headerForKey:@"host"],
297 urlPrefix, [_job valueForKey:@"jobId"]];
298 }
299 }
300
301
302 - (BOOL)showProjectName {
303 return (self->isProjectLinkMode || self->isEnterpriseLinkMode ||
304 (self->project != nil));
305 }
306
307 - (BOOL)showProjectSelection {
308 return !(self->isProjectLinkMode || self->isEnterpriseLinkMode);
309 }
310
311 - (NSArray *)teams {
312 return self->teams;
313 }
314
315 - (NSString *)noProjectLabel {
316 NSString *l;
317
318 l = [[self labels] valueForKey:@"noProject"];
319 return (l != nil) ? l : (NSString *)@"- no project -";
320 }
321
322 - (BOOL)hasExecutants {
323 return ([self->executantSelection isNotNull] ||
324 [self->resultList count] > 0) ? YES : NO;
325 }
326
327 - (BOOL)hasResultList {
328 return ([self->resultList count] > 0) ? YES : NO;
329 }
330
331 - (NSArray *)resultList {
332 if (([self->resultList count] == 0) &&
333 ([self->executantSelection isNotNull]))
334 [self->resultList addObject:self->executantSelection];
335 return self->resultList;
336 }
337
338 - (void)setExecutant:(id)_ex {
339 [self setExecutantSelection:_ex];
340 }
341
342 - (BOOL)isTeamSelected {
343 return [[self->executantSelection objectForKey:@"isTeam"] boolValue];
344 }
345
346 - (int)noOfCols {
347 if (self->noOfCols == -1) {
348 id d;
349 int n;
350
351 d = [[[self session] userDefaults] objectForKey:@"job_no_of_cols"];
352 n = [d intValue];
353 self->noOfCols = (n > 0) ? n : 3;
354 }
355 return self->noOfCols;
356 }
357
358 - (BOOL)startNewLine {
359 if (self->idx == 0) return NO; // first line always exists
360 return ((self->idx % [self noOfCols]) == 0) ? YES : NO;
361 }
362
363 /* TODO: the following is weird, just register the default default */
364 - (NSString *)defaultAccountLableFormat {
365 return @"$name$, $firstname$ ($login$)";
366 }
367 - (NSString *)accountLabelFormat {
368 if (self->accountLabelFormat == nil) {
369 NSUserDefaults *ud;
370
371 ud = [[self session] userDefaults];
372 self->accountLabelFormat =
373 [ud stringForKey:@"job_editor_account_format"];
374 if ([self->accountLabelFormat length] == 0)
375 self->accountLabelFormat = [self defaultAccountLableFormat];
376 self->accountLabelFormat = [self->accountLabelFormat copy];
377 }
378 return self->accountLabelFormat;
379 }
380
381 - (NSString *)accountDescription {
382 return [[self accountLabelFormat]
383 stringByReplacingVariablesWithBindings:self->item
384 stringForUnknownBindings:@""];
385 }
386
387 - (NSString *)teamDescription {
388 return [NSString stringWithFormat:@"Team: %@",
389 [self->item valueForKey:@"description"]];
390 }
391
392 - (NSString *)labelForAccount:(id)_part {
393 if ([[_part valueForKey:@"isTeam"] boolValue])
394 return [_part valueForKey:@"description"];
395
396 return [[self accountLabelFormat]
397 stringByReplacingVariablesWithBindings:_part
398 stringForUnknownBindings:@""];
399 }
400
401 - (BOOL)hasTeam {
402 return (self->team == nil) ? NO : YES;
403 }
404
405 - (NSString *)teamName {
406 return [self->item valueForKey:@"description"];
407 }
408
409 - (BOOL)isProjectEnabled {
410 return self->isProjectEnabled;
411 }
412
413 - (BOOL)userIsCreator {
414 return [[[[self session] activeAccount] valueForKey:@"companyId"]
415 isEqual:[[self object] valueForKey:@"creatorId"]];
416 }
417 - (BOOL)showExecutantSelection {
418 if ([self isInNewMode]) return YES;
419 return [self userIsCreator];
420 }
421
422 - (NSArray *)percentList {
423 NSArray *pList;
424 id jobPercent;
425
426 pList = JobAttrsEditor_percentages;
427
428 jobPercent = [[self job] valueForKey:@"percentComplete"];
429 if ([jobPercent isNotNull] && ![pList containsObject:jobPercent]) {
430 NSMutableArray *md;
431
432 md = [pList mutableCopy];
433 [md addObject:[NSNumber numberWithInt:[jobPercent intValue]]];
434 pList = [md sortedArrayUsingSelector:@selector(compare:)];
435 [md release];
436 }
437 return pList;
438 }
439
440 - (void)clearEditor {
441 [self->item release]; self->item = nil;
442 [super clearEditor];
443 }
444
445 /* commands */
446
447 - (id)_fetchProject:(id)_projectId {
448 NSArray *p = nil;
449
450 p = [self runCommand:@"project::get",
451 @"projectId", _projectId, nil];
452
453 return ([p count] > 0) ? [p lastObject] : nil;
454 }
455
456 - (NSArray *)_resolveAccountsOfTeamEO:(id)_team {
457 return [self runCommand:@"team::resolveaccounts", @"staff", _team, nil];
458 }
459
460 - (NSArray *)_fetchMemberEOsOfTeamEO:(id)_team {
461 return [self runCommand:@"team::members", @"object", _team, nil];
462 }
463
464 - (NSArray *)_searchAccountEOsMatchingString:(NSString *)_s {
465 return [self runCommand:@"account::extended-search",
466 @"operator", @"OR",
467 @"name", _s,
468 @"firstname", _s,
469 @"description", _s,
470 @"login", _s,
471 nil];
472 }
473
474 - (id)_createJobWithArguments:(NSDictionary *)_args {
475 return [self runCommand:@"job::new" arguments:_args];
476 }
477
478 - (void)_addLogForGlobalID:(EOKeyGlobalID *)_gid
479 action:(NSString *)_action comment:(NSString *)_comment
480 {
481 [self runCommand:@"object::add-log",
482 @"objectId", [_gid keyValues][0],
483 @"logText", _comment,
484 @"action", _action, nil];
485 }
486 - (void)_commentJobEO:(id)_eo comment:(NSString *)_comment {
487 [self runCommand:@"job::jobaction",
488 @"object", _eo,
489 @"action", @"comment",
490 @"comment", _comment,
491 nil];
492 }
493
494 /* activation */
495
496 - (BOOL)activateForImport {
497 NSMutableDictionary *snap;
498
499 [self setObject:[[self session] getTransferObject]];
500
501 snap = [[self object] mutableCopy];
502 [self setSnapshot:snap];
503 [snap release];
504
505 self->project =
506 [[self _fetchProject:[[self object] valueForKey:@"projectId"]] retain];
507 return YES;
508 }
509
510 - (BOOL)prepareForActivationCommand:(NSString *)_command
511 type:(NGMimeType *)_type
512 configuration:(NSDictionary *)_cmdCfg
513 {
514 // TODO: clean up!
515 WOSession *sn;
516
517 sn = [self session];
518
519 self->isProjectLinkMode = [[_type subType]
520 isEqualToString:@"project-job"];
521 self->isEnterpriseLinkMode = [[_type subType]
522 isEqualToString:@"enterprise-job"];
523 self->isImportMode = [[_type type] isEqualToString:@"dict"];
524
525 if (self->teams == nil) {
526 NSArray *a;
527
528 // TODO: was sorted before
529 a = [self runCommand:@"team::get",
530 @"returnType", intObj(LSDBReturnType_ManyObjects),
531 nil];
532 self->teams = [a retain];
533 }
534
535 if (self->isImportMode)
536 return [self activateForImport];
537
538 if ((self->isProjectLinkMode) ||
539 (self->isEnterpriseLinkMode))
540 self->project = [[self session] getTransferObject];
541
542 ASSIGN(self->notifyList, defNotifyList);
543 ASSIGN(self->notifyLabels, defNotifyLabels);
544
545 return [super prepareForActivationCommand:_command type:_type
546 configuration:_cmdCfg];
547 }
548
549 - (BOOL)prepareForNewCommand:(NSString *)_command
550 type:(NGMimeType *)_type
551 configuration:(NSDictionary *)_cmdCfg
552 {
553 WOSession *sn;
554 id job;
555 id pJob = nil;
556 NSCalendarDate *now;
557
558 now = [NSCalendarDate date];
559 sn = [self session];
560 job = [self snapshot];
561
562 [job takeValue:now forKey:@"startDate"];
563 {
564 NSCalendarDate *date;
565 id tmp;
566 int days;
567
568 tmp = [[sn userDefaults] objectForKey:@"job_defaultDuration"];
569 if (tmp == nil) days = 7;
570 else {
571 days = [tmp intValue];
572 if (days < 0) days = 7;
573 }
574 date = [now dateByAddingYears:0 months:0 days:days
575 hours:0 minutes:0 seconds:0];
576 [job takeValue:date forKey:@"endDate"];
577 }
578
579 [job takeValue:[NSNumber numberWithInt:3] forKey:@"priority"];
580
581 if (!self->isProjectLinkMode && !self->isEnterpriseLinkMode) {
582 pJob = [sn getTransferObject];
583
584 if (pJob != nil) {
585 id p;
586
587 p = [self _fetchProject:[pJob valueForKey:@"projectId"]];
588 self->project = [p retain];;
589 }
590 }
591
592 ASSIGN(self->executantSelection, [[self session] activeAccount]);
593
594 return YES;
595 }
596
597 - (BOOL)prepareForEditCommand:(NSString *)_command
598 type:(NGMimeType *)_type
599 configuration:(NSDictionary *)_cmdCfg
600 {
601 id job;
602 id obj;
603 id p;
604
605 job = [self snapshot];
606 obj = [self object];
607 p = [self _fetchProject:[obj valueForKey:@"projectId"]];
608
609 RELEASE(self->executantSelection);
610 self->executantSelection = [obj valueForKey:@"executant"];
611 RETAIN(self->executantSelection);
612 [job takeValue:self->executantSelection forKey:@"executant"];
613
614 ASSIGN(self->project, p);
615 self->snapshotCopy = [[self snapshot] copyWithZone:[self zone]];
616
617 return YES;
618 }
619
620 /* accessors */
621
622 - (NSArray *)priorities {
623 return JobAttrsEditor_priorities;
624 }
625
626 - (BOOL)checkPreferredExecutantsConstraintsForSave {
627 NSArray *acc;
628 id obj;
629 NSEnumerator *enumerator;
630
631 if (![self preferredExecutantsEnabled])
632 return YES;
633 if ([self->selPrefAccounts count] == 0)
634 return YES;
635
636 if (![[self->executantSelection entityName] isEqual:@"Team"]) {
637 NSString *s;
638
639 s = [[self labels] valueForKey:
640 @"Preferred executants allowed only if executant is a team"];
641 [self setErrorString:s];
642 return NO;
643 }
644
645 acc = [self _resolveAccountsOfTeamEO:self->executantSelection];
646 enumerator = [self->selPrefAccounts objectEnumerator];
647
648 while ((obj = [enumerator nextObject])) {
649 NSString *s;
650
651 if ([acc containsObject:obj])
652 continue;
653
654 s = @"Preferred executant %@ is not in selected team %@.";
655 s = [NSString stringWithFormat:[[self labels] valueForKey:s],
656 [self labelForAccount:obj],
657 [self labelForAccount:self->executantSelection]];
658 [self setErrorString:s];
659 }
660 return YES;
661 }
662 - (BOOL)checkConstraintsForSave {
663 // TODO: fix this huge method
664 NSMutableString *error = nil;
665 id labels = nil;
666 id job = nil;
667 NSTimeZone *tz = nil;
668 NSString *n = nil;
669 NSCalendarDate *sD = nil;
670 NSCalendarDate *eD = nil;
671
672 tz = [[self session] timeZone];
673 job = [self snapshot];
674 n = [job valueForKey:@"name"];
675 sD = [job valueForKey:@"startDate"];
676 eD = [job valueForKey:@"endDate"];
677
678 labels = [self labels];
679 error = [NSMutableString stringWithCapacity:128];
680
681 if (![n isNotNull]) {
682 [error appendString:[labels valueForKey:@"error_no_name"]];
683 }
684 else if (![sD isNotNull]) {
685 [error appendString:[labels valueForKey:@"error_no_start_date"]];
686 }
687 else if (![eD isNotNull]) {
688 [error appendString:[labels valueForKey:@"error_no_end_date"]];
689 }
690 else {
691 [sD setTimeZone:tz];
692 [eD setTimeZone:tz];
693
694 if ([[sD beginOfDay] compare:[eD beginOfDay]] == NSOrderedDescending) {
695 [error appendString:[labels valueForKey:@"error_end_before_start"]];
696 }
697 else {
698 id p;
699
700 if ([self isInNewMode]) {
701 NSCalendarDate *nowDate = [NSCalendarDate date];
702
703 [nowDate setTimeZone:tz];
704
705 if ([[nowDate beginOfDay] compare:[sD beginOfDay]]
706 == NSOrderedDescending) {
707 [error appendString:[labels valueForKey:@"error_start_before_now"]];
708 }
709 p = self->project;
710 }
711 else {
712 p = self->project;
713 }
714 }
715 }
716 if ([error length] > 0) {
717 [self setErrorString:error];
718 return NO;
719 }
720
721 if (![self checkPreferredExecutantsConstraintsForSave])
722 return NO;
723
724 [self setErrorString:nil];
725 return [super checkConstraintsForSave];
726 }
727
728 - (NSString *)changeStringForLabel:(NSString *)_labelName
729 withValue:(id)_value
730 {
731 NSString *label;
732
733 label = [[self labels] valueForKey:_labelName];
734 return [NSString stringWithFormat:@"%@: %@\n", label, _value];
735 }
736
737 /* notifications */
738
739 - (NSString *)insertNotificationName {
740 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
741
742 [nc postNotificationName:SkyNewJobNotification object:nil];
743
744 return LSWJobHasChanged;
745 }
746
747 - (NSString *)updateNotificationName {
748 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
749
750 [nc postNotificationName:SkyUpdatedJobNotification object:nil];
751
752 return LSWJobHasChanged;
753 }
754
755 - (NSString *)deleteNotificationName {
756 NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
757
758 [nc postNotificationName:SkyDeletedJobNotification object:nil];
759
760 return LSWJobHasChanged;
761 }
762
763 /* actions */
764
765 - (id)search {
766 NSArray *result = nil;
767
768 [self setErrorString:nil];
769 [self->resultList removeAllObjects];
770
771 if (![self->team isNotNull]) { /* Search accounts with searchAccount field */
772 result = [self _searchAccountEOsMatchingString:self->searchAccount];
773 if (result != nil)
774 [self->resultList addObjectsFromArray:result];
775 }
776 else { /* take accounts from team */
777 NSArray *acc;
778
779 if ([[[self->executantSelection globalID] entityName] isEqual:@"Team"]) {
780 ASSIGN(self->executantSelection, nil);
781 [self->resultList removeObject:self->executantSelection];
782 }
783
784 acc = [self _resolveAccountsOfTeamEO:self->team];
785 if (acc != nil)
786 [self->resultList addObjectsFromArray:acc];
787
788 if (![self->resultList containsObject:self->team])
789 [self->resultList addObject:self->team];
790 }
791 if (self->executantSelection &&
792 ![self->resultList containsObject:self->executantSelection])
793 [self->resultList addObject:self->executantSelection];
794
795 [self->resultList sortUsingFunction:compareAccounts context:NULL];
796
797 if ([self->resultList count] > 0)
798 self->executantSelection = [[self->resultList objectAtIndex:0] retain];
799
800 return nil;
801 }
802
803 - (NSString *)emailSubjectForJobEO:(id)_job {
804 NSString *subject;
805
806 subject = [NSString stringWithFormat:@"%@: '%@' %@ %@",
807 [[self labels] valueForKey:@"job"],
808 [_job valueForKey:@"name"],
809 [[self labels] valueForKey:@"createLabel"],
810 [[[self session] activeAccount] valueForKey:@"login"]];
811 return subject;
812 }
813 - (id)jobObjectForSend {
814 id obj;
815
816 obj = [self object];
817 if (![obj isKindOfClass:[NSArray class]])
818 return obj;
819
820 return ([(NSArray *)obj count] > 0) ? [obj objectAtIndex:0] : nil;
821 }
822
823 - (id)sendMessage {
824 id<LSWMailEditorComponent,OGoContentPage> editor;
825 id obj;
826
827 if ((obj = [self jobObjectForSend]) == nil) {
828 [self setErrorString:@"No job found for email send!"];
829 return nil;
830 }
831
832 /* setup email editor */
833
834 editor = (id)[self pageWithName:@"LSWImapMailEditor"];
835 [self enterPage:editor];
836 [editor setSubject:[self emailSubjectForJobEO:obj]];
837 [editor setContentWithoutSign:@""];
838
839 /* add recipients */
840
841 if ([self isTeamSelected]) {
842 NSArray *m = [self->executantSelection valueForKey:@"members"];
843 int i, cnt = 0;
844
845 if (m == nil)
846 m = [self _fetchMemberEOsOfTeamEO:self->executantSelection];
847
848 for (i = 0, cnt = [m count]; i < cnt; i++)
849 [editor addReceiver:[m objectAtIndex:i] type:@"to"];
850 }
851 else
852 [editor addReceiver:self->executantSelection type:@"to"];
853
854 /* add attachments */
855
856 [editor addAttachment:obj type:[NGMimeType mimeType:@"eo" subType:@"job"]];
857
858 return [editor send];
859 }
860
861 - (void)_applyPreferredExecutantsOnJobEO:(id)job {
862 NSEnumerator *enumerator;
863 id account, l;
864 OGoObjectLinkManager *lm;
865 EOKeyGlobalID *gid;
866 NSString *teamLabel;
867
868 enumerator = [self->selPrefAccounts objectEnumerator];
869 lm = [[[self session] commandContext] linkManager];
870 gid = (EOKeyGlobalID *)[job globalID];
871 l = [self labels];
872 teamLabel = [self labelForAccount:self->executantSelection];
873
874 while ((account = [enumerator nextObject]) != nil) {
875 OGoObjectLink *link;
876 EOKeyGlobalID *targetGID;
877 NSString *label, *comment;
878
879 /* create object link */
880
881 label = [self labelForAccount:account];
882 targetGID = (EOKeyGlobalID *)[account globalID];
883 link = [[OGoObjectLink alloc] initWithSource:gid target:targetGID
884 type:preferredJobExecutantLinkType
885 label:label];
886 [lm createLink:link];
887 [link release]; link = nil;
888
889 /* add an object log */
890
891 comment = [l valueForKey:@"Add job link to %@ [team:%@]."];
892 comment = [NSString stringWithFormat:comment, label, teamLabel];
893 [self _addLogForGlobalID:gid action:@"05_changed" comment:comment];
894 }
895 }
896
897 - (void)_applyValuesOnSnapshot:(id)job {
898 [job takeValue:[NSNumber numberWithBool:[self isTeamSelected]]
899 forKey:@"isTeamJob"];
900 [job takeValue:[self->executantSelection valueForKey:@"companyId"]
901 forKey:@"executantId"];
902 if ([self->project isNotNull]) {
903 [job takeValue:[self->project valueForKey:@"projectId"]
904 forKey:@"projectId"];
905 }
906 else {
907 [job takeValue:[NSNull null] forKey:@"projectId"];
908 }
909 }
910
911 - (id)insertObject {
912 id job;
913
914 job = [self snapshot];
915 [self _applyValuesOnSnapshot:job];
916
917 job = [self _createJobWithArguments:job];
918
919 if ([self preferredExecutantsEnabled])
920 [self _applyPreferredExecutantsOnJobEO:job];
921
922 return job;
923 }
924
925 - (id)updateObject {
926 id job;
927
928 job = [self snapshot];
929 [job removeObjectForKey:@"executant"];
930 [job removeObjectForKey:@"object"];
931
932 [self _applyValuesOnSnapshot:job];
933
934 return [self runCommand:@"job::set" arguments:job];
935 }
936
937 - (id)deleteObject {
938 return [self runCommand:@"job::delete",
939 @"object", [self object],
940 @"reallyDelete", [NSNumber numberWithBool:NO],
941 nil];
942 }
943
944 - (id)_saveExistingJob {
945 BOOL access;
946 id acManager;
947
948 if (![self->executantSelection isNotNull]) {
949 [self setErrorString:
950 [[self labels] valueForKey:@"NoTeamAndExecutantsWasSelected"]];
951 return nil;
952 }
953
954 // TODO: document, what is referredPerson?
955
956 if (self->referredPerson == nil)
957 return [self _save];
958
959 acManager = [[[self session] commandContext] accessManager];
960 access = [acManager operation:@"rw"
961 allowedOnObjectID:
962 [self->referredPerson globalID]
963 forAccessGlobalID:
964 [self->executantSelection globalID]];
965 if (!access) {
966 [self setWarningOkAction:@"editAccessAndSave"];
967 [self setWarningPhrase:[[self labels] valueForKey:@"AccessWarning"]];
968 [self setIsInWarningMode:YES];
969 return nil;
970 }
971 return [self _save];
972 }
973
974 - (id)save {
975 return [self isInNewMode] ? [self _save] : [self _saveExistingJob];
976 }
977
978 - (BOOL)hasJobAttributes {
979 if (!JobAttributesCollapsible)
980 return NO;
981
982 // TODO: was: return self->referredPerson != nil > 0 ? YES : NO;
983 // what do we want here? :-)
984 return self->referredPerson != nil ? YES : NO;
985 }
986
987 - (void)setReferredPerson:(NSString *)_per {
988 ASSIGN(self->referredPerson, _per);
989 }
990 - (id)referredPerson {
991 return self->referredPerson;
992 }
993
994 - (NSString *)referredPersonLabel {
995 NSMutableString *str;
996 id eo;
997 NSString *fn;
998
999 if ((eo = [self referredPerson]) == nil)
1000 return nil;
1001
1002 str = [NSMutableString stringWithCapacity:30];
1003
1004 [str appendString:[[eo valueForKey:@"name"] stringValue]];
1005
1006 fn = [eo valueForKey:@"firstname"];
1007
1008 if ([fn isNotNull] && [[fn stringValue] length] > 0) {
1009 [str appendString:@", "];
1010 [str appendString:[fn stringValue]];
1011 }
1012 return str;
1013 }
1014
1015 - (NSString *)referredPersonAction {
1016 NSDictionary *dict;
1017
1018 if (self->referredPerson == nil)
1019 return nil;
1020
1021 dict = [NSDictionary dictionaryWithObjectsAndKeys:
1022 [self->referredPerson valueForKey:@"companyId"],
1023 @"companyId",
1024 [self referredPersonLabel], @"label", nil];
1025
1026 return [[self context]
1027 directActionURLForActionNamed:@"LSWViewAction/viewPerson"
1028 queryDictionary:dict];
1029 }
1030
1031 - (id)editAccessAndSave {
1032 id acManager;
1033
1034 [self setIsInWarningMode:NO];
1035
1036 acManager = [[[self session] commandContext] accessManager];
1037
1038 if (![acManager setOperation:@"rw"
1039 onObjectID:[self->referredPerson globalID]
1040 forAccessGlobalID:[self->executantSelection globalID]]) {
1041 [self setErrorString:@"CouldntSetAccessRights"];
1042 return nil;
1043 }
1044
1045 return [self _save];
1046 }
1047
1048 - (id)_saveInImportModeWithSnapshot:(id)s {
1049 /* called by _save */
1050 id obj = [self object];
1051 id projId = nil;
1052
1053 NSAssert2([obj isKindOfClass:[NSMutableDictionary class]],
1054 @"Imported job is not a NSMutableDictionary %@ %@",
1055 [obj class], obj);
1056
1057 [obj addEntriesFromDictionary:s];
1058 projId = [self->project valueForKey:@"projectId"];
1059
1060 NSAssert(projId != nil, @"no projectId");
1061 [obj takeValue:projId forKey:@"projectId"];
1062
1063 return [self leavePage];
1064 }
1065 - (void)_processInsertProperties {
1066 id pm;
1067 NSDictionary *dic;
1068
1069 if (![self hasJobAttributes])
1070 return;
1071 if (self->referredPerson == nil)
1072 return;
1073
1074 pm = [[[self session] commandContext] propertyManager];
1075
1076 dic = [NSDictionary dictionaryWithObjectsAndKeys:
1077 [self referredPersonAction],
1078 @"{person}referredPerson", nil];
1079 [pm takeProperties:dic namespace:nil globalID:[[self object] globalID]];
1080 }
1081
1082 - (void)_postLinkSaveNotificationsOnJobEO:(id)obj {
1083 NSEnumerator *enumerator;
1084
1085 if (!((self->isProjectLinkMode) || (self->isEnterpriseLinkMode)))
1086 return;
1087
1088 if (![obj isKindOfClass:[NSArray class]])
1089 obj = [NSArray arrayWithObject:obj];
1090
1091 enumerator = [obj objectEnumerator];
1092 while ((obj = [enumerator nextObject]) != nil) {
1093 NSDictionary *dict;
1094
1095 dict = [NSDictionary dictionaryWithObjectsAndKeys:
1096 [self jobUrl:obj], @"LinkUrl",
1097 [obj valueForKey:@"name"],
1098 @"LinkTitle",
1099 @"job", @"fileType", nil];
1100
1101 if (self->isProjectLinkMode) {
1102 [self postChange:LSWNewObjectLinkProjectNotificationName onObject:dict];
1103 }
1104 else if (self->isEnterpriseLinkMode) {
1105 [self postChange:LSWNewObjectLinkEnterpriseNotificationName
1106 onObject:dict];
1107 }
1108 }
1109 }
1110
1111 static BOOL _isIntKeyEq(id a, id b, NSString *key) {
1112 a = [a valueForKey:key];
1113 b = [b valueForKey:key];
1114 if (a == b) return YES;
1115 return [a intValue] == [b intValue] ? YES : NO;
1116 }
1117
1118 - (NSString *)_buildCommentWithOldSnapshot:(id)sc andNewSnapshot:(id)s{
1119 // TODO: clean up this mess!
1120 NSMutableString *comment;
1121 NSFormatter *form = nil;
1122 BOOL nameChanged, startDateChanged, endDateChanged, notifyChanged;
1123 BOOL projectChanged, executantChanged;
1124 id l, tmp;
1125
1126 /* detect changes */
1127
1128 nameChanged = ![[sc valueForKey:@"name"] isEqual:[s valueForKey:@"name"]];
1129 startDateChanged = ![[sc valueForKey:@"startDate"]
1130 isEqual:[s valueForKey:@"startDate"]];
1131 endDateChanged = ![[sc valueForKey:@"endDate"]
1132 isEqual:[s valueForKey:@"endDate"]];
1133
1134 notifyChanged = !_isIntKeyEq(sc, s, @"notify");
1135 projectChanged = !_isIntKeyEq(sc, s, @"projectId");
1136
1137 executantChanged = ![[sc valueForKey:@"executantId"]
1138 isEqual:[s valueForKey:@"executantId"]];
1139
1140
1141 form = [[self session] formatDate];
1142 l = [self labels];
1143
1144 comment = [NSMutableString stringWithCapacity:256];
1145 [comment appendString:[l valueForKey:@"oldJob"]];
1146 [comment appendString:@"\n"];
1147
1148 tmp = [sc valueForKey:@"name"];
1149 tmp = [self changeStringForLabel:@"jobName" withValue:tmp];
1150 [comment appendString:tmp];
1151
1152 if (startDateChanged) {
1153 tmp = [form stringForObjectValue:[sc valueForKey:@"startDate"]];
1154 tmp = [self changeStringForLabel:@"startDate" withValue:tmp];
1155 [comment appendString:tmp];
1156 }
1157 if (endDateChanged) {
1158 tmp = [form stringForObjectValue:[sc valueForKey:@"endDate"]];
1159 tmp = [self changeStringForLabel:@"endDate" withValue:tmp];
1160 [comment appendString:tmp];
1161 }
1162
1163 if (notifyChanged) {
1164 tmp = [sc valueForKey:@"notify"];
1165 tmp = [self->notifyLabels objectAtIndex:[tmp intValue]];
1166 tmp = [l valueForKey:tmp];
1167 tmp = [self changeStringForLabel:@"notifyCreator" withValue:tmp];
1168 [comment appendString:tmp];
1169 }
1170
1171 if (projectChanged) {
1172 tmp = [self _fetchProject:[sc valueForKey:@"projectId"]];
1173 tmp = [tmp valueForKey:@"name"];
1174 tmp = [self changeStringForLabel:@"projectLabel" withValue:tmp];
1175 [comment appendString:tmp];
1176 }
1177
1178 if (executantChanged) {
1179 tmp = [self labelForAccount:[sc valueForKey:@"executant"]];
1180 tmp = [self changeStringForLabel:@"executant" withValue:tmp];
1181 [comment appendString:tmp];
1182
1183 // TODO: weird side effect, why is that?
1184 [[self object] takeValue:[EONull null] forKey:@"executant"];
1185 }
1186 [comment appendString:@"\n"];
1187
1188 [comment appendString:[l valueForKey:@"newJob"]];
1189 [comment appendString:@"\n"];
1190
1191 tmp = [s valueForKey:@"name"];
1192 tmp = [self changeStringForLabel:@"jobName" withValue:tmp];
1193 [comment appendString:tmp];
1194
1195 if (startDateChanged) {
1196 tmp = [form stringForObjectValue:[s valueForKey:@"startDate"]];
1197 tmp = [self changeStringForLabel:@"startDate" withValue:tmp];
1198 [comment appendString:tmp];
1199 }
1200 if (endDateChanged) {
1201 tmp = [form stringForObjectValue:[s valueForKey:@"endDate"]];
1202 tmp = [self changeStringForLabel:@"endDate" withValue:tmp];
1203 [comment appendString:tmp];
1204 }
1205
1206 if (notifyChanged) {
1207 tmp = [s valueForKey:@"notify"];
1208 tmp = [self->notifyLabels objectAtIndex:[tmp intValue]];
1209 tmp = [l valueForKey:tmp];
1210 tmp = [self changeStringForLabel:@"notifyCreator" withValue:tmp];
1211 [comment appendString:tmp];
1212 }
1213
1214 if (projectChanged) {
1215 tmp = [self->project valueForKey:@"name"];
1216 tmp = [self changeStringForLabel:@"projectLabel" withValue:tmp];
1217 [comment appendString:tmp];
1218 }
1219
1220 if (executantChanged) {
1221 tmp = [self labelForAccount:self->executantSelection];
1222 tmp = [self changeStringForLabel:@"executant" withValue:tmp];
1223 [comment appendString:tmp];
1224 }
1225 return comment;
1226 }
1227
1228 - (BOOL)shouldSendMessage {
1229 // kinda hack
1230 return [[self navigation] activePage] != self ? YES : NO;
1231 }
1232
1233 - (id)_save {
1234 if (self->isImportMode)
1235 return [self _saveInImportModeWithSnapshot:[self snapshot]];
1236
1237 [self setErrorString:nil];
1238 [self saveAndGoBackWithCount:1];
1239
1240 if ([[self errorString] length] > 0)
1241 return nil;
1242
1243 if ([self shouldSendMessage]) {
1244 id notifyValue;
1245
1246 notifyValue = [[self snapshot] objectForKey:@"notify"];
1247
1248 if (self->notifyExecutant ||
1249 ([notifyValue isNotNull] && [notifyValue intValue] == 1)) {
1250
1251 if (![self isInNewMode]) {
1252 [self setExecutantSelection:
1253 [[self object] valueForKey:@"executant"]];
1254 }
1255 [self sendMessage];
1256 }
1257
1258 if (![self isInNewMode]) {
1259 // TODO: clean up this mess!
1260 NSString *comment;
1261
1262 comment = [self _buildCommentWithOldSnapshot:self->snapshotCopy
1263 andNewSnapshot:[self snapshot]];
1264 [self _commentJobEO:[self object] comment:comment];
1265
1266 if (![self commit]) {
1267 [self setErrorString:@"Could not commit jobaction command "
1268 @"(rolled back) !"];
1269 [self rollback];
1270 return nil;
1271 }
1272 }
1273
1274 [self _postLinkSaveNotificationsOnJobEO:[self object]];
1275 }
1276
1277 if ([self isInNewMode] && [[self object] globalID] != nil)
1278 [self _processInsertProperties];
1279
1280 return nil;
1281 }
1282
1283 - (BOOL)preferredExecutantsEnabled {
1284 return PreferredAccountsEnabled;
1285 }
1286
1287 - (void)setSelPrefAccounts:(id)_o {
1288 ASSIGN(self->selPrefAccounts, _o);
1289 }
1290 - (NSArray *)selPrefAccounts {
1291 return self->selPrefAccounts;
1292 }
1293
1294 - (NSArray *)prefAccountList {
1295 if (self->team == nil)
1296 return nil;
1297
1298 return [self _resolveAccountsOfTeamEO:self->team];
1299 }
1300
1301 - (NSString *)searchPreferredAccountsLabel {
1302 NSString *fmt, *s;
1303 id l;
1304
1305 l = [self labels];
1306 fmt = [l valueForKey:@"searchPreferredAccounts"];
1307 s = (self->team != nil)
1308 ? [self labelForAccount:self->team]
1309 : (NSString *)[l valueForKey:@"noTeamSelected"];
1310 return [NSString stringWithFormat:fmt, s];
1311 }
1312
1313 /* KVC */
1314
1315 - (void)takeValue:(id)_v forKey:(id)_key {
1316 // TODO: why is that?! should be mapped automatically?!
1317 if ([_key isEqualToString:@"referredPerson"])
1318 [self setReferredPerson:_v];
1319 else
1320 [super takeValue:_v forKey:_key];
1321 }
1322
1323 @end /* LSWJobEditor */