xref: /haiku/src/apps/icon-o-matic/import_export/Exporter.cpp (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
1 /*
2  * Copyright 2006, 2011, Stephan Aßmus <superstippi@gmx.de>.
3  * All rights reserved. Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "Exporter.h"
8 
9 #include <fs_attr.h>
10 #include <new>
11 #include <stdio.h>
12 
13 #include <Alert.h>
14 #include <Catalog.h>
15 #include <File.h>
16 #include <Locale.h>
17 #include <Node.h>
18 #include <NodeInfo.h>
19 #include <Path.h>
20 #include <Roster.h>
21 #include <String.h>
22 
23 #include "CommandStack.h"
24 #include "Document.h"
25 #include "Icon.h"
26 
27 
28 #undef B_TRANSLATION_CONTEXT
29 #define B_TRANSLATION_CONTEXT "Icon-O-Matic-Exporter"
30 
31 
32 using std::nothrow;
33 
34 
35 Exporter::Exporter()
36 	: fDocument(NULL),
37 	  fClonedIcon(NULL),
38 	  fRef(),
39 	  fExportThread(-1),
40 	  fSelfDestroy(false)
41 {
42 }
43 
44 
45 Exporter::~Exporter()
46 {
47 	WaitForExportThread();
48 
49 	delete fClonedIcon;
50 }
51 
52 
53 status_t
54 Exporter::Export(Document* document, const entry_ref& ref)
55 {
56 	if (!document || ref.name == NULL)
57 		return B_BAD_VALUE;
58 
59 	fDocument = document;
60 	fClonedIcon = fDocument->Icon()->Clone();
61 	if (!fClonedIcon)
62 		return B_NO_MEMORY;
63 
64 	fRef = ref;
65 
66 	fExportThread = spawn_thread(_ExportThreadEntry, "export",
67 								 B_NORMAL_PRIORITY, this);
68 	if (fExportThread < 0)
69 		return (status_t)fExportThread;
70 
71 	resume_thread(fExportThread);
72 
73 	return B_OK;
74 }
75 
76 
77 void
78 Exporter::SetSelfDestroy(bool selfDestroy)
79 {
80 	fSelfDestroy = selfDestroy;
81 }
82 
83 
84 void
85 Exporter::WaitForExportThread()
86 {
87 	if (fExportThread >= 0 && find_thread(NULL) != fExportThread) {
88 		status_t ret;
89 		wait_for_thread(fExportThread, &ret);
90 		fExportThread = -1;
91 	}
92 }
93 
94 
95 // #pragma mark -
96 
97 
98 int32
99 Exporter::_ExportThreadEntry(void* cookie)
100 {
101 	Exporter* exporter = (Exporter*)cookie;
102 	return exporter->_ExportThread();
103 }
104 
105 
106 int32
107 Exporter::_ExportThread()
108 {
109 	status_t ret = _Export(fClonedIcon, &fRef);
110 	if (ret < B_OK) {
111 		// inform user of failure at this point
112 		BString helper(B_TRANSLATE("Saving your document failed!"));
113 		helper << "\n\n" << ErrorCodeToString(ret);
114 		BAlert* alert = new BAlert(B_TRANSLATE_CONTEXT("Bad news", "Title of error alert"),
115 			helper.String(),
116 			B_TRANSLATE_COMMENT("Bleep!", "Exporter - Continue in error dialog"),
117 			NULL, NULL, B_WIDTH_AS_USUAL, B_STOP_ALERT);
118 		// launch alert asynchronously
119 		alert->SetFlags(alert->Flags() | B_CLOSE_ON_ESCAPE);
120 		alert->Go(NULL);
121 	} else {
122 		// success
123 
124 		// add to recent document list
125 		be_roster->AddToRecentDocuments(&fRef);
126 		// mark command stack state as saved,
127 		fDocument->CommandStack()->Save();
128 			// NOTE: CommandStack is thread safe
129 
130 		if (fDocument->WriteLock()) {
131 			// set ref and name of document
132 //			fDocument->SetRef(fRef);
133 			fDocument->SetName(fRef.name);
134 
135 			fDocument->WriteUnlock();
136 		}
137 	}
138 
139 	if (fSelfDestroy)
140 		delete this;
141 
142 	return ret;
143 }
144 
145 
146 status_t
147 Exporter::_Export(const Icon* icon, const entry_ref* docRef)
148 {
149 	// TODO: reenable the commented out code, but make it work
150 	// the opposite direction, ie *copy* the file contents
151 
152 	BEntry entry(docRef, true);
153 	if (entry.IsDirectory())
154 		return B_BAD_VALUE;
155 
156 	const entry_ref* ref = docRef;
157 //	entry_ref tempRef;
158 //
159 //	if (entry.Exists()) {
160 //		// if the file exists create a temporary file in the same folder
161 //		// and hope that it doesn't already exist...
162 //		BPath tempPath(docRef);
163 //		if (tempPath.GetParent(&tempPath) >= B_OK) {
164 //			BString helper(docRef->name);
165 //			helper << system_time();
166 //			if (tempPath.Append(helper.String()) >= B_OK
167 //				&& entry.SetTo(tempPath.Path()) >= B_OK
168 //				&& entry.GetRef(&tempRef) >= B_OK) {
169 //				// have the output ref point to the temporary
170 //				// file instead
171 //				ref = &tempRef;
172 //			}
173 //		}
174 //	}
175 
176 	status_t ret = B_BAD_VALUE;
177 
178 	// do the actual save operation into a file
179 	BFile outFile(ref, B_CREATE_FILE | B_READ_WRITE | B_ERASE_FILE);
180 	ret = outFile.InitCheck();
181 	if (ret == B_OK) {
182 		try {
183 			// export using the virtual Export() version
184 			ret = Export(icon, &outFile);
185 		} catch (...) {
186 			printf("Exporter::_Export() - "
187 				   "unkown exception occured!\n");
188 			ret = B_ERROR;
189 		}
190 		if (ret < B_OK) {
191 			printf("Exporter::_Export() - "
192 				   "failed to export icon: %s\n", strerror(ret));
193 		}
194 	} else {
195 		printf("Exporter::_Export() - "
196 			   "failed to create output file: %s\n", strerror(ret));
197 	}
198 	outFile.Unset();
199 
200 //	if (ret < B_OK && ref != docRef) {
201 //		// in case of failure, remove temporary file
202 //		entry.Remove();
203 //	}
204 //
205 //	if (ret >= B_OK && ref != docRef) {
206 //		// move temp file overwriting actual document file
207 //		BEntry docEntry(docRef, true);
208 //		// copy attributes of previous document file
209 //		BNode sourceNode(&docEntry);
210 //		BNode destNode(&entry);
211 //		if (sourceNode.InitCheck() >= B_OK && destNode.InitCheck() >= B_OK) {
212 //			// lock the nodes
213 //			if (sourceNode.Lock() >= B_OK) {
214 //				if (destNode.Lock() >= B_OK) {
215 //					// iterate over the attributes
216 //					char attrName[B_ATTR_NAME_LENGTH];
217 //					while (sourceNode.GetNextAttrName(attrName) >= B_OK) {
218 ////						// skip the icon, since we probably wrote that
219 ////						// before
220 ////						if (strcmp(attrName, "BEOS:ICON") == 0)
221 ////							continue;
222 //						attr_info info;
223 //						if (sourceNode.GetAttrInfo(attrName, &info) >= B_OK) {
224 //							char *buffer = new (nothrow) char[info.size];
225 //							if (buffer && sourceNode.ReadAttr(attrName, info.type, 0,
226 //															  buffer, info.size) == info.size) {
227 //								destNode.WriteAttr(attrName, info.type, 0,
228 //												   buffer, info.size);
229 //							}
230 //							delete[] buffer;
231 //						}
232 //					}
233 //					destNode.Unlock();
234 //				}
235 //				sourceNode.Unlock();
236 //			}
237 //		}
238 //		// clobber the orginal file with the new temporary one
239 //		ret = entry.Rename(docRef->name, true);
240 //	}
241 
242 	if (ret >= B_OK && MIMEType()) {
243 		// set file type
244 		BNode node(docRef);
245 		if (node.InitCheck() == B_OK) {
246 			BNodeInfo nodeInfo(&node);
247 			if (nodeInfo.InitCheck() == B_OK)
248 				nodeInfo.SetType(MIMEType());
249 		}
250 	}
251 	return ret;
252 }
253