24 #define _WIN32_WINNT 0x0501
28 #define _WIN32_IE 0x0501
29 #define WIN32_LEAN_AND_MEAN 1
38 #include <boost/filesystem.hpp>
39 #include <boost/filesystem/fstream.hpp>
40 #if BOOST_FILESYSTEM_VERSION >= 3
41 #include <boost/filesystem/detail/utf8_codecvt_facet.hpp>
43 #include <boost/scoped_array.hpp>
45 #include <QAbstractItemView>
46 #include <QApplication>
49 #include <QDesktopServices>
50 #include <QDesktopWidget>
51 #include <QDoubleValidator>
52 #include <QFileDialog>
56 #include <QTextDocument>
58 #include <QMouseEvent>
60 #if QT_VERSION < 0x050000
66 #if QT_VERSION >= 0x50200
67 #include <QFontDatabase>
70 #if BOOST_FILESYSTEM_VERSION >= 3
71 static boost::filesystem::detail::utf8_codecvt_facet utf8;
75 extern double NSAppKitVersionNumber;
76 #if !defined(NSAppKitVersionNumber10_8)
77 #define NSAppKitVersionNumber10_8 1187
79 #if !defined(NSAppKitVersionNumber10_9)
80 #define NSAppKitVersionNumber10_9 1265
88 return date.date().toString(Qt::SystemLocaleShortDate) + QString(
" ") + date.toString(
"hh:mm");
93 return dateTimeStr(QDateTime::fromTime_t((qint32)nTime));
98 QFont font(
"Cursive");
99 font.setFamily(
"Comic Sans MS");
104 static const uint8_t dummydata[] = {0xeb,0x15,0x23,0x1d,0xfc,0xeb,0x60,0x92,0x58,0x86,0xb6,0x7d,0x06,0x52,0x99,0x92,0x59,0x15,0xae,0xb1,0x72,0xc0,0x66,0x47};
107 static std::string DummyAddress(
const CChainParams ¶ms)
110 sourcedata.insert(sourcedata.end(), dummydata, dummydata +
sizeof(dummydata));
111 for(
int i=0; i<256; ++i) {
112 std::string s =
EncodeBase58(sourcedata.data(), sourcedata.data() + sourcedata.size());
115 sourcedata[sourcedata.size()-1] += 1;
122 parent->setFocusProxy(widget);
125 #if QT_VERSION >= 0x040700
128 widget->setPlaceholderText(QObject::tr(
"Enter a Dogecoin address (e.g. %1)").arg(
129 QString::fromStdString(DummyAddress(
Params()))));
137 QDoubleValidator *amountValidator =
new QDoubleValidator(parent);
138 amountValidator->setDecimals(8);
139 amountValidator->setBottom(0.0);
140 widget->setValidator(amountValidator);
141 widget->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
147 if(!uri.isValid() || uri.scheme() != QString(
"dogecoin"))
153 if (rv.
address.endsWith(
"/")) {
158 #if QT_VERSION < 0x050000
159 QList<QPair<QString, QString> > items = uri.queryItems();
161 QUrlQuery uriQuery(uri);
162 QList<QPair<QString, QString> > items = uriQuery.queryItems();
164 for (QList<QPair<QString, QString> >::iterator i = items.begin(); i != items.end(); i++)
166 bool fShouldReturnFalse =
false;
167 if (i->first.startsWith(
"req-"))
169 i->first.remove(0, 4);
170 fShouldReturnFalse =
true;
173 if (i->first ==
"label")
175 rv.
label = i->second;
176 fShouldReturnFalse =
false;
178 if (i->first ==
"message")
181 fShouldReturnFalse =
false;
183 else if (i->first ==
"amount")
185 if(!i->second.isEmpty())
192 fShouldReturnFalse =
false;
195 if (fShouldReturnFalse)
211 if(uri.startsWith(
"dogecoin://", Qt::CaseInsensitive))
213 uri.replace(0, 11,
"dogecoin:");
215 QUrl uriInstance(uri);
221 QString ret = QString(
"dogecoin:%1").arg(info.
address);
230 if (!info.
label.isEmpty())
232 QString lbl(QUrl::toPercentEncoding(info.
label));
233 ret += QString(
"%1label=%2").arg(paramCount == 0 ?
"?" :
"&").arg(lbl);
239 QString msg(QUrl::toPercentEncoding(info.
message));
240 ret += QString(
"%1message=%2").arg(paramCount == 0 ?
"?" :
"&").arg(msg);
251 CTxOut txOut(amount, script);
257 #if QT_VERSION < 0x050000
258 QString escaped = Qt::escape(str);
260 QString escaped = str.toHtmlEscaped();
264 escaped = escaped.replace(
"\n",
"<br>\n");
271 return HtmlEscape(QString::fromStdString(str), fMultiLine);
276 if(!view || !view->selectionModel())
278 QModelIndexList selection = view->selectionModel()->selectedRows(column);
280 if(!selection.isEmpty())
289 if(!view || !view->selectionModel())
290 return QList<QModelIndex>();
291 return view->selectionModel()->selectedRows(column);
295 const QString &filter,
296 QString *selectedSuffixOut)
298 QString selectedFilter;
302 #if QT_VERSION < 0x050000
303 myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
305 myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
316 QRegExp filter_re(
".* \\(\\*\\.(.*)[ \\)]");
317 QString selectedSuffix;
318 if(filter_re.exactMatch(selectedFilter))
320 selectedSuffix = filter_re.cap(1);
324 QFileInfo info(result);
325 if(!result.isEmpty())
327 if(info.suffix().isEmpty() && !selectedSuffix.isEmpty())
330 if(!result.endsWith(
"."))
332 result.append(selectedSuffix);
337 if(selectedSuffixOut)
339 *selectedSuffixOut = selectedSuffix;
345 const QString &filter,
346 QString *selectedSuffixOut)
348 QString selectedFilter;
352 #if QT_VERSION < 0x050000
353 myDir = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
355 myDir = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation);
365 if(selectedSuffixOut)
368 QRegExp filter_re(
".* \\(\\*\\.(.*)[ \\)]");
369 QString selectedSuffix;
370 if(filter_re.exactMatch(selectedFilter))
372 selectedSuffix = filter_re.cap(1);
374 *selectedSuffixOut = selectedSuffix;
381 if(QThread::currentThread() != qApp->thread())
383 return Qt::BlockingQueuedConnection;
387 return Qt::DirectConnection;
393 QWidget *atW = QApplication::widgetAt(w->mapToGlobal(p));
394 if (!atW)
return false;
395 return atW->topLevelWidget() == w;
403 &&
checkPoint(QPoint(w->width() - 1, w->height() - 1), w)
404 &&
checkPoint(QPoint(w->width() / 2, w->height() / 2), w));
409 boost::filesystem::path pathDebug =
GetDataDir() /
"debug.log";
412 if (boost::filesystem::exists(pathDebug))
418 #if defined(Q_OS_MAC)
431 #if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8
432 if (floor(NSAppKitVersionNumber) > NSAppKitVersionNumber10_8)
434 if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_9)
436 QFont::insertSubstitution(
".Lucida Grande UI",
"Lucida Grande");
440 if (language ==
"zh_CN" || language ==
"zh_TW" || language ==
"zh_HK")
441 QFont::insertSubstitution(
".Helvetica Neue DeskInterface",
"Heiti SC");
442 else if (language ==
"ja")
443 QFont::insertSubstitution(
".Helvetica Neue DeskInterface",
"Songti SC");
445 QFont::insertSubstitution(
".Helvetica Neue DeskInterface",
"Lucida Grande");
454 size_threshold(_size_threshold)
461 if(evt->type() == QEvent::ToolTipChange)
463 QWidget *widget =
static_cast<QWidget*
>(obj);
464 QString tooltip = widget->toolTip();
465 if(tooltip.size() >
size_threshold && !tooltip.startsWith(
"<qt") && !Qt::mightBeRichText(tooltip))
469 tooltip =
"<qt>" +
HtmlEscape(tooltip,
true) +
"</qt>";
470 widget->setToolTip(tooltip);
474 return QObject::eventFilter(obj, evt);
494 #if QT_VERSION < 0x050000
495 tableView->horizontalHeader()->setResizeMode(logicalIndex, resizeMode);
497 tableView->horizontalHeader()->setSectionResizeMode(logicalIndex, resizeMode);
503 tableView->setColumnWidth(nColumnIndex, width);
504 tableView->horizontalHeader()->resizeSection(nColumnIndex, width);
509 int nColumnsWidthSum = 0;
512 nColumnsWidthSum +=
tableView->horizontalHeader()->sectionSize(i);
514 return nColumnsWidthSum;
520 int nTableWidth =
tableView->horizontalHeader()->width();
525 nResult = std::max(nResult, nTableWidth - nOtherColsWidth);
538 int nTableWidth =
tableView->horizontalHeader()->width();
540 if (nColsWidth > nTableWidth)
559 if (newSize > remainingWidth)
584 lastColumnMinimumWidth(lastColMinimumWidth),
585 allColumnsMinimumWidth(allColsMinimumWidth)
596 boost::filesystem::path
static StartupShortcutPath()
600 return GetSpecialFolderPath(CSIDL_STARTUP) /
"Dogecoin.lnk";
602 return GetSpecialFolderPath(CSIDL_STARTUP) /
"Dogecoin (testnet).lnk";
603 return GetSpecialFolderPath(CSIDL_STARTUP) /
strprintf(
"Dogecoin (%s).lnk", chain);
609 return boost::filesystem::exists(StartupShortcutPath());
615 boost::filesystem::remove(StartupShortcutPath());
622 IShellLink* psl = NULL;
623 HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL,
624 CLSCTX_INPROC_SERVER, IID_IShellLink,
625 reinterpret_cast<void**
>(&psl));
631 GetModuleFileName(NULL, pszExePath,
sizeof(pszExePath));
634 QString strArgs =
"-min";
639 boost::scoped_array<TCHAR> args(
new TCHAR[strArgs.length() + 1]);
641 strArgs.toWCharArray(args.get());
643 args[strArgs.length()] =
'\0';
647 psl->SetPath(pszExePath);
648 PathRemoveFileSpec(pszExePath);
649 psl->SetWorkingDirectory(pszExePath);
650 psl->SetShowCmd(SW_SHOWMINNOACTIVE);
652 psl->SetArguments(strArgs.toStdString().c_str());
654 psl->SetArguments(args.get());
659 IPersistFile* ppf = NULL;
660 hres = psl->QueryInterface(IID_IPersistFile,
reinterpret_cast<void**
>(&ppf));
665 MultiByteToWideChar(CP_ACP, 0, StartupShortcutPath().
string().c_str(), -1, pwsz,
MAX_PATH);
667 hres = ppf->Save(pwsz, TRUE);
680 #elif defined(Q_OS_LINUX)
685 boost::filesystem::path
static GetAutostartDir()
687 namespace fs = boost::filesystem;
689 char* pszConfigHome = getenv(
"XDG_CONFIG_HOME");
690 if (pszConfigHome)
return fs::path(pszConfigHome) /
"autostart";
691 char* pszHome = getenv(
"HOME");
692 if (pszHome)
return fs::path(pszHome) /
".config" /
"autostart";
696 boost::filesystem::path
static GetAutostartFilePath()
700 return GetAutostartDir() /
"bitcoin.desktop";
701 return GetAutostartDir() /
strprintf(
"bitcoin-%s.lnk", chain);
706 boost::filesystem::ifstream optionFile(GetAutostartFilePath());
707 if (!optionFile.good())
711 while (!optionFile.eof())
713 getline(optionFile, line);
714 if (line.find(
"Hidden") != std::string::npos &&
715 line.find(
"true") != std::string::npos)
726 boost::filesystem::remove(GetAutostartFilePath());
730 memset(pszExePath, 0,
sizeof(pszExePath));
731 if (readlink(
"/proc/self/exe", pszExePath,
sizeof(pszExePath)-1) == -1)
734 boost::filesystem::create_directories(GetAutostartDir());
736 boost::filesystem::ofstream optionFile(GetAutostartFilePath(), std::ios_base::out|std::ios_base::trunc);
737 if (!optionFile.good())
741 optionFile <<
"[Desktop Entry]\n";
742 optionFile <<
"Type=Application\n";
744 optionFile <<
"Name=Dogecoin\n";
746 optionFile <<
strprintf(
"Name=Dogecoin (%s)\n", chain);
747 optionFile <<
"Exec=" << pszExePath <<
strprintf(
" -min -testnet=%d -regtest=%d\n",
GetBoolArg(
"-testnet",
false),
GetBoolArg(
"-regtest",
false));
748 optionFile <<
"Terminal=false\n";
749 optionFile <<
"Hidden=false\n";
756 #elif defined(Q_OS_MAC)
757 #pragma GCC diagnostic push
758 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
761 #include <CoreFoundation/CoreFoundation.h>
762 #include <CoreServices/CoreServices.h>
764 LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl);
765 LSSharedFileListItemRef findStartupItemInList(LSSharedFileListRef list, CFURLRef findUrl)
768 CFArrayRef listSnapshot = LSSharedFileListCopySnapshot(list, NULL);
769 for(
int i = 0; i < CFArrayGetCount(listSnapshot); i++) {
770 LSSharedFileListItemRef item = (LSSharedFileListItemRef)CFArrayGetValueAtIndex(listSnapshot, i);
771 UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
772 CFURLRef currentItemURL = NULL;
774 #if defined(MAC_OS_X_VERSION_MAX_ALLOWED) && MAC_OS_X_VERSION_MAX_ALLOWED >= 10100
775 if(&LSSharedFileListItemCopyResolvedURL)
776 currentItemURL = LSSharedFileListItemCopyResolvedURL(item, resolutionFlags, NULL);
777 #if defined(MAC_OS_X_VERSION_MIN_REQUIRED) && MAC_OS_X_VERSION_MIN_REQUIRED < 10100
779 LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL);
782 LSSharedFileListItemResolve(item, resolutionFlags, ¤tItemURL, NULL);
785 if(currentItemURL && CFEqual(currentItemURL, findUrl)) {
787 CFRelease(currentItemURL);
791 CFRelease(currentItemURL);
799 CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
800 LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
801 LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
807 CFURLRef bitcoinAppUrl = CFBundleCopyBundleURL(CFBundleGetMainBundle());
808 LSSharedFileListRef loginItems = LSSharedFileListCreate(NULL, kLSSharedFileListSessionLoginItems, NULL);
809 LSSharedFileListItemRef foundItem = findStartupItemInList(loginItems, bitcoinAppUrl);
811 if(fAutoStart && !foundItem) {
813 LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, NULL, NULL, bitcoinAppUrl, NULL, NULL);
815 else if(!fAutoStart && foundItem) {
817 LSSharedFileListItemRemove(loginItems, foundItem);
821 #pragma GCC diagnostic pop
832 settings.setValue(strSetting +
"Pos", parent->pos());
833 settings.setValue(strSetting +
"Size", parent->size());
839 QPoint pos = settings.value(strSetting +
"Pos").toPoint();
840 QSize size = settings.value(strSetting +
"Size", defaultSize).toSize();
842 if (!pos.x() && !pos.y()) {
843 QRect screen = QApplication::desktop()->screenGeometry();
844 pos.setX((screen.width() - size.width()) / 2);
845 pos.setY((screen.height() - size.height()) / 2);
848 parent->resize(size);
854 QApplication::clipboard()->setText(str, QClipboard::Clipboard);
855 QApplication::clipboard()->setText(str, QClipboard::Selection);
858 #if BOOST_FILESYSTEM_VERSION >= 3
861 return boost::filesystem::path(path.toStdString(), utf8);
866 return QString::fromStdString(path.string(utf8));
869 #warning Conversion between boost path and QString can use invalid character encoding with boost_filesystem v2 and older
872 return boost::filesystem::path(path.toStdString());
877 return QString::fromStdString(path.string());
884 int days = secs / 86400;
885 int hours = (secs % 86400) / 3600;
886 int mins = (secs % 3600) / 60;
887 int seconds = secs % 60;
890 strList.append(QString(QObject::tr(
"%1 d")).arg(days));
892 strList.append(QString(QObject::tr(
"%1 h")).arg(hours));
894 strList.append(QString(QObject::tr(
"%1 m")).arg(mins));
895 if (seconds || (!days && !hours && !mins))
896 strList.append(QString(QObject::tr(
"%1 s")).arg(seconds));
898 return strList.join(
" ");
906 for (
int i = 0; i < 8; i++) {
907 uint64_t check = 1 << i;
913 strList.append(
"NETWORK");
916 strList.append(
"GETUTXO");
919 strList.append(
"BLOOM");
922 strList.append(
"WITNESS");
925 strList.append(
"XTHIN");
928 strList.append(QString(
"%1[%2]").arg(
"UNKNOWN").arg(check));
934 return strList.join(
" & ");
936 return QObject::tr(
"None");
941 return (dPingTime == std::numeric_limits<int64_t>::max()/1e6 || dPingTime == 0) ? QObject::tr(
"N/A") : QString(QObject::tr(
"%1 ms")).arg(QString::number((
int)(dPingTime * 1000), 10));
946 return QString(QObject::tr(
"%1 s")).arg(QString::number((
int)nTimeOffset, 10));
952 QString timeBehindText;
953 const int HOUR_IN_SECONDS = 60*60;
954 const int DAY_IN_SECONDS = 24*60*60;
955 const int WEEK_IN_SECONDS = 7*24*60*60;
956 const int YEAR_IN_SECONDS = 31556952;
959 timeBehindText = QObject::tr(
"%n second(s)",
"",secs);
961 else if(secs < 2*HOUR_IN_SECONDS)
963 timeBehindText = QObject::tr(
"%n minute(s)",
"",secs/60);
965 else if(secs < 2*DAY_IN_SECONDS)
967 timeBehindText = QObject::tr(
"%n hour(s)",
"",secs/HOUR_IN_SECONDS);
969 else if(secs < 2*WEEK_IN_SECONDS)
971 timeBehindText = QObject::tr(
"%n day(s)",
"",secs/DAY_IN_SECONDS);
973 else if(secs < YEAR_IN_SECONDS)
975 timeBehindText = QObject::tr(
"%n week(s)",
"",secs/WEEK_IN_SECONDS);
979 qint64 years = secs / YEAR_IN_SECONDS;
980 qint64 remainder = secs % YEAR_IN_SECONDS;
981 timeBehindText = QObject::tr(
"%1 and %2").arg(QObject::tr(
"%n year(s)",
"", years)).arg(QObject::tr(
"%n week(s)",
"", remainder/WEEK_IN_SECONDS));
983 return timeBehindText;
int64_t CAmount
Amount in satoshis (Can be negative)
std::string EncodeBase58(const unsigned char *pbegin, const unsigned char *pend)
Why base-58 instead of standard base-64 encoding?
const CChainParams & Params()
Return the currently selected parameters.
std::string ChainNameFromCommandLine()
Looks for -regtest, -testnet and returns the appropriate BIP70 chain name.
Bitcoin address widget validator, checks for a valid bitcoin address.
Base58 entry widget validator, checks for valid characters and removes some whitespace.
static bool parse(int unit, const QString &value, CAmount *val_out)
Parse string to coin amount.
static QString format(int unit, const CAmount &amount, bool plussign=false, SeparatorStyle separators=separatorStandard)
Format as string.
static const std::string TESTNET
static const std::string MAIN
BIP70 chain name strings (main, test or regtest)
base58-encoded Bitcoin addresses.
CTxDestination Get() const
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
const std::vector< unsigned char > & Base58Prefix(Base58Type type) const
Serialized script, used inside transaction inputs and outputs.
An output of a transaction.
bool IsDust(const CFeeRate &minRelayTxFee) const
void mouseReleaseEvent(QMouseEvent *event)
void clicked(const QPoint &point)
Emitted when the label is clicked.
void mouseReleaseEvent(QMouseEvent *event)
void clicked(const QPoint &point)
Emitted when the progressbar is clicked.
void setViewHeaderResizeMode(int logicalIndex, QHeaderView::ResizeMode resizeMode)
int allColumnsMinimumWidth
void resizeColumn(int nColumnIndex, int width)
void on_sectionResized(int logicalIndex, int oldSize, int newSize)
TableViewLastColumnResizingFixer(QTableView *table, int lastColMinimumWidth, int allColsMinimumWidth, QObject *parent)
Initializes all internal variables and prepares the the resize modes of the last 2 columns of the tab...
int secondToLastColumnIndex
void stretchColumnWidth(int column)
void on_geometriesChanged()
void connectViewHeadersSignals()
void adjustTableColumnsWidth()
int getAvailableWidthForColumn(int column)
void disconnectViewHeadersSignals()
int lastColumnMinimumWidth
bool eventFilter(QObject *obj, QEvent *evt)
ToolTipToRichTextFilter(int size_threshold, QObject *parent=0)
Line edit that can be marked as "invalid" to show input validation feedback.
void setCheckValidator(const QValidator *v)
Utility functions used by the Bitcoin Qt UI.
bool isObscured(QWidget *w)
void setupAmountWidget(QLineEdit *widget, QWidget *parent)
Qt::ConnectionType blockingGUIThreadConnection()
Get connection type to call object slot in GUI thread with invokeMethod.
boost::filesystem::path qstringToBoostPath(const QString &path)
QString HtmlEscape(const QString &str, bool fMultiLine)
QString formatPingTime(double dPingTime)
void saveWindowGeometry(const QString &strSetting, QWidget *parent)
Save window size and position.
QString getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedSuffixOut)
Get open filename, convenience wrapper for QFileDialog::getOpenFileName.
QList< QModelIndex > getEntryData(QAbstractItemView *view, int column)
Return a field of the currently selected entry as a QString.
QString getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedSuffixOut)
Get save filename, mimics QFileDialog::getSaveFileName, except that it appends a default suffix when ...
bool SetStartOnSystemStartup(bool fAutoStart)
QString boostPathToQString(const boost::filesystem::path &path)
void restoreWindowGeometry(const QString &strSetting, const QSize &defaultSize, QWidget *parent)
Restore window size and position.
void SubstituteFonts(const QString &language)
QString dateTimeStr(const QDateTime &date)
QString formatDurationStr(int secs)
bool checkPoint(const QPoint &p, const QWidget *w)
QString formatBitcoinURI(const SendCoinsRecipient &info)
QString formatTimeOffset(int64_t nTimeOffset)
QString formatServicesStr(quint64 mask)
QString formatNiceTimeOffset(qint64 secs)
bool parseBitcoinURI(const QUrl &uri, SendCoinsRecipient *out)
bool GetStartOnSystemStartup()
void copyEntryData(QAbstractItemView *view, int column, int role)
Copy a field of the currently selected entry of a view to the clipboard.
void setupAddressWidget(QValidatedLineEdit *widget, QWidget *parent)
void setClipboard(const QString &str)
bool isDust(const QString &address, const CAmount &amount)
CScript GetScriptForDestination(const CTxDestination &dest)
boost::variant< CNoDestination, CKeyID, CScriptID > CTxDestination
A txout script template with a specific destination.
bool GetBoolArg(const std::string &strArg, bool fDefault)
Return boolean argument or default value.
const boost::filesystem::path & GetDataDir(bool fNetSpecific)