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 32using std::nothrow; 33 34 35Exporter::Exporter() 36 : fDocument(NULL), 37 fClonedIcon(NULL), 38 fRef(), 39 fExportThread(-1), 40 fSelfDestroy(false) 41{ 42} 43 44 45Exporter::~Exporter() 46{ 47 WaitForExportThread(); 48 49 delete fClonedIcon; 50} 51 52 53status_t 54Exporter::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 77void 78Exporter::SetSelfDestroy(bool selfDestroy) 79{ 80 fSelfDestroy = selfDestroy; 81} 82 83 84void 85Exporter::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 98int32 99Exporter::_ExportThreadEntry(void* cookie) 100{ 101 Exporter* exporter = (Exporter*)cookie; 102 return exporter->_ExportThread(); 103} 104 105 106int32 107Exporter::_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 146status_t 147Exporter::_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