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