use BLI_strncpy and BLI_snprintf when the size of the string is known.
[blender.git] / source / blender / editors / space_info / info_ops.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2008 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/editors/space_info/info_ops.c
28  *  \ingroup spinfo
29  */
30
31
32 #include <string.h>
33 #include <stdio.h>
34
35 #include "DNA_packedFile_types.h"
36 #include "DNA_space_types.h"
37 #include "DNA_windowmanager_types.h"
38
39 #include "MEM_guardedalloc.h"
40
41 #include "BLI_blenlib.h"
42 #include "BLI_math.h"
43 #include "BLI_bpath.h"
44 #include "BLI_utildefines.h"
45
46 #include "BKE_context.h"
47 #include "BKE_global.h"
48 #include "BKE_image.h"
49 #include "BKE_main.h"
50 #include "BKE_packedFile.h"
51 #include "BKE_report.h"
52
53
54 #include "WM_api.h"
55 #include "WM_types.h"
56
57
58 #include "UI_interface.h"
59 #include "UI_resources.h"
60
61 #include "IMB_imbuf_types.h"
62
63 #include "RNA_access.h"
64 #include "RNA_define.h"
65
66
67 #include "info_intern.h"
68
69 /********************* pack all operator *********************/
70
71 static int pack_all_exec(bContext *C, wmOperator *op)
72 {
73         Main *bmain= CTX_data_main(C);
74
75         packAll(bmain, op->reports);
76         G.fileflags |= G_AUTOPACK;
77
78         return OPERATOR_FINISHED;
79 }
80
81 static int pack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
82 {
83         Main *bmain= CTX_data_main(C);
84         Image *ima;
85         ImBuf *ibuf;
86
87         // first check for dirty images
88         for(ima=bmain->image.first; ima; ima=ima->id.next) {
89                 if(ima->ibufs.first) { /* XXX FIX */
90                         ibuf= BKE_image_get_ibuf(ima, NULL);
91                         
92                         if(ibuf && (ibuf->userflags & IB_BITMAPDIRTY))
93                                 break;
94                 }
95         }
96
97         if(ima) {
98                 uiPupMenuOkee(C, "FILE_OT_pack_all", "Some images are painted on. These changes will be lost. Continue?");
99                 return OPERATOR_CANCELLED;
100         }
101
102         return pack_all_exec(C, op);
103 }
104
105 void FILE_OT_pack_all(wmOperatorType *ot)
106 {
107         /* identifiers */
108         ot->name= "Pack All";
109         ot->idname= "FILE_OT_pack_all";
110         
111         /* api callbacks */
112         ot->exec= pack_all_exec;
113         ot->invoke= pack_all_invoke;
114
115         /* flags */
116         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
117 }
118
119 /********************* unpack all operator *********************/
120
121 static const EnumPropertyItem unpack_all_method_items[] = {
122         {PF_USE_LOCAL, "USE_LOCAL", 0, "Use files in current directory (create when necessary)", ""},
123         {PF_WRITE_LOCAL, "WRITE_LOCAL", 0, "Write files to current directory (overwrite existing files)", ""},
124         {PF_USE_ORIGINAL, "USE_ORIGINAL", 0, "Use files in original location (create when necessary)", ""},
125         {PF_WRITE_ORIGINAL, "WRITE_ORIGINAL", 0, "Write files to original location (overwrite existing files)", ""},
126         {PF_KEEP, "KEEP", 0, "Disable AutoPack, keep all packed files", ""},
127         {PF_ASK, "ASK", 0, "Ask for each file", ""},
128         {0, NULL, 0, NULL, NULL}};
129
130 static int unpack_all_exec(bContext *C, wmOperator *op)
131 {
132         Main *bmain= CTX_data_main(C);
133         int method= RNA_enum_get(op->ptr, "method");
134
135         if(method != PF_KEEP) unpackAll(bmain, op->reports, method); /* XXX PF_ASK can't work here */
136         G.fileflags &= ~G_AUTOPACK;
137
138         return OPERATOR_FINISHED;
139 }
140
141 static int unpack_all_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
142 {
143         Main *bmain= CTX_data_main(C);
144         uiPopupMenu *pup;
145         uiLayout *layout;
146         char title[64];
147         int count = 0;
148         
149         count = countPackedFiles(bmain);
150         
151         if(!count) {
152                 BKE_report(op->reports, RPT_WARNING, "No packed files. Autopack disabled");
153                 G.fileflags &= ~G_AUTOPACK;
154                 return OPERATOR_CANCELLED;
155         }
156
157         if(count == 1)
158                 strcpy(title, "Unpack 1 file");
159         else
160                 BLI_snprintf(title, sizeof(title), "Unpack %d files", count);
161         
162         pup= uiPupMenuBegin(C, title, ICON_NONE);
163         layout= uiPupMenuLayout(pup);
164
165         uiLayoutSetOperatorContext(layout, WM_OP_EXEC_DEFAULT);
166         uiItemsEnumO(layout, "FILE_OT_unpack_all", "method");
167
168         uiPupMenuEnd(C, pup);
169
170         return OPERATOR_CANCELLED;
171 }
172
173 void FILE_OT_unpack_all(wmOperatorType *ot)
174 {
175         /* identifiers */
176         ot->name= "Unpack All";
177         ot->idname= "FILE_OT_unpack_all";
178         
179         /* api callbacks */
180         ot->exec= unpack_all_exec;
181         ot->invoke= unpack_all_invoke;
182
183         /* flags */
184         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
185
186         /* properties */
187         RNA_def_enum(ot->srna, "method", unpack_all_method_items, PF_USE_LOCAL, "Method", "How to unpack");
188 }
189
190 /********************* make paths relative operator *********************/
191
192 static int make_paths_relative_exec(bContext *C, wmOperator *op)
193 {
194         Main *bmain= CTX_data_main(C);
195
196         if(!G.relbase_valid) {
197                 BKE_report(op->reports, RPT_WARNING, "Can't set relative paths with an unsaved blend file");
198                 return OPERATOR_CANCELLED;
199         }
200
201         makeFilesRelative(bmain, bmain->name, op->reports);
202
203         /* redraw everything so any changed paths register */
204         WM_main_add_notifier(NC_WINDOW, NULL);
205
206         return OPERATOR_FINISHED;
207 }
208
209 void FILE_OT_make_paths_relative(wmOperatorType *ot)
210 {
211         /* identifiers */
212         ot->name= "Make All Paths Relative";
213         ot->idname= "FILE_OT_make_paths_relative";
214         
215         /* api callbacks */
216         ot->exec= make_paths_relative_exec;
217
218         /* flags */
219         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
220 }
221
222 /********************* make paths absolute operator *********************/
223
224 static int make_paths_absolute_exec(bContext *C, wmOperator *op)
225 {
226         Main *bmain= CTX_data_main(C);
227
228         if(!G.relbase_valid) {
229                 BKE_report(op->reports, RPT_WARNING, "Can't set absolute paths with an unsaved blend file");
230                 return OPERATOR_CANCELLED;
231         }
232
233         makeFilesAbsolute(bmain, bmain->name, op->reports);
234
235         /* redraw everything so any changed paths register */
236         WM_main_add_notifier(NC_WINDOW, NULL);
237
238         return OPERATOR_FINISHED;
239 }
240
241 void FILE_OT_make_paths_absolute(wmOperatorType *ot)
242 {
243         /* identifiers */
244         ot->name= "Make All Paths Absolute";
245         ot->idname= "FILE_OT_make_paths_absolute";
246         
247         /* api callbacks */
248         ot->exec= make_paths_absolute_exec;
249
250         /* flags */
251         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
252 }
253
254 /********************* report missing files operator *********************/
255
256 static int report_missing_files_exec(bContext *C, wmOperator *op)
257 {
258         Main *bmain= CTX_data_main(C);
259
260         /* run the missing file check */
261         checkMissingFiles(bmain, op->reports);
262         
263         return OPERATOR_FINISHED;
264 }
265
266 void FILE_OT_report_missing_files(wmOperatorType *ot)
267 {
268         /* identifiers */
269         ot->name= "Report Missing Files";
270         ot->idname= "FILE_OT_report_missing_files";
271         
272         /* api callbacks */
273         ot->exec= report_missing_files_exec;
274
275         /* flags */
276         ot->flag= 0; /* only reports so no need to undo/register */
277 }
278
279 /********************* find missing files operator *********************/
280
281 static int find_missing_files_exec(bContext *C, wmOperator *op)
282 {
283         Main *bmain= CTX_data_main(C);
284         const char *searchpath= RNA_string_get_alloc(op->ptr, "filepath", NULL, 0);
285         findMissingFiles(bmain, searchpath, op->reports);
286         MEM_freeN((void *)searchpath);
287
288         return OPERATOR_FINISHED;
289 }
290
291 static int find_missing_files_invoke(bContext *C, wmOperator *op, wmEvent *UNUSED(event))
292 {
293         /* XXX file open button text "Find Missing Files" */
294         WM_event_add_fileselect(C, op); 
295         return OPERATOR_RUNNING_MODAL;
296 }
297
298 void FILE_OT_find_missing_files(wmOperatorType *ot)
299 {
300         /* identifiers */
301         ot->name= "Find Missing Files";
302         ot->idname= "FILE_OT_find_missing_files";
303         
304         /* api callbacks */
305         ot->exec= find_missing_files_exec;
306         ot->invoke= find_missing_files_invoke;
307
308         /* flags */
309         ot->flag= OPTYPE_REGISTER|OPTYPE_UNDO;
310
311         /* properties */
312         WM_operator_properties_filesel(ot, 0, FILE_SPECIAL, FILE_OPENFILE, WM_FILESEL_FILEPATH);
313 }
314
315 /********************* report box operator *********************/
316
317 /* Hard to decide whether to keep this as an operator, 
318  * or turn it into a hardcoded ui control feature, 
319  * handling TIMER events for all regions in interface_handlers.c
320  * Not sure how good that is to be accessing UI data from 
321  * inactive regions, so use this for now. --matt
322  */
323
324 #define INFO_TIMEOUT            5.0f
325 #define INFO_COLOR_TIMEOUT      3.0f
326 #define ERROR_TIMEOUT           10.0f
327 #define ERROR_COLOR_TIMEOUT     6.0f
328 #define COLLAPSE_TIMEOUT        0.25f
329 static int update_reports_display_invoke(bContext *C, wmOperator *UNUSED(op), wmEvent *event)
330 {
331         wmWindowManager *wm= CTX_wm_manager(C);
332         ReportList *reports= CTX_wm_reports(C);
333         Report *report;
334         ReportTimerInfo *rti;
335         float progress=0.0, color_progress=0.0;
336         float neutral_col[3] = {0.35, 0.35, 0.35};
337         float neutral_grey= 0.6;
338         float timeout=0.0, color_timeout=0.0;
339         int send_note= 0;
340         
341         /* escape if not our timer */
342         if(             (reports->reporttimer==NULL) ||
343                         (reports->reporttimer != event->customdata) ||
344                         ((report= BKE_reports_last_displayable(reports))==NULL) /* may have been deleted */
345         ) {
346                 return OPERATOR_PASS_THROUGH;
347         }
348
349         rti = (ReportTimerInfo *)reports->reporttimer->customdata;
350         
351         timeout = (report->type & RPT_ERROR_ALL)?ERROR_TIMEOUT:INFO_TIMEOUT;
352         color_timeout = (report->type & RPT_ERROR_ALL)?ERROR_COLOR_TIMEOUT:INFO_COLOR_TIMEOUT;
353         
354         /* clear the report display after timeout */
355         if ((float)reports->reporttimer->duration > timeout) {
356                 WM_event_remove_timer(wm, NULL, reports->reporttimer);
357                 reports->reporttimer = NULL;
358                 
359                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_INFO, NULL);
360                 
361                 return (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH);
362         }
363
364         if (rti->widthfac == 0.0f) {
365                 /* initialise colors based on report type */
366                 if(report->type & RPT_ERROR_ALL) {
367                         rti->col[0] = 1.0;
368                         rti->col[1] = 0.2;
369                         rti->col[2] = 0.0;
370                 } else if(report->type & RPT_WARNING_ALL) {
371                         rti->col[0] = 1.0;
372                         rti->col[1] = 1.0;
373                         rti->col[2] = 0.0;
374                 } else if(report->type & RPT_INFO_ALL) {
375                         rti->col[0] = 0.3;
376                         rti->col[1] = 0.45;
377                         rti->col[2] = 0.7;
378                 }
379                 rti->greyscale = 0.75;
380                 rti->widthfac=1.0;
381         }
382         
383         progress = (float)reports->reporttimer->duration / timeout;
384         color_progress = (float)reports->reporttimer->duration / color_timeout;
385         
386         /* save us from too many draws */
387         if(color_progress <= 1.0f) {
388                 send_note= 1;
389                 
390                 /* fade colors out sharply according to progress through fade-out duration */
391                 interp_v3_v3v3(rti->col, rti->col, neutral_col, color_progress);
392                 rti->greyscale = interpf(neutral_grey, rti->greyscale, color_progress);
393         }
394
395         /* collapse report at end of timeout */
396         if (progress*timeout > timeout - COLLAPSE_TIMEOUT) {
397                 rti->widthfac = (progress*timeout - (timeout - COLLAPSE_TIMEOUT)) / COLLAPSE_TIMEOUT;
398                 rti->widthfac = 1.0f - rti->widthfac;
399                 send_note= 1;
400         }
401         
402         if(send_note) {
403                 WM_event_add_notifier(C, NC_SPACE|ND_SPACE_INFO, NULL);
404         }
405         
406         return (OPERATOR_FINISHED|OPERATOR_PASS_THROUGH);
407 }
408
409 void INFO_OT_reports_display_update(wmOperatorType *ot)
410 {
411         /* identifiers */
412         ot->name= "Update Reports Display";
413         ot->idname= "INFO_OT_reports_display_update";
414         
415         /* api callbacks */
416         ot->invoke= update_reports_display_invoke;
417         
418         /* flags */
419         ot->flag= 0;
420         
421         /* properties */
422 }
423
424 /* report operators */