xref: /haiku/src/apps/icon-o-matic/import_export/Exporter.cpp (revision 1f3678c17932184598bc317740b71f593629f059)
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_TRANSLATE_CONTEXT
29 #define B_TRANSLATE_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" << B_TRANSLATE("Error: ") << strerror(ret);
114 		BAlert* alert = new BAlert(B_TRANSLATE("bad news"), helper.String(),
115 			B_TRANSLATE_WITH_CONTEXT("Bleep!",
116 				"Exporter - Continue in error dialog"),
117 			NULL, NULL);
118 		// launch alert asynchronously
119 		alert->Go(NULL);
120 	} else {
121 		// success
122 
123 		// add to recent document list
124 		be_roster->AddToRecentDocuments(&fRef);
125 		// mark command stack state as saved,
126 		fDocument->CommandStack()->Save();
127 			// NOTE: CommandStack is thread safe
128 
129 		if (fDocument->WriteLock()) {
130 			// set ref and name of document
131 //			fDocument->SetRef(fRef);
132 			fDocument->SetName(fRef.name);
133 
134 			fDocument->WriteUnlock();
135 		}
136 	}
137 
138 	if (fSelfDestroy)
139 		delete this;
140 
141 	return ret;
142 }
143 
144 
145 status_t
146 Exporter::_Export(const Icon* icon, const entry_ref* docRef)
147 {
148 	// TODO: reenable the commented out code, but make it work
149 	// the opposite direction, ie *copy* the file contents
150 
151 	BEntry entry(docRef, true);
152 	if (entry.IsDirectory())
153 		return B_BAD_VALUE;
154 
155 	const entry_ref* ref = docRef;
156 //	entry_ref tempRef;
157 //
158 //	if (entry.Exists()) {
159 //		// if the file exists create a temporary file in the same folder
160 //		// and hope that it doesn't already exist...
161 //		BPath tempPath(docRef);
162 //		if (tempPath.GetParent(&tempPath) >= B_OK) {
163 //			BString helper(docRef->name);
164 //			helper << system_time();
165 //			if (tempPath.Append(helper.String()) >= B_OK
166 //				&& entry.SetTo(tempPath.Path()) >= B_OK
167 //				&& entry.GetRef(&tempRef) >= B_OK) {
168 //				// have the output ref point to the temporary
169 //				// file instead
170 //				ref = &tempRef;
171 //			}
172 //		}
173 //	}
174 
175 	status_t ret = B_BAD_VALUE;
176 
177 	// do the actual save operation into a file
178 	BFile outFile(ref, B_CREATE_FILE | B_READ_WRITE | B_ERASE_FILE);
179 	ret = outFile.InitCheck();
180 	if (ret == B_OK) {
181 		try {
182 			// export using the virtual Export() version
183 			ret = Export(icon, &outFile);
184 		} catch (...) {
185 			printf("Exporter::_Export() - "
186 				   "unkown exception occured!\n");
187 			ret = B_ERROR;
188 		}
189 		if (ret < B_OK) {
190 			printf("Exporter::_Export() - "
191 				   "failed to export icon: %s\n", strerror(ret));
192 		}
193 	} else {
194 		printf("Exporter::_Export() - "
195 			   "failed to create output file: %s\n", strerror(ret));
196 	}
197 	outFile.Unset();
198 
199 //	if (ret < B_OK && ref != docRef) {
200 //		// in case of failure, remove temporary file
201 //		entry.Remove();
202 //	}
203 //
204 //	if (ret >= B_OK && ref != docRef) {
205 //		// move temp file overwriting actual document file
206 //		BEntry docEntry(docRef, true);
207 //		// copy attributes of previous document file
208 //		BNode sourceNode(&docEntry);
209 //		BNode destNode(&entry);
210 //		if (sourceNode.InitCheck() >= B_OK && destNode.InitCheck() >= B_OK) {
211 //			// lock the nodes
212 //			if (sourceNode.Lock() >= B_OK) {
213 //				if (destNode.Lock() >= B_OK) {
214 //					// iterate over the attributes
215 //					char attrName[B_ATTR_NAME_LENGTH];
216 //					while (sourceNode.GetNextAttrName(attrName) >= B_OK) {
217 ////						// skip the icon, since we probably wrote that
218 ////						// before
219 ////						if (strcmp(attrName, "BEOS:ICON") == 0)
220 ////							continue;
221 //						attr_info info;
222 //						if (sourceNode.GetAttrInfo(attrName, &info) >= B_OK) {
223 //							char *buffer = new (nothrow) char[info.size];
224 //							if (buffer && sourceNode.ReadAttr(attrName, info.type, 0,
225 //															  buffer, info.size) == info.size) {
226 //								destNode.WriteAttr(attrName, info.type, 0,
227 //												   buffer, info.size);
228 //							}
229 //							delete[] buffer;
230 //						}
231 //					}
232 //					destNode.Unlock();
233 //				}
234 //				sourceNode.Unlock();
235 //			}
236 //		}
237 //		// clobber the orginal file with the new temporary one
238 //		ret = entry.Rename(docRef->name, true);
239 //	}
240 
241 	if (ret >= B_OK && MIMEType()) {
242 		// set file type
243 		BNode node(docRef);
244 		if (node.InitCheck() == B_OK) {
245 			BNodeInfo nodeInfo(&node);
246 			if (nodeInfo.InitCheck() == B_OK)
247 				nodeInfo.SetType(MIMEType());
248 		}
249 	}
250 	return ret;
251 }
252