1/*
2   GNUstep ProjectCenter - http://www.gnustep.org/experience/ProjectCenter.html
3
4   Copyright (C) 2005-2013 Free Software Foundation
5
6   Authors: Serg Stoyan
7
8   This file is part of GNUstep.
9
10   This application is free software; you can redistribute it and/or
11   modify it under the terms of the GNU General Public
12   License as published by the Free Software Foundation; either
13   version 2 of the License, or (at your option) any later version.
14
15   This application is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18   Library General Public License for more details.
19
20   You should have received a copy of the GNU General Public
21   License along with this library; if not, write to the Free
22   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA.
23*/
24
25#import <ProjectCenter/PCDefines.h>
26#import <ProjectCenter/PCMakefileFactory.h>
27#import <ProjectCenter/PCProjectBrowser.h>
28#import <ProjectCenter/PCFileManager.h>
29#import <ProjectCenter/PCFileCreator.h>
30
31#import "PCFrameworkProject.h"
32
33@implementation PCFrameworkProject
34
35//----------------------------------------------------------------------------
36// Init and free
37//----------------------------------------------------------------------------
38
39- (id)init
40{
41  if ((self = [super init]))
42    {
43      rootKeys = [[NSArray arrayWithObjects:
44	PCClasses,
45	PCHeaders,
46	PCOtherSources,
47	PCOtherResources,
48	PCSubprojects,
49	PCDocuFiles,
50	PCSupportingFiles,
51	PCLibraries,
52	PCNonProject,
53	nil] retain];
54
55      rootCategories = [[NSArray arrayWithObjects:
56	@"Classes",
57	@"Headers",
58	@"Other Sources",
59	@"Other Resources",
60	@"Subprojects",
61	@"Documentation",
62	@"Supporting Files",
63	@"Libraries",
64	@"Non Project Files",
65	nil] retain];
66
67      rootEntries = [[NSDictionary
68	dictionaryWithObjects:rootCategories forKeys:rootKeys] retain];
69    }
70
71  return self;
72}
73
74- (void)dealloc
75{
76  [rootCategories release];
77  [rootKeys release];
78  [rootEntries release];
79
80  [super dealloc];
81}
82
83//----------------------------------------------------------------------------
84// --- PCProject overridings
85//----------------------------------------------------------------------------
86
87- (Class)builderClass
88{
89  return [PCFrameworkProject class];
90}
91
92// ----------------------------------------------------------------------------
93// --- ProjectType protocol
94// ----------------------------------------------------------------------------
95
96- (PCProject *)createProjectAt:(NSString *)path
97{
98//  PCFileManager *pcfm = [PCFileManager defaultManager];
99  PCFileCreator *pcfc = [PCFileCreator sharedCreator];
100  NSBundle      *projectBundle = nil;
101  NSString      *_file = nil;
102  NSString      *_2file = nil;
103//  NSString      *_resourcePath;
104
105  NSAssert(path,@"No valid project path provided!");
106
107  projectBundle = [NSBundle bundleForClass:[self class]];
108
109  _file = [projectBundle pathForResource:@"PC" ofType:@"project"];
110  [projectDict initWithContentsOfFile:_file];
111
112  // Customise the project
113  [self setProjectPath:path];
114  [self setProjectName:[path lastPathComponent]];
115  if ([[projectName pathExtension] isEqualToString:@"subproj"])
116    {
117      projectName = [projectName stringByDeletingPathExtension];
118    }
119  [projectDict setObject:projectName forKey:PCProjectName];
120  [projectDict setObject:[NSUserDefaults userLanguages] forKey:PCUserLanguages];
121
122  // Copy the project files to the provided path
123
124  // $PROJECTNAME$.m
125  _file = [NSString stringWithFormat:@"%@", projectName];
126  _2file = [NSString stringWithFormat:@"%@.m", projectName];
127  [pcfc createFileOfType:ObjCClass
128                    path:[path stringByAppendingPathComponent:_file]
129                 project:self];
130  [projectDict setObject:[NSArray arrayWithObjects:_2file,nil]
131                  forKey:PCClasses];
132
133  // $PROJECTNAME$.h already created by creating $PROJECTNAME$.m
134  _file = [NSString stringWithFormat:@"%@.h", projectName];
135  [projectDict setObject:[NSArray arrayWithObjects:_file,nil]
136                  forKey:PCHeaders];
137  [projectDict setObject:[NSArray arrayWithObjects:_file,nil]
138                  forKey:PCPublicHeaders];
139
140  // GNUmakefile.postamble
141  [[PCMakefileFactory sharedFactory] createPostambleForProject:self];
142
143  // Resources
144//  _resourcePath = [path stringByAppendingPathComponent:@"Resources"];
145
146  // Save the project to disc
147  [self writeMakefile];
148  [self save];
149
150  return self;
151}
152
153// ----------------------------------------------------------------------------
154// --- File Handling
155// ----------------------------------------------------------------------------
156
157- (void)addFiles:(NSArray *)files forKey:(NSString *)type notify:(BOOL)yn
158{
159  if ([type isEqualToString:PCHeaders])
160    {
161      [super addFiles:files forKey:PCPublicHeaders notify:NO];
162    }
163
164  [super addFiles:files forKey:type notify:YES];
165}
166
167- (BOOL)renameFile:(NSString *)fromFile toFile:(NSString *)toFile
168{
169  NSString *category = [projectBrowser nameOfSelectedCategory];
170  BOOL     success = NO;
171  BOOL     isPublicHeader = YES;
172
173  isPublicHeader =
174    [[projectDict objectForKey:PCPublicHeaders] containsObject:fromFile];
175
176  success = [super renameFile:fromFile toFile:toFile];
177
178  if (success && [category isEqualToString:[super categoryForKey:PCHeaders]])
179    {
180      if (isPublicHeader == NO)
181	{
182	  [self setHeaderFile:toFile public:NO];
183	}
184    }
185
186  return success;
187}
188
189@end
190
191@implementation PCFrameworkProject (GeneratedFiles)
192
193- (BOOL)writeMakefile
194{
195  PCMakefileFactory *mf = [PCMakefileFactory sharedFactory];
196  NSUInteger        i,count;
197  NSString          *mfl = nil;
198  NSData            *mfd = nil;
199  NSString          *key = nil;
200  NSMutableArray    *resources = nil;
201  NSArray           *localizedResources = nil;
202
203  // Save the GNUmakefile backup
204  [super writeMakefile];
205
206  // Save GNUmakefile.preamble
207  [mf createPreambleForProject:self];
208
209  // Create the new file
210  [mf createMakefileForProject:self];
211
212  // Head
213  [self appendHead:mf];
214
215  // Libraries depend upon
216  [mf appendLibraries:[projectDict objectForKey:PCLibraries]];
217
218  // Subprojects
219  if ([[projectDict objectForKey:PCSubprojects] count] > 0)
220    {
221      [mf appendSubprojects:[projectDict objectForKey:PCSubprojects]];
222    }
223
224  // Resources
225  count = [[self resourceFileKeys] count];
226  resources = [[NSMutableArray alloc] initWithCapacity:1];
227  // Gather all resource files into one array
228  for (i = 0; i < count; i++)
229    {
230      key = [[self resourceFileKeys] objectAtIndex:i];
231
232      [resources addObjectsFromArray:[projectDict objectForKey:key]];
233    }
234  // Remove localized resource files from gathered array
235  localizedResources = [projectDict objectForKey:PCLocalizedResources];
236  for (i = [resources count]; i > 0; i--)
237    {
238      if ([localizedResources containsObject:[resources objectAtIndex:i-1]])
239	{
240	  [resources removeObjectAtIndex:i-1];
241	}
242    }
243  [mf appendResources:resources inDir:@"Resources"];
244  [resources release];
245
246  // Localization
247  [mf appendLocalizedResources:localizedResources
248		  forLanguages:[projectDict objectForKey:PCUserLanguages]];
249
250  // Sources
251  [self appendPublicHeaders:mf];
252  [mf appendClasses:[projectDict objectForKey:PCClasses]];
253  [mf appendOtherSources:[projectDict objectForKey:PCOtherSources]];
254
255  // Tail
256  [self appendTail:mf];
257
258  // Write the new file to disc!
259  mfl = [projectPath stringByAppendingPathComponent:@"GNUmakefile"];
260  if ((mfd = [mf encodedMakefile]))
261    {
262      if ([mfd writeToFile:mfl atomically:YES])
263	{
264	  return YES;
265	}
266    }
267
268  return NO;
269}
270
271- (void)appendHead:(PCMakefileFactory *)mff
272{
273  [mff appendString:@"\n#\n# Framework\n#\n"];
274  [mff appendString:[NSString stringWithFormat:@"VERSION = %@\n",
275    [projectDict objectForKey:PCRelease]]];
276  [mff appendString:[NSString stringWithFormat:@"FRAMEWORK_NAME = %@\n",
277    projectName]];
278  [mff appendString:[NSString
279    stringWithFormat:@"%@_CURRENT_VERSION_NAME = %@\n",
280    projectName, [projectDict objectForKey:PCRelease]]];
281  [mff appendString:[NSString
282    stringWithFormat:@"%@_DEPLOY_WITH_CURRENT_VERSION = yes\n", projectName]];
283}
284
285- (void)appendPublicHeaders:(PCMakefileFactory *)mff
286{
287  NSArray *array = [projectDict objectForKey:PCPublicHeaders];
288
289  if (array == nil || [array count] == 0)
290    {
291      return;
292    }
293
294  [mff appendString:@"\n\n#\n# Public headers (will be installed)\n#\n"];
295
296  [mff appendString:[NSString stringWithFormat:@"%@_HEADER_FILES = ",
297                     projectName]];
298
299  if (array && [array count])
300    {
301      NSString     *tmp;
302      NSEnumerator *enumerator = [array objectEnumerator];
303
304      while ((tmp = [enumerator nextObject]))
305	{
306	  [mff appendString:[NSString stringWithFormat:@"\\\n%@ ",tmp]];
307	}
308    }
309}
310
311- (void)appendTail:(PCMakefileFactory *)mff
312{
313  [mff appendString:@"\n\n#\n# Makefiles\n#\n"];
314  [mff appendString:@"-include GNUmakefile.preamble\n"];
315  [mff appendString:@"include $(GNUSTEP_MAKEFILES)/aggregate.make\n"];
316  [mff appendString:@"include $(GNUSTEP_MAKEFILES)/framework.make\n"];
317  [mff appendString:@"-include GNUmakefile.postamble\n"];
318}
319
320@end
321
322@implementation PCFrameworkProject (Inspector)
323
324- (NSView *)projectAttributesView
325{
326  if (projectAttributesView == nil)
327    {
328      if ([NSBundle loadNibNamed:@"Inspector" owner:self] == NO)
329	{
330	  NSLog(@"PCFrameworkProject: error loading Inspector NIB!");
331	  return nil;
332	}
333      [projectAttributesView retain];
334      [self updateInspectorValues:nil];
335    }
336
337  return projectAttributesView;
338}
339
340- (void)updateInspectorValues:(NSNotification *)aNotif
341{
342  [principalClassField
343    setStringValue:[projectDict objectForKey:PCPrincipalClass]];
344}
345
346- (void)setPrincipalClass:(id)sender
347{
348  [self setProjectDictObject:[principalClassField stringValue]
349                      forKey:PCPrincipalClass
350		      notify:YES];
351}
352
353
354@end
355
356