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