a9e55d5a6acd0a360b7be865d78377dbbd4f786c
[novacoin.git] / src / qt / transactiondesc.cpp
1 #include <transactiondesc.h>
2
3 #include "guiutil.h"
4 #include "main.h"
5 #include "externui.h"
6
7 #include <QString>
8
9 /* Taken straight from ui.cpp
10    TODO: Convert to use QStrings, Qt::Escape and tr()
11  */
12
13 using namespace std;
14
15 static string HtmlEscape(const char* psz, bool fMultiLine=false)
16 {
17     int len = 0;
18     for (const char* p = psz; *p; p++)
19     {
20              if (*p == '<') len += 4;
21         else if (*p == '>') len += 4;
22         else if (*p == '&') len += 5;
23         else if (*p == '"') len += 6;
24         else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') len += 6;
25         else if (*p == '\n' && fMultiLine) len += 5;
26         else
27             len++;
28     }
29     string str;
30     str.reserve(len);
31     for (const char* p = psz; *p; p++)
32     {
33              if (*p == '<') str += "&lt;";
34         else if (*p == '>') str += "&gt;";
35         else if (*p == '&') str += "&amp;";
36         else if (*p == '"') str += "&quot;";
37         else if (*p == ' ' && p > psz && p[-1] == ' ' && p[1] == ' ') str += "&nbsp;";
38         else if (*p == '\n' && fMultiLine) str += "<br>\n";
39         else
40             str += *p;
41     }
42     return str;
43 }
44
45 static string HtmlEscape(const string& str, bool fMultiLine=false)
46 {
47     return HtmlEscape(str.c_str(), fMultiLine);
48 }
49
50 static string FormatTxStatus(const CWalletTx& wtx)
51 {
52     // Status
53     if (!wtx.IsFinal())
54     {
55         if (wtx.nLockTime < 500000000)
56             return strprintf(_("Open for %d blocks"), nBestHeight - wtx.nLockTime);
57         else
58             return strprintf(_("Open until %s"), GUIUtil::DateTimeStr(wtx.nLockTime).toStdString().c_str());
59     }
60     else
61     {
62         int nDepth = wtx.GetDepthInMainChain();
63         if (GetAdjustedTime() - wtx.nTimeReceived > 2 * 60 && wtx.GetRequestCount() == 0)
64             return strprintf(_("%d/offline?"), nDepth);
65         else if (nDepth < 6)
66             return strprintf(_("%d/unconfirmed"), nDepth);
67         else
68             return strprintf(_("%d confirmations"), nDepth);
69     }
70 }
71
72 string TransactionDesc::toHTML(CWalletTx &wtx)
73 {
74     string strHTML;
75     CRITICAL_BLOCK(cs_mapAddressBook)
76     {
77         strHTML.reserve(4000);
78         strHTML += "<html><font face='verdana, arial, helvetica, sans-serif'>";
79
80         int64 nTime = wtx.GetTxTime();
81         int64 nCredit = wtx.GetCredit();
82         int64 nDebit = wtx.GetDebit();
83         int64 nNet = nCredit - nDebit;
84
85
86
87         strHTML += _("<b>Status:</b> ") + FormatTxStatus(wtx);
88         int nRequests = wtx.GetRequestCount();
89         if (nRequests != -1)
90         {
91             if (nRequests == 0)
92                 strHTML += _(", has not been successfully broadcast yet");
93             else if (nRequests == 1)
94                 strHTML += strprintf(_(", broadcast through %d node"), nRequests);
95             else
96                 strHTML += strprintf(_(", broadcast through %d nodes"), nRequests);
97         }
98         strHTML += "<br>";
99
100         strHTML += _("<b>Date:</b> ") + (nTime ? GUIUtil::DateTimeStr(nTime).toStdString() : "") + "<br>";
101
102
103         //
104         // From
105         //
106         if (wtx.IsCoinBase())
107         {
108             strHTML += _("<b>Source:</b> Generated<br>");
109         }
110         else if (!wtx.mapValue["from"].empty())
111         {
112             // Online transaction
113             if (!wtx.mapValue["from"].empty())
114                 strHTML += _("<b>From:</b> ") + HtmlEscape(wtx.mapValue["from"]) + "<br>";
115         }
116         else
117         {
118             // Offline transaction
119             if (nNet > 0)
120             {
121                 // Credit
122                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
123                 {
124                     if (txout.IsMine())
125                     {
126                         vector<unsigned char> vchPubKey;
127                         if (ExtractPubKey(txout.scriptPubKey, true, vchPubKey))
128                         {
129                             string strAddress = PubKeyToAddress(vchPubKey);
130                             if (mapAddressBook.count(strAddress))
131                             {
132                                 strHTML += string() + _("<b>From:</b> ") + _("unknown") + "<br>";
133                                 strHTML += _("<b>To:</b> ");
134                                 strHTML += HtmlEscape(strAddress);
135                                 if (!mapAddressBook[strAddress].empty())
136                                     strHTML += _(" (yours, label: ") + mapAddressBook[strAddress] + ")";
137                                 else
138                                     strHTML += _(" (yours)");
139                                 strHTML += "<br>";
140                             }
141                         }
142                         break;
143                     }
144                 }
145             }
146         }
147
148
149         //
150         // To
151         //
152         string strAddress;
153         if (!wtx.mapValue["to"].empty())
154         {
155             // Online transaction
156             strAddress = wtx.mapValue["to"];
157             strHTML += _("<b>To:</b> ");
158             if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
159                 strHTML += mapAddressBook[strAddress] + " ";
160             strHTML += HtmlEscape(strAddress) + "<br>";
161         }
162
163
164         //
165         // Amount
166         //
167         if (wtx.IsCoinBase() && nCredit == 0)
168         {
169             //
170             // Coinbase
171             //
172             int64 nUnmatured = 0;
173             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
174                 nUnmatured += txout.GetCredit();
175             strHTML += _("<b>Credit:</b> ");
176             if (wtx.IsInMainChain())
177                 strHTML += strprintf(_("(%s matures in %d more blocks)"), FormatMoney(nUnmatured).c_str(), wtx.GetBlocksToMaturity());
178             else
179                 strHTML += _("(not accepted)");
180             strHTML += "<br>";
181         }
182         else if (nNet > 0)
183         {
184             //
185             // Credit
186             //
187             strHTML += _("<b>Credit:</b> ") + FormatMoney(nNet) + "<br>";
188         }
189         else
190         {
191             bool fAllFromMe = true;
192             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
193                 fAllFromMe = fAllFromMe && txin.IsMine();
194
195             bool fAllToMe = true;
196             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
197                 fAllToMe = fAllToMe && txout.IsMine();
198
199             if (fAllFromMe)
200             {
201                 //
202                 // Debit
203                 //
204                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
205                 {
206                     if (txout.IsMine())
207                         continue;
208
209                     if (wtx.mapValue["to"].empty())
210                     {
211                         // Offline transaction
212                         uint160 hash160;
213                         if (ExtractHash160(txout.scriptPubKey, hash160))
214                         {
215                             string strAddress = Hash160ToAddress(hash160);
216                             strHTML += _("<b>To:</b> ");
217                             if (mapAddressBook.count(strAddress) && !mapAddressBook[strAddress].empty())
218                                 strHTML += mapAddressBook[strAddress] + " ";
219                             strHTML += strAddress;
220                             strHTML += "<br>";
221                         }
222                     }
223
224                     strHTML += _("<b>Debit:</b> ") + FormatMoney(-txout.nValue) + "<br>";
225                 }
226
227                 if (fAllToMe)
228                 {
229                     // Payment to self
230                     int64 nChange = wtx.GetChange();
231                     int64 nValue = nCredit - nChange;
232                     strHTML += _("<b>Debit:</b> ") + FormatMoney(-nValue) + "<br>";
233                     strHTML += _("<b>Credit:</b> ") + FormatMoney(nValue) + "<br>";
234                 }
235
236                 int64 nTxFee = nDebit - wtx.GetValueOut();
237                 if (nTxFee > 0)
238                     strHTML += _("<b>Transaction fee:</b> ") + FormatMoney(-nTxFee) + "<br>";
239             }
240             else
241             {
242                 //
243                 // Mixed debit transaction
244                 //
245                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
246                     if (txin.IsMine())
247                         strHTML += _("<b>Debit:</b> ") + FormatMoney(-txin.GetDebit()) + "<br>";
248                 BOOST_FOREACH(const CTxOut& txout, wtx.vout)
249                     if (txout.IsMine())
250                         strHTML += _("<b>Credit:</b> ") + FormatMoney(txout.GetCredit()) + "<br>";
251             }
252         }
253
254         strHTML += _("<b>Net amount:</b> ") + FormatMoney(nNet, true) + "<br>";
255
256
257         //
258         // Message
259         //
260         if (!wtx.mapValue["message"].empty())
261             strHTML += string() + "<br><b>" + _("Message:") + "</b><br>" + HtmlEscape(wtx.mapValue["message"], true) + "<br>";
262         if (!wtx.mapValue["comment"].empty())
263             strHTML += string() + "<br><b>" + _("Comment:") + "</b><br>" + HtmlEscape(wtx.mapValue["comment"], true) + "<br>";
264
265         if (wtx.IsCoinBase())
266             strHTML += string() + "<br>" + _("Generated coins must wait 120 blocks before they can be spent.  When you generated this block, it was broadcast to the network to be added to the block chain.  If it fails to get into the chain, it will change to \"not accepted\" and not be spendable.  This may occasionally happen if another node generates a block within a few seconds of yours.") + "<br>";
267
268
269         //
270         // Debug view
271         //
272         if (fDebug)
273         {
274             strHTML += "<hr><br>debug print<br><br>";
275             BOOST_FOREACH(const CTxIn& txin, wtx.vin)
276                 if (txin.IsMine())
277                     strHTML += "<b>Debit:</b> " + FormatMoney(-txin.GetDebit()) + "<br>";
278             BOOST_FOREACH(const CTxOut& txout, wtx.vout)
279                 if (txout.IsMine())
280                     strHTML += "<b>Credit:</b> " + FormatMoney(txout.GetCredit()) + "<br>";
281
282             strHTML += "<br><b>Transaction:</b><br>";
283             strHTML += HtmlEscape(wtx.ToString(), true);
284
285             strHTML += "<br><b>Inputs:</b><br>";
286             CRITICAL_BLOCK(cs_mapWallet)
287             {
288                 BOOST_FOREACH(const CTxIn& txin, wtx.vin)
289                 {
290                     COutPoint prevout = txin.prevout;
291                     map<uint256, CWalletTx>::iterator mi = mapWallet.find(prevout.hash);
292                     if (mi != mapWallet.end())
293                     {
294                         const CWalletTx& prev = (*mi).second;
295                         if (prevout.n < prev.vout.size())
296                         {
297                             strHTML += HtmlEscape(prev.ToString(), true);
298                             strHTML += " &nbsp;&nbsp; " + FormatTxStatus(prev) + ", ";
299                             strHTML = strHTML + "IsMine=" + (prev.vout[prevout.n].IsMine() ? "true" : "false") + "<br>";
300                         }
301                     }
302                 }
303             }
304         }
305
306
307
308         strHTML += "</font></html>";
309     }
310     return strHTML;
311 }