diff options
Diffstat (limited to 'VMProtect')
188 files changed, 19481 insertions, 0 deletions
diff --git a/VMProtect/about_dialog.cc b/VMProtect/about_dialog.cc new file mode 100644 index 0000000..f1458c4 --- /dev/null +++ b/VMProtect/about_dialog.cc @@ -0,0 +1,177 @@ +#include "../core/objects.h" +#include "../core/files.h" +#include "../core/core.h" +#include "../core/lang.h" +#include "widgets.h" +#include "about_dialog.h" +#include "help_browser.h" +#include "moc/moc_about_dialog.cc" + +/** + * AboutDialog + */ + +AboutDialog::AboutDialog(QWidget *parent) + : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint | Qt::MSWindowsFixedSizeDialogHint) +{ + setWindowTitle(QString::fromUtf8(language[lsAbout].c_str())); + + QAction *helpAction = new QAction(this); + helpAction->setShortcut(HelpContentsKeySequence()); + connect(helpAction, SIGNAL(triggered()), this, SLOT(help())); + + addAction(helpAction); + + QFrame *top = new QFrame(this); + top->setObjectName("bootTop"); + + QLabel *logo = new QLabel(this); + logo->setPixmap(QPixmap(":/images/logo.png")); + + QLabel *version = new QLabel(QString::fromLatin1(Core::edition()) + " v " + QString::fromLatin1(Core::version()), this); + version->setObjectName("version"); + + QLabel *build = new QLabel("build " + QString::fromLatin1(Core::build()), this); + build->setObjectName("build"); + + QGridLayout *grid_layout = new QGridLayout(); + grid_layout->setContentsMargins(30, 30, 30, 20); + grid_layout->setSpacing(0); + grid_layout->setColumnStretch(1, 1); + grid_layout->addWidget(logo, 0, 0, 3, 1); + grid_layout->addWidget(version, 0, 1, Qt::AlignCenter); + grid_layout->addItem(new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding), 1, 1); + grid_layout->addWidget(build, 2, 1, Qt::AlignRight); + top->setLayout(grid_layout); + + QFrame *line1 = new QFrame(this); + line1->setObjectName("bootHSeparator"); + line1->setFixedHeight(1); + + QFrame *center = new QFrame(this); + center->setObjectName("boot"); + + QLabel *registered1 = new QLabel(this); + registered1->setWordWrap(true); + QLabel *registered2 = new QLabel(this); + registered2->setWordWrap(true); + + enum PurchaseMode { + pmLicense, + pmSubscriptionPersonal, + pmSubscriptionCompany + }; + + QPushButton *purchase = NULL; + PurchaseMode purchaseMode = pmLicense; +#ifdef DEMO + registered1->setText(QString::fromUtf8(language[lsDemoVersion].c_str())); + registered1->setObjectName("unregistered"); + + purchase = new PushButton(QString::fromUtf8(language[lsPurchaseLicense].c_str()), this); +#else + VMProtectSerialNumberData data; + data.nState = SERIAL_STATE_FLAG_INVALID; + if (VMProtectGetSerialNumberData(&data, sizeof(data)) && data.nState == 0) { + registered1->setText(QString("%1: <b>%2 [%3], %4</b>").arg(QString::fromUtf8(language[lsRegisteredTo].c_str())). + arg(QString::fromUtf16((ushort *)data.wUserName)). + arg(QString::fromUtf16((ushort *)data.wEMail)). + arg((data.bUserData[0] & 1) ? "Personal License" : "Company License")); + if (data.dtMaxBuild.wYear) { + QDate dt = QDate(data.dtMaxBuild.wYear, data.dtMaxBuild.bMonth, data.dtMaxBuild.bDay); + registered2->setText(QString("%1: <b>%2</b>").arg(QString::fromUtf8(language[lsFreeUpdatesPeriod].c_str())).arg(dt.toString(Qt::SystemLocaleShortDate))); + + if (QDate::currentDate() > dt) { + purchase = new PushButton(QString::fromUtf8(language[lsPurchaseSubscription].c_str()), this); + if (data.nUserDataLength) + purchaseMode = (data.bUserData[0] & 1) ? pmSubscriptionPersonal : pmSubscriptionCompany; + } + } + } else { + if (data.nState & SERIAL_STATE_FLAG_BLACKLISTED) { + registered1->setText(QString::fromLatin1(VMProtectDecryptStringA("Your key file is blocked!"))); + // don't show "buy now" button + } else if (data.nState & SERIAL_STATE_FLAG_MAX_BUILD_EXPIRED) { + registered1->setText(QString::fromLatin1(VMProtectDecryptStringA("Your key file will not work with this version of VMProtect!\nYou should use older version or buy one more year of updates and technical support."))); + purchase = new PushButton(QString::fromUtf8(language[lsPurchaseSubscription].c_str()), this); + if (data.nUserDataLength) + purchaseMode = (data.bUserData[0] & 1) ? pmSubscriptionPersonal : pmSubscriptionCompany; + } else { + registered1->setText(QString::fromUtf8(language[lsUnregisteredVersion].c_str())); + purchase = new PushButton(QString::fromUtf8(language[lsPurchaseLicense].c_str()), this); + } + registered1->setObjectName("unregistered"); + } +#endif + + QBoxLayout *layout = new QVBoxLayout(); + layout->setContentsMargins(10, 10, 10, 10); + layout->setSpacing(5); + layout->addWidget(registered1); + layout->addWidget(registered2); + layout->addStretch(1); + if (purchase) { + switch (purchaseMode) { + case pmSubscriptionPersonal: + connect(purchase, SIGNAL(clicked()), this, SLOT(purchaseSubscriptionPersonal())); + break; + case pmSubscriptionCompany: + connect(purchase, SIGNAL(clicked()), this, SLOT(purchaseSubscriptionCompany())); + break; + default: + connect(purchase, SIGNAL(clicked()), this, SLOT(purchaseLicense())); + break; + } + layout->addWidget(purchase, 0, Qt::AlignCenter); + } + center->setLayout(layout); + + QFrame *line2 = new QFrame(this); + line2->setObjectName("bootHSeparator"); + line2->setFixedHeight(1); + + QLabel *copyright = new QLabel(QString::fromLatin1(Core::copyright()), this); + copyright->setObjectName("copyright"); + + QFrame *bottom = new QFrame(this); + bottom->setObjectName("bootTop"); + layout = new QHBoxLayout(); + layout->setContentsMargins(10, 10, 10, 10); + layout->setSpacing(0); + layout->addWidget(copyright, 0, Qt::AlignCenter); + bottom->setLayout(layout); + + layout = new QVBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(top); + layout->addWidget(line1); + layout->addWidget(center, 1); + layout->addWidget(line2); + layout->addWidget(bottom); + setLayout(layout); + + setMinimumSize(500, 300); + setMaximumSize(500, 300); + //auto size: layout->setSizeConstraint(QLayout::SetFixedSize); +} + +void AboutDialog::purchaseLicense() +{ + QDesktopServices::openUrl(QUrl(VMProtectDecryptStringA("http://www.vmpsoft.com/purchase/buy-online/"))); +} + +void AboutDialog::purchaseSubscriptionPersonal() +{ + QDesktopServices::openUrl(QUrl("https://store.payproglobal.com/checkout?products[1][id]=35518")); +} + +void AboutDialog::purchaseSubscriptionCompany() +{ + QDesktopServices::openUrl(QUrl("https://store.payproglobal.com/checkout?products[1][id]=35531")); +} + +void AboutDialog::help() +{ + HelpBrowser::showTopic("contacts"); +}
\ No newline at end of file diff --git a/VMProtect/about_dialog.h b/VMProtect/about_dialog.h new file mode 100644 index 0000000..871d69a --- /dev/null +++ b/VMProtect/about_dialog.h @@ -0,0 +1,16 @@ +#ifndef ABOUT_DIALOG_H +#define ABOUT_DIALOG_H + +class AboutDialog : public QDialog +{ + Q_OBJECT +public: + AboutDialog(QWidget *parent = NULL); +private slots: + void purchaseLicense(); + void purchaseSubscriptionPersonal(); + void purchaseSubscriptionCompany(); + void help(); +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/app_icon.mm b/VMProtect/app_icon.mm new file mode 100644 index 0000000..03c193d --- /dev/null +++ b/VMProtect/app_icon.mm @@ -0,0 +1,137 @@ +#include <QtGui/QIcon> +#include <AppKit/AppKit.h> + +/* + Helper class that automates refernce counting for CFtypes. + After constructing the QCFType object, it can be copied like a + value-based type. + + Note that you must own the object you are wrapping. + This is typically the case if you get the object from a Core + Foundation function with the word "Create" or "Copy" in it. If + you got the object from a "Get" function, either retain it or use + constructFromGet(). One exception to this rule is the + HIThemeGet*Shape functions, which in reality are "Copy" functions. +*/ +template <typename T> +class QCFType +{ +public: + inline QCFType(const T &t = 0) : type(t) {} + inline QCFType(const QCFType &helper) : type(helper.type) { if (type) CFRetain(type); } + inline ~QCFType() { if (type) CFRelease(type); } + inline operator T() { return type; } + inline QCFType operator =(const QCFType &helper) + { + if (helper.type) + CFRetain(helper.type); + CFTypeRef type2 = type; + type = helper.type; + if (type2) + CFRelease(type2); + return *this; + } + inline T *operator&() { return &type; } + template <typename X> X as() const { return reinterpret_cast<X>(type); } + static QCFType constructFromGet(const T &t) + { + CFRetain(t); + return QCFType<T>(t); + } +protected: + T type; +}; + +CGColorSpaceRef qt_mac_genericColorSpace() +{ + CGDirectDisplayID displayID = CGMainDisplayID(); + CGColorSpaceRef colorSpace = CGDisplayCopyColorSpace(displayID); + if (colorSpace == 0) + colorSpace = CGColorSpaceCreateDeviceRGB(); + + return colorSpace; +} + +static void qt_mac_deleteImage(void *image, const void *, size_t) +{ + delete static_cast<QImage *>(image); +} + +// Creates a CGDataProvider with the data from the given image. +// The data provider retains a copy of the image. +CGDataProviderRef qt_mac_CGDataProvider(const QImage &image) +{ + return CGDataProviderCreateWithData(new QImage(image), image.bits(), + image.byteCount(), qt_mac_deleteImage); +} + +CGImageRef qt_mac_toCGImage(const QImage &inImage) +{ + if (inImage.isNull()) + return 0; + + QImage image = inImage; + + uint cgflags = kCGImageAlphaNone; + switch (image.format()) { + case QImage::Format_ARGB32: + cgflags = kCGImageAlphaFirst | kCGBitmapByteOrder32Host; + break; + case QImage::Format_RGB32: + cgflags = kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Host; + break; + case QImage::Format_RGB888: + cgflags = kCGImageAlphaNone | kCGBitmapByteOrder32Big; + break; + case QImage::Format_RGBA8888_Premultiplied: + cgflags = kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big; + break; + case QImage::Format_RGBA8888: + cgflags = kCGImageAlphaLast | kCGBitmapByteOrder32Big; + break; + case QImage::Format_RGBX8888: + cgflags = kCGImageAlphaNoneSkipLast | kCGBitmapByteOrder32Big; + break; + default: + // Everything not recognized explicitly is converted to ARGB32_Premultiplied. + image = inImage.convertToFormat(QImage::Format_ARGB32_Premultiplied); + // no break; + case QImage::Format_ARGB32_Premultiplied: + cgflags = kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Host; + break; + } + + QCFType<CGDataProviderRef> dataProvider = qt_mac_CGDataProvider(image); + return CGImageCreate(image.width(), image.height(), 8, 32, + image.bytesPerLine(), + qt_mac_genericColorSpace(), + cgflags, dataProvider, 0, false, kCGRenderingIntentDefault); +} + +NSImage *qt_mac_create_nsimage(const QIcon &icon) +{ + if (icon.isNull()) + return nil; + + NSImage *nsImage = [[NSImage alloc] init]; + foreach (QSize size, icon.availableSizes()) { + QPixmap pm = icon.pixmap(size); + QImage image = pm.toImage(); + CGImageRef cgImage = qt_mac_toCGImage(image); + NSBitmapImageRep *imageRep = [[NSBitmapImageRep alloc] initWithCGImage:cgImage]; + [nsImage addRepresentation:imageRep]; + [imageRep release]; + CGImageRelease(cgImage); + } + return nsImage; +} + +void qt_mac_set_app_icon(const QIcon &icon) +{ + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSImage *image = qt_mac_create_nsimage(icon); + [NSApp setApplicationIconImage:image]; + [image release]; + [pool release]; +} + diff --git a/VMProtect/application.h b/VMProtect/application.h new file mode 100644 index 0000000..466d289 --- /dev/null +++ b/VMProtect/application.h @@ -0,0 +1,30 @@ +#ifndef APPLICATION_H +#define APPLICATION_H + +class Application : public QApplication +{ + Q_OBJECT +public: + Application(int &argc, char **argv); + bool isHelpMode() { return help_filename_.length() > 0; } + const QString &helpFileName() const { return help_filename_; } + static double stylesheetScaleFactor() { return stylesheetScaleFactor_; } + static double devicePixelRatio() { return devicePixelRatio_; } + + ~Application(); + +signals: + void fileOpenEvent(const QString &); + +protected: + /*virtual*/ bool event(QEvent *event); + + void installStylesheet(); + QByteArray transformStylesheet(const QByteArray &qssData); + void initScalingConstants(); + static double stylesheetScaleFactor_, devicePixelRatio_; + + QString help_filename_; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/application.qrc b/VMProtect/application.qrc new file mode 100644 index 0000000..b60e171 --- /dev/null +++ b/VMProtect/application.qrc @@ -0,0 +1,132 @@ +<!DOCTYPE RCC><RCC version="1.0"> +<qresource> + <file>images/star.png</file> + <file>images/star_gray.png</file> + <file>images/tool.png</file> + <file>images/key.png</file> + <file>images/key_gray.png</file> + <file>images/bullet_key.png</file> + <file>images/bullet_import.png</file> + <file>images/box.png</file> + <file>images/folder.png</file> + <file>images/folder_close.png</file> + <file>images/item.png</file> + <file>images/item_m.png</file> + <file>images/item_v.png</file> + <file>images/item_u.png</file> + <file>images/item_file.png</file> + <file>images/item_key.png</file> + <file>images/item_import.png</file> + <file>images/item_export.png</file> + <file>images/item_resource.png</file> + <file>images/item_load_command.png</file> + <file>images/item_code.png</file> + <file>images/item_property.png</file> + <file>images/gear.png</file> + <file>images/import.png</file> + <file>images/export.png</file> + <file>images/code.png</file> + <file>images/dump.png</file> + <file>images/lightning.png</file> + <file>images/database.png</file> + <file>images/cancel.png</file> + <file>images/cancel_hover.png</file> + <file>images/cancel_gray.png</file> + <file>images/script.png</file> + <file>images/processor.png</file> + <file>images/cut.png</file> + <file>images/cut_hover.png</file> + <file>images/cut_disabled.png</file> + <file>images/copy.png</file> + <file>images/copy_hover.png</file> + <file>images/copy_disabled.png</file> + <file>images/paste.png</file> + <file>images/paste_hover.png</file> + <file>images/paste_disabled.png</file> + <file>images/add.png</file> + <file>images/add_hover.png</file> + <file>images/add_disabled.png</file> + <file>images/add_gray.png</file> + <file>images/delete.png</file> + <file>images/open.png</file> + <file>images/open_hover.png</file> + <file>images/open_disabled.png</file> + <file>images/disk.png</file> + <file>images/disk_hover.png</file> + <file>images/disk_disabled.png</file> + <file>images/information.png</file> + <file>images/warning.png</file> + <file>images/error.png</file> + <file>images/bullet_warning.png</file> + <file>images/compile.png</file> + <file>images/compile_hover.png</file> + <file>images/compile_disabled.png</file> + <file>images/execute.png</file> + <file>images/execute_hover.png</file> + <file>images/execute_disabled.png</file> + <file>images/link.png</file> + <file>images/disabled.png</file> + <file>images/reference.png</file> + <file>images/bullet_delete.png</file> + <file>images/boot_open.png</file> + <file>images/boot_help.png</file> + <file>images/boot_examples.png</file> + <file>images/branch_open.png</file> + <file>images/branch_closed.png</file> + <file>images/scroll_up.png</file> + <file>images/scroll_down.png</file> + <file>images/scroll_left.png</file> + <file>images/scroll_right.png</file> + <file>images/scroll_up_hover.png</file> + <file>images/scroll_down_hover.png</file> + <file>images/scroll_left_hover.png</file> + <file>images/scroll_right_hover.png</file> + <file>images/project.png</file> + <file>images/project_checked.png</file> + <file>images/project_hover.png</file> + <file>images/functions.png</file> + <file>images/functions_checked.png</file> + <file>images/functions_hover.png</file> + <file>images/details.png</file> + <file>images/details_checked.png</file> + <file>images/details_hover.png</file> + <file>images/logo.png</file> + <file>images/up_arrow.png</file> + <file>images/up_arrow_disabled.png</file> + <file>images/down_arrow.png</file> + <file>images/down_arrow_disabled.png</file> + <file>images/file_open.png</file> + <file>images/file_open_hover.png</file> + <file>images/up_down.png</file> + <file>images/up_down_disabled.png</file> + <file>images/browse.png</file> + <file>images/search.png</file> + <file>images/search_gray.png</file> + <file>images/checkbox.png</file> + <file>images/checkbox_checked.png</file> + <file>images/radiobutton.png</file> + <file>images/radiobutton_checked.png</file> + <file>images/menu_arrow.png</file> + <file>images/menu_arrow_hover.png</file> + <file>images/menu_arrow_disabled.png</file> + <file>images/goto.png</file> + <file>images/goto_hover.png</file> + <file>images/goto_disabled.png</file> + <file>images/back.png</file> + <file>images/back_hover.png</file> + <file>images/back_disabled.png</file> + <file>images/forward.png</file> + <file>images/forward_hover.png</file> + <file>images/forward_disabled.png</file> + <file>images/check_off.png</file> + <file>images/check_on.png</file> + <file>images/check_off_hover.png</file> + <file>images/check_on_hover.png</file> + <file>images/next.png</file> + <file>images/previous.png</file> + <file>images/help_gray.png</file> + <file>images/help_icon.png</file> + <file>images/calc.png</file> + <file>styles.qss</file> +</qresource> +</RCC>
\ No newline at end of file diff --git a/VMProtect/export_key-pair.h b/VMProtect/export_key-pair.h new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/VMProtect/export_key-pair.h diff --git a/VMProtect/export_key_pair_dialog.cc b/VMProtect/export_key_pair_dialog.cc new file mode 100644 index 0000000..cadec84 --- /dev/null +++ b/VMProtect/export_key_pair_dialog.cc @@ -0,0 +1,168 @@ +#ifdef ULTIMATE +#include "../core/objects.h" +#include "../core/core.h" +#include "../core/lang.h" +#include "export_key_pair_dialog.h" +#include "widgets.h" +#include "moc/moc_export_key_pair_dialog.cc" +#include "help_browser.h" + +/** + * ExportKeyPairDialog + */ + +ExportKeyPairDialog::ExportKeyPairDialog(QWidget *parent, LicensingManager *manager) + : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint) +{ + bits_ = manager->bits(); + private_exp_ = manager->private_exp(); + public_exp_ = manager->public_exp(); + modulus_ = manager->modulus(); + uint64_t product_code = manager->product_code(); + product_code_.insert(product_code_.end(), reinterpret_cast<uint8_t *>(&product_code), reinterpret_cast<uint8_t *>(&product_code) + sizeof(product_code)); + + setWindowTitle(QString::fromUtf8(language[lsExportKeyPair].c_str())); + + QLabel *labelFormat = new QLabel(this); + labelFormat->setObjectName("header"); + labelFormat->setText(QString::fromUtf8(language[lsKeyPairExportTarget].c_str())); + + QComboBox *format = new QComboBox(this); + format->addItems(QStringList() << QString::fromUtf8(language[lsParametersForMSVC].c_str()) + << QString::fromUtf8(language[lsParametersForDelphi].c_str()) + << QString::fromUtf8(language[lsParametersForNET].c_str()) + << QString::fromUtf8(language[lsParametersForPHP].c_str())); + format->setCurrentIndex(0); + connect(format, SIGNAL(currentIndexChanged(int)), this, SLOT(formatChanged(int))); + + QLabel *labelResults = new QLabel(this); + labelResults->setObjectName("header"); + labelResults->setText(QString::fromUtf8(language[lsKeyPairExportResult].c_str())); + + edit_ = new QPlainTextEdit(this); + QFont font = edit_->font(); + font.setFamily(MONOSPACE_FONT_FAMILY); + edit_->setFont(font); + + QToolButton *helpButton = new QToolButton(this); + helpButton->setShortcut(HelpContentsKeySequence()); + helpButton->setIconSize(QSize(20, 20)); + helpButton->setIcon(QIcon(":/images/help_gray.png")); + helpButton->setToolTip(QString::fromUtf8(language[lsHelp].c_str())); + connect(helpButton, SIGNAL(clicked(bool)), this, SLOT(helpClicked())); + + QPushButton *closeButton = new PushButton(QString::fromUtf8(language[lsClose].c_str())); + connect(closeButton, SIGNAL(clicked()), this, SLOT(reject())); + + QPushButton *copyButton = new PushButton(QString::fromUtf8(language[lsCopy].c_str())); + connect(copyButton, SIGNAL(clicked()), this, SLOT(copyClicked())); + + QHBoxLayout *buttonLayout = new QHBoxLayout(); + buttonLayout->addWidget(helpButton); + buttonLayout->addStretch(); +#ifdef __APPLE__ + buttonLayout->addWidget(closeButton); + buttonLayout->addWidget(copyButton); +#else + buttonLayout->addWidget(copyButton); + buttonLayout->addWidget(closeButton); +#endif + + QVBoxLayout *layout = new QVBoxLayout(); + layout->setContentsMargins(10, 10, 10, 10); + layout->setSpacing(10); + layout->addWidget(labelFormat); + layout->addWidget(format); + layout->addWidget(labelResults); + layout->addWidget(edit_); + layout->addLayout(buttonLayout); + setLayout(layout); + + resize(610, 300); + + formatChanged(format->currentIndex()); +} + +QString VectorToString(const std::vector<uint8_t> &value) +{ + QString res; + for (size_t i = 0; i < value.size(); i++) { + if (i > 0) + res.append(',').append((i & 0xf) ? ' ' : '\n'); + res.append(QString("%1").arg(value[i], 3, 10, QChar(' '))); + } + + return res; +} + +QString _VectorToBase64(const std::vector<uint8_t> &value) +{ + QByteArray res = QByteArray(reinterpret_cast<const char *>(&value[0]), (int)value.size()); + return res.toBase64(); +} + +QString StringToBase64(const QString &value) +{ + QByteArray res; + res.append(value); + return res.toBase64(); +} + +void ExportKeyPairDialog::formatChanged(int format) +{ + QStringList lines; + switch (format) { + case 0: + lines.append("VMProtectAlgorithms g_Algorithm = ALGORITHM_RSA;"); + lines.append(QString("size_t g_nBits = %1;").arg(bits_)); + lines.append(QString("byte g_vPrivate[%1] = {").arg(private_exp_.size())); + lines.append(VectorToString(private_exp_) + "};"); + lines.append(""); + lines.append(QString("byte g_vModulus[%1] = {").arg(modulus_.size())); + lines.append(VectorToString(modulus_) + "};"); + lines.append(""); + lines.append(QString("byte g_vProductCode[%1] = {%2};").arg(product_code_.size()).arg(VectorToString(product_code_))); + break; + case 1: + lines.append("g_Algorithm: Longword = ALGORITHM_RSA;"); + lines.append(QString("g_nBits: Longword = %1;").arg(bits_)); + lines.append(QString("g_vPrivate: array [0..%1] of Byte = (").arg(private_exp_.size() - 1)); + lines.append(VectorToString(private_exp_) + ");"); + lines.append(""); + lines.append(QString("g_vModulus: array [0..%1] of Byte = (").arg(modulus_.size() - 1)); + lines.append(VectorToString(modulus_) + ");"); + lines.append(""); + lines.append(QString("g_vProductCode: array [0..%1] of Byte = (%2);").arg(product_code_.size() - 1).arg(VectorToString(product_code_))); + break; + case 2: + { + QString str = StringToBase64(QString("<vmp-lm-product algorithm=\"RSA\" bits=\"%1\" exp=\"%2\" mod=\"%3\" product=\"%4\"/>").arg(bits_).arg(_VectorToBase64(private_exp_)).arg(_VectorToBase64(modulus_)).arg(_VectorToBase64(product_code_))); + while (!str.isEmpty()) { + lines.append(str.left(76)); + str.remove(0, 76); + } + } + break; + case 3: + lines.append("$exported_algorithm = \"RSA\";"); + lines.append(QString("$exported_bits = %1;").arg(bits_)); + lines.append(QString("$exported_private = \"%1\";").arg(_VectorToBase64(private_exp_))); + lines.append(QString("$exported_modulus = \"%1\";").arg(_VectorToBase64(modulus_))); + lines.append(QString("$exported_product_code = \"%1\";").arg(_VectorToBase64(product_code_))); + break; + } + edit_->setPlainText(lines.join("\n")); +} + +void ExportKeyPairDialog::copyClicked() +{ + QClipboard *clipboard = QApplication::clipboard(); + clipboard->setText(edit_->toPlainText()); +} + +void ExportKeyPairDialog::helpClicked() +{ + HelpBrowser::showTopic("project::licenses"); +} + +#endif diff --git a/VMProtect/export_key_pair_dialog.h b/VMProtect/export_key_pair_dialog.h new file mode 100644 index 0000000..564a692 --- /dev/null +++ b/VMProtect/export_key_pair_dialog.h @@ -0,0 +1,23 @@ +#ifndef EXPORT_KEY_PAIR_DIALOG_H +#define EXPORT_KEY_PAIR_DIALOG_H + +class ExportKeyPairDialog : public QDialog +{ + Q_OBJECT +public: + ExportKeyPairDialog(QWidget *parent, LicensingManager *manager); +private slots: + void formatChanged(int format); + void copyClicked(); + void helpClicked(); +private: + size_t bits_; + std::vector<uint8_t> public_exp_; + std::vector<uint8_t> private_exp_; + std::vector<uint8_t> modulus_; + std::vector<uint8_t> product_code_; + + QPlainTextEdit *edit_; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/folder_dialog.h b/VMProtect/folder_dialog.h new file mode 100644 index 0000000..202ee9b --- /dev/null +++ b/VMProtect/folder_dialog.h @@ -0,0 +1,19 @@ +#ifndef FOLDER_DIALOG_H +#define FOLDER_DIALOG_H + +#include <QtGui/QDialog> +#include <QtGui/QtGui> + +class FolderDialog : public QDialog +{ + Q_OBJECT + +public: + FolderDialog(QWidget *parent = NULL); + QString nameText() const { return nameEdit->text(); } + void setNameText(const QString &text) { nameEdit->setText(text); } +private: + QLineEdit *nameEdit; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/function_dialog.cc b/VMProtect/function_dialog.cc new file mode 100644 index 0000000..3e67212 --- /dev/null +++ b/VMProtect/function_dialog.cc @@ -0,0 +1,265 @@ +#include "../core/objects.h" +#include "../core/core.h" +#include "../core/lang.h" +#include "../core/files.h" +#include "../core/processors.h" + +#include "widgets.h" +#include "models.h" +#include "property_editor.h" +#include "function_dialog.h" +#include "message_dialog.h" +#include "help_browser.h" +#include "moc/moc_function_dialog.cc" +#include "application.h" + +/** + * FunctionDialog + */ + +FunctionDialog::FunctionDialog(IFile *file, IArchitecture *file_arch, ShowMode mode, QWidget *parent) + : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint), file_(file), mode_(mode), defaultArch_(NULL) +{ + setWindowTitle(QString::fromUtf8(language[mode_ == smAddFunction ? lsAddFunction : lsGoTo].c_str())); + + if (file_arch) { + functionListModel_.reset(new MapFunctionListModel(*file_arch, (mode_ == smAddFunction), this)); + defaultArch_ = file_arch; + } else { + functionBundleListModel_.reset(new MapFunctionBundleListModel(*file, (mode_ == smAddFunction), this)); + if (!file_->map_function_list()->show_arch_name()) { + for (size_t i = 0; i < file_->count(); i++) { + IArchitecture *arch = file_->item(i); + if (!arch->visible()) + continue; + + defaultArch_ = arch; + break; + } + } + } + + QLabel *addressLabel = new QLabel(QString::fromUtf8(language[lsAddress].c_str()), this); + addressEdit_ = new LineEdit(this); + tabBar_ = new TabWidget(this); + tabBar_->setIconSize(QSize(18, 18)); + + QFrame *panel; + QLayout *panelLayout; + + functionsTree_ = new TreeView(this); + functionsTree_->setObjectName("grid"); + functionsTree_->setIconSize(QSize(18, 18)); + functionsTree_->setRootIsDecorated(false); + functionsTree_->setUniformRowHeights(true); + if (functionBundleListModel_.get()) + functionsTree_->setModel(functionBundleListModel_.get()); + else + functionsTree_->setModel(functionListModel_.get()); + if (mode_ == smAddFunction) + functionsTree_->setSelectionMode(QTreeView::ExtendedSelection); + functionsTree_->setSelectionBehavior(QTreeView::SelectRows); + functionsTree_->setEditTriggers(QAbstractItemView::NoEditTriggers); + functionsTree_->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + functionsTree_->header()->setSectionsMovable(false); + functionsTree_->header()->setSectionsClickable(true); + connect(functionsTree_->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), + this, SLOT(functionsTreeSelectionChanged(QItemSelection, QItemSelection))); + connect(functionsTree_, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(okButtonClicked())); + connect(functionsTree_->header(), SIGNAL(sectionClicked(int)), this, SLOT(sectionClicked(int))); + + functionsFilter_ = new SearchLineEdit(this); + functionsFilter_->setPlaceholderText(QString::fromUtf8(language[lsSearch].c_str())); + connect(functionsFilter_, SIGNAL(textChanged(const QString &)), this, SLOT(functionsFilterChanged())); + connect(functionsFilter_, SIGNAL(returnPressed()), this, SLOT(functionsFilterChanged())); + + panel = new QFrame(this); + panelLayout = new QVBoxLayout(); + panelLayout->setContentsMargins(0, 10, 0, 0); + panelLayout->setSpacing(10); + panelLayout->addWidget(functionsFilter_); + panelLayout->addWidget(functionsTree_); + panel->setLayout(panelLayout); + tabBar_->addTab(panel, QIcon(":/images/star_gray.png"), QString::fromUtf8(language[lsFunctions].c_str())); + + if (mode_ == smAddFunction) { + PropertyManager *propertyManager = new PropertyManager(this); + GroupProperty *protection = propertyManager->addGroupProperty(NULL, QString::fromUtf8(language[lsProtection].c_str())); + compilationType_ = propertyManager->addEnumProperty(protection, QString::fromUtf8(language[lsCompilationType].c_str()), + QStringList() << QString::fromUtf8(language[lsVirtualization].c_str()) + << QString::fromUtf8(language[lsMutation].c_str()) + << QString("%1 (%2 + %3)").arg(QString::fromUtf8(language[lsUltra].c_str())).arg(QString::fromUtf8(language[lsMutation].c_str())).arg(QString::fromUtf8(language[lsVirtualization].c_str())), 0); + lockToKey_ = propertyManager->addBoolProperty(protection, QString::fromUtf8(language[lsLockToSerialNumber].c_str()), false); + + TreePropertyEditor *optionsTree = new TreePropertyEditor(this); + optionsTree->setFrameShape(QFrame::Box); + optionsTree->setModel(propertyManager); + optionsTree->expandToDepth(0); + optionsTree->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + optionsTree->header()->setSectionsMovable(false); + + panel = new QFrame(this); + panelLayout = new QVBoxLayout(); + panelLayout->setContentsMargins(0, 10, 0, 0); + panelLayout->addWidget(optionsTree); + panel->setLayout(panelLayout); + tabBar_->addTab(panel, QIcon(":/images/gear.png"), QString::fromUtf8(language[lsOptions].c_str())); + } + + QToolButton *helpButton = new QToolButton(this); + helpButton->setShortcut(HelpContentsKeySequence()); + helpButton->setIconSize(QSize(20, 20)); + helpButton->setIcon(QIcon(":/images/help_gray.png")); + helpButton->setToolTip(QString::fromUtf8(language[lsHelp].c_str())); + connect(helpButton, SIGNAL(clicked(bool)), this, SLOT(helpClicked())); + + QPushButton *okButton = new PushButton(windowTitle(), this); + connect(okButton, SIGNAL(clicked()), this, SLOT(okButtonClicked())); + + QPushButton *cancelButton = new PushButton(QString::fromUtf8(language[lsCancel].c_str()), this); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + QHBoxLayout *buttonLayout = new QHBoxLayout(); + buttonLayout->setContentsMargins(0, 0, 0, 0); + buttonLayout->setSpacing(10); + buttonLayout->addWidget(helpButton); + buttonLayout->addStretch(); +#ifdef __APPLE__ + buttonLayout->addWidget(cancelButton); + buttonLayout->addWidget(okButton); +#else + buttonLayout->addWidget(okButton); + buttonLayout->addWidget(cancelButton); +#endif + + QGridLayout *layout = new QGridLayout(); + layout->setContentsMargins(10, 10, 10, 10); + layout->setSpacing(10); + layout->addWidget(addressLabel, 0, 0); + layout->addWidget(addressEdit_, 0, 1); + layout->addWidget(tabBar_, 1, 0, 1, 2); + layout->addLayout(buttonLayout, 2, 0, 1, 2); + setLayout(layout); + + setMinimumSize(480 * Application::stylesheetScaleFactor(), 300 * Application::stylesheetScaleFactor()); +} + +bool FunctionDialog::checkAddress(const AddressInfo &info) +{ + if (!info.arch) + return false; + + if (mode_ == smAddFunction) { + if (info.arch->segment_list()->GetMemoryTypeByAddress(info.address) & mtExecutable) { + return true; + } else { + MapFunction *func = info.arch->map_function_list()->GetFunctionByAddress(info.address); + if (func && func->type() == otString) + return true; + } + } else { + if (info.arch->segment_list()->GetSectionByAddress(info.address)) + return true; + } + return false; +} + +void FunctionDialog::okButtonClicked() +{ + addresses_.clear(); + + bool show_arch_name = file_->map_function_list()->show_arch_name(); + + QStringList address_list = addressEdit_->text().split(','); + if (address_list.isEmpty()) + address_list.append("0"); + + QString address_str; + AddressInfo info; + info.arch = NULL; + int p = 0; + for (int i = 0; i < address_list.size(); i++) { + address_str = address_list[i].trimmed(); + info.arch = defaultArch_; + if (show_arch_name) { + int dot_pos = address_str.indexOf('.'); + if (dot_pos > -1) { + info.arch = file_->GetArchitectureByName(address_str.left(dot_pos).toUtf8().constData()); + address_str.remove(0, dot_pos + 1); + } + } + bool is_valid; + info.address = address_str.toULongLong(&is_valid, 16); + + if (!is_valid || !checkAddress(info)) { + MessageDialog::critical(this, "Invalid address", QMessageBox::Ok); + addressEdit_->setFocus(); + addressEdit_->setCursorPosition(p); + addressEdit_->cursorForward(true, address_list[i].size()); + return; + } + addresses_.append(info); + p += address_list[i].size() + 1; + } + + accept(); +} + +void FunctionDialog::functionsTreeSelectionChanged(const QItemSelection & /*selected*/, const QItemSelection & /*deselected*/) +{ + QModelIndexList list; + + list = functionsTree_->selectionModel()->selectedIndexes(); + + QString address; + for (int i = 0; i < list.size(); i++) { + QModelIndex index = list.at(i); + if (index.column() != 0) + continue; + + if (!address.isEmpty()) + address.append(", "); + if (functionBundleListModel_.get()) { + MapFunctionBundle *func = static_cast<MapFunctionBundle *>(index.internalPointer()); + address.append(QString::fromLatin1(func->display_address().c_str())); + } else { + MapFunction *func = static_cast<MapFunction *>(index.internalPointer()); + address.append(QString::fromLatin1(func->display_address("").c_str())); + } + } + addressEdit_->setText(address); +} + +CompilationType FunctionDialog::compilationType() const +{ + return static_cast<CompilationType>(compilationType_->value()); +} + +uint32_t FunctionDialog::compilationOptions() const +{ + uint32_t res = 0; + if (lockToKey_->value()) + res |= coLockToKey; + return res; +} + +void FunctionDialog::functionsFilterChanged() +{ + if (functionBundleListModel_.get()) + functionBundleListModel_->search(functionsFilter_->text()); + else + functionListModel_->search(functionsFilter_->text()); +} + +void FunctionDialog::helpClicked() +{ + HelpBrowser::showTopic(tabBar_->currentIndex() == 0 ? "functions::search" : "functions::setup"); +} + +void FunctionDialog::sectionClicked(int index) +{ + auto mdl = functionsTree_->model(); + assert(mdl); + if (mdl) + mdl->sort(index); +}
\ No newline at end of file diff --git a/VMProtect/function_dialog.h b/VMProtect/function_dialog.h new file mode 100644 index 0000000..54b3b54 --- /dev/null +++ b/VMProtect/function_dialog.h @@ -0,0 +1,45 @@ +#ifndef FUNCTION_DIALOG_H +#define FUNCTION_DIALOG_H + +struct AddressInfo { + uint64_t address; + IArchitecture *arch; +}; + +enum ShowMode { + smAddFunction, + smGotoAddress +}; + +class FunctionDialog : public QDialog +{ + Q_OBJECT +public: + FunctionDialog(IFile *file, IArchitecture *arch, ShowMode mode, QWidget *parent = NULL); + QList<AddressInfo> addresses() const { return addresses_; } + CompilationType compilationType() const; + uint32_t compilationOptions() const; +private slots: + void okButtonClicked(); + void functionsTreeSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected); + void functionsFilterChanged(); + void helpClicked(); + void sectionClicked(int index); +private: + bool checkAddress(const AddressInfo &info); + + QTabWidget *tabBar_; + IFile *file_; + ShowMode mode_; + QLineEdit *addressEdit_; + SearchLineEdit *functionsFilter_; + QTreeView *functionsTree_; + QList<AddressInfo> addresses_; + EnumProperty *compilationType_; + BoolProperty *lockToKey_; + std::auto_ptr<MapFunctionBundleListModel> functionBundleListModel_; + std::auto_ptr<MapFunctionListModel> functionListModel_; + IArchitecture *defaultArch_; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/help_browser.cc b/VMProtect/help_browser.cc new file mode 100644 index 0000000..cb028e2 --- /dev/null +++ b/VMProtect/help_browser.cc @@ -0,0 +1,689 @@ +#include "help_browser.h" +#include "message_dialog.h" +#include "widgets.h" +#include "moc/moc_help_browser.cc" +#include "../core/objects.h" +#include "../core/lang.h" +#include "../core/inifile.h" +#include "remotecontrol.h" + +/** + * HelpContentModel + */ + +HelpContentModel::HelpContentModel(QHelpEngine *engine, QObject *parent) + : QIdentityProxyModel(parent) +{ + setSourceModel(engine->contentModel()); +} + +QVariant HelpContentModel::data(const QModelIndex &index, int role) const +{ + if (role == Qt::FontRole) { + if (!index.parent().isValid()) { + // top level + QFont font; + font.setBold(true); + return font; + } + } + return QIdentityProxyModel::data(index, role); +} + +QVariant HelpContentModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role == Qt::DisplayRole) { + if (section == 0) + return QString::fromUtf8(language[lsContents].c_str()); + } + return QIdentityProxyModel::headerData(section, orientation, role); +} + +QHelpContentItem *HelpContentModel::contentItemAt(const QModelIndex &index) const +{ + QHelpContentModel *model = qobject_cast<QHelpContentModel*>(sourceModel()); + if (model) + return model->contentItemAt(index); + return NULL; +} + +QModelIndex HelpContentModel::indexOf(const QUrl &link) +{ + if (link.scheme() != QLatin1String("qthelp")) + return QModelIndex(); + + QString fragment = link.fragment(); + for (int i = 0; i < rowCount(); ++i) { + QHelpContentItem *item = contentItemAt(index(i, 0)); + if (item && item->url().host() == link.host()) { + QString path = link.path(); + //if (path.startsWith(QLatin1Char('/'))) + // path = path.mid(1); + QModelIndex res = searchContentItem(index(i, 0), path); + if (res.isValid()) { + if (!fragment.isEmpty()) { + item = contentItemAt(res); + assert(item); + for (int j = 0; item && (j < item->childCount()); ++j) { + auto ch = item->child(j); + assert(ch); + if (ch && (ch->url().fragment() == fragment)) { + res = index(j, 0, res); + break; + } + } + } + return res; + } + } + } + return QModelIndex(); +} + +QModelIndex HelpContentModel::searchContentItem(const QModelIndex &parent, const QString &path) +{ + QHelpContentItem *parentItem = contentItemAt(parent); + if (!parentItem) + return QModelIndex(); + + QString cpath = parentItem->url().path(); + if (cpath == path) + return parent; + + for (int i = 0; i < parentItem->childCount(); ++i) { + QModelIndex res = searchContentItem(index(i, 0, parent), path); + if (res.isValid()) + return res; + } + return QModelIndex(); +} + +/** + * HelpResultItem + */ + +HelpResultItem::HelpResultItem(const QString &title, const QString &url, const QString &toolTip) + : title_(title), url_(url), toolTip_(toolTip), parent_(NULL) +{ + +} + +HelpResultItem::~HelpResultItem() +{ + clear(); + if (parent_) + parent_->removeChild(this); +} + +void HelpResultItem::clear() +{ + for (int i = 0; i < children_.size(); i++) { + HelpResultItem *item = children_[i]; + item->parent_ = NULL; + delete item; + } + children_.clear(); +} + +void HelpResultItem::addChild(HelpResultItem *child) +{ + insertChild(childCount(), child); +} + +void HelpResultItem::insertChild(int index, HelpResultItem *child) +{ + if (child->parent()) + return; + + child->parent_ = this; + children_.insert(index, child); +} + +void HelpResultItem::removeChild(HelpResultItem *child) +{ + if (children_.removeOne(child)) + child->parent_ = NULL; +} + +/** + * HelpResultModel + */ + +HelpResultModel::HelpResultModel(QHelpEngine *engine, QObject *parent) + : QAbstractItemModel(parent), engine_(engine) +{ + root_ = new HelpResultItem(QString(), QString(), QString()); + + connect(engine_->searchEngine(), SIGNAL(searchingFinished(int)), this, SLOT(searchingFinished())); +} + +HelpResultModel::~HelpResultModel() +{ + delete root_; +} + +QModelIndex HelpResultModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + HelpResultItem *childItem = itemAt(index); + HelpResultItem *parentItem = childItem->parent(); + if (parentItem == root_) + return QModelIndex(); + + return createIndex(parentItem->parent()->children().indexOf(parentItem), 0, parentItem); +} + +int HelpResultModel::columnCount(const QModelIndex & /* parent */) const +{ + return 1; +} + +QVariant HelpResultModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role == Qt::DisplayRole) { + if (section == 0) + return QString::fromUtf8(language[lsSearchResult].c_str()); + } + return QVariant(); +} + +int HelpResultModel::rowCount(const QModelIndex &parent) const +{ + HelpResultItem *parentItem = itemAt(parent); + return parentItem->childCount(); +} + +QVariant HelpResultModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + HelpResultItem *item = itemAt(index); + switch (role) { + case Qt::DisplayRole: + return item->title(); + case Qt::ToolTipRole: + return item->toolTip(); + case Qt::FontRole: + if (!index.parent().isValid()) { + // top level + QFont font; + font.setBold(true); + return font; + } + break; + } + return QVariant(); +} + +QModelIndex HelpResultModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) + return QModelIndex(); + + HelpResultItem *parentItem = itemAt(parent); + HelpResultItem *childItem = parentItem->child(row); + if (!childItem) + return QModelIndex(); + + return createIndex(row, column, childItem); +} + +HelpResultItem *HelpResultModel::itemAt(const QModelIndex &index) const +{ + if (index.isValid()) + return static_cast<HelpResultItem *>(index.internalPointer()); + return root_; +} + +void HelpResultModel::search(const QString &text) +{ + QHelpSearchQuery q(QHelpSearchQuery::DEFAULT, QStringList(text)); + QList<QHelpSearchQuery> ql; + ql.append(q); + engine_->searchEngine()->search(ql); +} + +void HelpResultModel::searchingFinished() +{ + beginResetModel(); + + root_->clear(); + QList<QHelpSearchEngine::SearchHit> hits = engine_->searchEngine()->hits(0, engine_->searchEngine()->hitsCount()); + foreach(const QHelpSearchEngine::SearchHit &hit, hits) { + QString toolTip; + QModelIndex index = engine_->contentWidget()->indexOf(hit.first); + while (index.isValid()) { + QHelpContentItem *item = engine_->contentModel()->contentItemAt(index); + if (item) { + if (!toolTip.isEmpty()) + toolTip = " > " + toolTip; + toolTip = item->title() + toolTip; + } + index = index.parent(); + } + root_->addChild(new HelpResultItem(hit.second, hit.first, toolTip)); + } + + endResetModel(); + + emit finished(root_->childCount()); +} + +class TextBrowser : public QTextBrowser +{ +public: + TextBrowser(QHelpEngine *helpEngine, QWidget *parent_ = 0): QTextBrowser(parent_), helpEngine_(helpEngine) {} + QVariant loadResource(int type, const QUrl &url) + { + const QString &scheme = url.scheme(); + if(scheme == "qthelp") + return QVariant(helpEngine_->fileData(url)); + else + return QTextBrowser::loadResource(type, url); + } + bool navigateToKeyword(const QString &keywordId) + { + auto links = helpEngine_->linksForIdentifier(keywordId); + if(links.count() > 0) + { + setSource(links.begin().value()); + return true; + } + return false; + } + void setSource(const QUrl &src) + { + const QUrl &prevSrc = source(); + if(src == prevSrc) return; + + const QString &scheme = src.scheme(); + if(scheme != "qthelp") + { + QDesktopServices::openUrl(src); + return; + } + + QTextBrowser::setSource(src); + } + + bool findText(const QString &text, QTextDocument::FindFlags flags, bool incremental, bool fromSearch) + { + QTextDocument *doc = document(); + QTextCursor cursor = textCursor(); + if (!doc || cursor.isNull()) + return false; + + const int position = cursor.selectionStart(); + if (incremental) + cursor.setPosition(position); + + QTextCursor found = doc->find(text, cursor, flags); + if (found.isNull()) { + if ((flags & QTextDocument::FindBackward) == 0) + cursor.movePosition(QTextCursor::Start); + else + cursor.movePosition(QTextCursor::End); + found = doc->find(text, cursor, flags); + } + + if (fromSearch) { + cursor.beginEditBlock(); + viewport()->setUpdatesEnabled(false); + + QTextCharFormat marker; + marker.setForeground(Qt::red); + marker.setBackground(Qt::yellow); + cursor.movePosition(QTextCursor::Start); + setTextCursor(cursor); + + while (find(text)) { + QTextCursor hit = textCursor(); + hit.mergeCharFormat(marker); + } + + viewport()->setUpdatesEnabled(true); + cursor.endEditBlock(); + } + + bool cursorIsNull = found.isNull(); + if (cursorIsNull) { + found = textCursor(); + found.setPosition(position); + } + setTextCursor(found); + return !cursorIsNull; + } + +private: + QHelpEngine *helpEngine_; +}; + +HelpBrowser::HelpBrowser(const QString &fileName) + : QMainWindow(NULL), fileName_(fileName), contentsCreated_(false) +{ + settings_file(); + + QVBoxLayout *mainLayout = new QVBoxLayout; + mainLayout->setContentsMargins(0, 0, 0, 0); + mainLayout->setSpacing(0); + + QToolBar *toolBar = new QToolBar(this); + QSplitter *splitter = new QSplitter(Qt::Horizontal, this); + + QIcon icon = QIcon(":/images/back.png"); + icon.addPixmap(QPixmap(":/images/back_hover.png"), QIcon::Active, QIcon::Off); + icon.addPixmap(QPixmap(":/images/back_disabled.png"), QIcon::Disabled, QIcon::Off); + backButton_ = new QAction(icon, QString::fromUtf8(language[lsBack].c_str()), this); + backButton_->setEnabled(false); + + icon = QIcon(":/images/forward.png"); + icon.addPixmap(QPixmap(":/images/forward_hover.png"), QIcon::Active, QIcon::Off); + icon.addPixmap(QPixmap(":/images/forward_disabled.png"), QIcon::Disabled, QIcon::Off); + fwdButton_ = new QAction(icon, QString::fromUtf8(language[lsForward].c_str()), this); + fwdButton_->setEnabled(false); + + searchBox_ = new SearchLineEdit(this); + searchBox_->setFrame(false); + searchBox_->setFixedWidth(200); + searchBox_->setPlaceholderText(QString::fromUtf8(language[lsSearch].c_str())); + connect(searchBox_, SIGNAL(textChanged(const QString &)), this, SLOT(searchBoxChanged())); + connect(searchBox_, SIGNAL(returnPressed()), this, SLOT(searchBoxChanged())); + + toolBar->setMovable(false); + toolBar->setIconSize(QSize(22, 22)); + toolBar->addSeparator(); + toolBar->addAction(backButton_); + toolBar->addAction(fwdButton_); + toolBar->addSeparator(); + QWidget *spacer = new QWidget(this); + spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + toolBar->addWidget(spacer); + toolBar->addWidget(searchBox_); + + QVBoxLayout *vLayout = new QVBoxLayout(this); + vLayout->setContentsMargins(0, 0, 0, 0); + vLayout->setSpacing(0); + + helpEngine_ = new QHelpEngine(fileName_, splitter); + connect(helpEngine_->contentModel(), SIGNAL(contentsCreated()), this, SLOT(contentsCreated())); + if (!helpEngine_->setupData()) { + contentsCreated_ = true; + MessageDialog::critical(this, QString("Can not open file \"%1\"").arg(fileName_), QMessageBox::Ok); + } + + contentModel_ = new HelpContentModel(helpEngine_, this); + resultModel_ = new HelpResultModel(helpEngine_, this); + + contentWidget_ = new TreeView(this); + contentWidget_->setObjectName("project"); + contentWidget_->setFrameShape(QFrame::NoFrame); + contentWidget_->header()->setObjectName("project"); + contentWidget_->setUniformRowHeights(true); + contentWidget_->setModel(contentModel_); + + resultWidget_ = new TreeView(this); + resultWidget_->setObjectName("project"); + resultWidget_->setFrameShape(QFrame::NoFrame); + resultWidget_->header()->setObjectName("project"); + resultWidget_->setUniformRowHeights(true); + resultWidget_->setModel(resultModel_); + + QToolButton *closeButton = new QToolButton(this); + closeButton->setObjectName("cancel"); + closeButton->setToolTip(QString::fromUtf8(language[lsClose].c_str())); + + QHBoxLayout *layout = new QHBoxLayout; + layout->setContentsMargins(5, 0, 5, 0); + layout->setSpacing(0); + layout->addWidget(closeButton, 0, Qt::AlignRight); + resultWidget_->header()->setLayout(layout); + + tabWidget_ = new QStackedWidget; + tabWidget_->addWidget(contentWidget_); + tabWidget_->addWidget(resultWidget_); + + splitter->addWidget(tabWidget_); + helpBrowser_ = new TextBrowser(helpEngine_); + helpBrowser_->setFrameShape(QFrame::NoFrame); + + QWidget *right = new QWidget(); + vLayout->addWidget(helpBrowser_); + findWidget_ = new FindWidget(this); + vLayout->addWidget(findWidget_); + findWidget_->hide(); + right->setLayout(vLayout); + splitter->addWidget(right); + splitter->setStretchFactor(1, 1); + + mainLayout->addWidget(toolBar); + mainLayout->addWidget(splitter); + + QWidget *window = new QWidget(); + window->setLayout(mainLayout); + setCentralWidget(window); + + RemoteControl *rc = new RemoteControl(this); + connect(helpBrowser_, SIGNAL(sourceChanged(const QUrl &)), this, SLOT(syncTree(const QUrl &))); + connect(rc, SIGNAL(handleNavigateToKeywordCommand(const QString &)), this, SLOT(handleNavigateToKeywordCommand(const QString &))); + + connect(contentWidget_, SIGNAL(clicked(const QModelIndex &)), this, SLOT(contentWidgetClicked(const QModelIndex &))); + connect(resultWidget_, SIGNAL(clicked(const QModelIndex &)), this, SLOT(resultWidgetClicked(const QModelIndex &))); + connect(backButton_, SIGNAL(triggered()), helpBrowser_, SLOT(backward())); + connect(fwdButton_, SIGNAL(triggered()), helpBrowser_, SLOT(forward())); + connect(helpBrowser_, SIGNAL(backwardAvailable(bool)), backButton_, SLOT(setEnabled(bool))); + connect(helpBrowser_, SIGNAL(forwardAvailable(bool)), fwdButton_, SLOT(setEnabled(bool))); + connect(helpBrowser_, SIGNAL(sourceChanged(const QUrl &)), this, SLOT(highlightSearchTerms())); + connect(resultModel_, SIGNAL(finished(int)), this, SLOT(searchingFinished())); + connect(closeButton, SIGNAL(clicked(bool)), this, SLOT(resultCloseClicked())); + + connect(findWidget_, SIGNAL(findNext()), this, SLOT(findNext())); + connect(findWidget_, SIGNAL(findPrevious()), this, SLOT(findPrevious())); + connect(findWidget_, SIGNAL(find(QString, bool, bool)), this, + SLOT(find(QString, bool, bool))); + connect(findWidget_, SIGNAL(escapePressed()), helpBrowser_, SLOT(setFocus())); + + resize(890, 440); +} + +void HelpBrowser::handleNavigateToKeywordCommand(const QString &arg) +{ + if(arg.length()) navigateToKeyword(arg); + raise(); + activateWindow(); +} + +void HelpBrowser::findNext() +{ + find(findWidget_->text(), true, false); +} + +void HelpBrowser::findPrevious() +{ + find(findWidget_->text(), false, false); +} + +void HelpBrowser::find(const QString &ttf, bool forward, bool incremental) +{ + bool found = false; + QTextDocument::FindFlags flags = (QTextDocument::FindFlags)0; + if (!forward) + flags |= QTextDocument::FindBackward; + if (findWidget_->caseSensitive()) + flags |= QTextDocument::FindCaseSensitively; + found = helpBrowser_->findText(ttf, flags, incremental, false); + + if (!found && ttf.isEmpty()) + found = true; // the line edit is empty, no need to mark it red... + + if (!findWidget_->isVisible()) + findWidget_->show(); + findWidget_->setPalette(found); +} + +void HelpBrowser::highlightSearchTerms() +{ + if (tabWidget_->currentIndex() != 1) + return; + + QHelpSearchEngine *searchEngine = helpEngine_->searchEngine(); + QList<QHelpSearchQuery> queryList = searchEngine->query(); + + QStringList terms; + foreach (const QHelpSearchQuery &query, queryList) { + switch (query.fieldName) + { + default: break; + case QHelpSearchQuery::ALL: + case QHelpSearchQuery::PHRASE: + case QHelpSearchQuery::DEFAULT: + case QHelpSearchQuery::ATLEAST: + foreach (QString term, query.wordList) + terms.append(term.remove(QLatin1Char('"'))); + } + } + + foreach (const QString& term, terms) + helpBrowser_->findText(term, 0, false, true); +} + +void HelpBrowser::keyPressEvent(QKeyEvent *e) +{ + if ((e->modifiers() & Qt::ControlModifier) && e->key()==Qt::Key_F) { + if (!findWidget_->isVisible()) { + findWidget_->showAndClear(searchBox_->text()); + } else { + findWidget_->show(); + } + } else { + QWidget::keyPressEvent(e); + } +} + +void HelpBrowser::searchBoxChanged() +{ + QString term = searchBox_->text(); + if(term.length() < 3) { + tabWidget_->setCurrentIndex(0); + return; + } + + resultModel_->search(term); +} + +void HelpBrowser::searchingFinished() +{ + tabWidget_->setCurrentIndex(1); +} + +void HelpBrowser::syncTree(const QUrl &src) +{ + setWindowTitle(QString("%1: %2").arg(QString::fromUtf8(language[lsHelp].c_str())).arg(helpBrowser_->documentTitle())); + + // Synchronize with help content widget + QModelIndex indexOfSource = contentModel_->indexOf(src); + if (contentWidget_->currentIndex() != indexOfSource) + contentWidget_->setCurrentIndex(indexOfSource); + + if(indexOfSource.isValid()) + contentWidget_->expand(indexOfSource); + else + contentWidget_->expandAll(); +} + +static QString helpFileName(const QString &lang) +{ + return QString("%1/Help/%2.qhc").arg(QCoreApplication::applicationDirPath()).arg(lang); +} + +void HelpBrowser::showTopic(const QString &keywordId) +{ + QString fileName = helpFileName(QString::fromUtf8(settings_file().language().c_str())); + if (!QFileInfo(fileName).exists()) + fileName = helpFileName("en"); + + bool bOldProcess = true; + if (help_browser_process_ == NULL || help_browser_process_->state() == QProcess::NotRunning || help_browser_process_->fileName_ != fileName) { + delete help_browser_process_; + help_browser_process_ = new QHelpBrowserProcess(qApp, fileName); + if (!help_browser_process_->waitForStarted()) + { + MessageDialog::critical(NULL, QString("Can not launch help system"), QMessageBox::Ok); + delete help_browser_process_; + help_browser_process_ = NULL; + return; + } + bOldProcess = false; + } + QByteArray ba; + ba += "navigateToKeyword#"; + ba += (keywordId.length() || bOldProcess) ? keywordId : QString("default"); + ba += ";\n"; + help_browser_process_->write(ba); +} + +void HelpBrowser::navigateToKeyword(const QString &keywordId) +{ + for (int i = 0; i < 50 && !contentsCreated_; i++) + QCoreApplication::processEvents(QEventLoop::AllEvents, 100); + if(!helpBrowser_->navigateToKeyword(keywordId)) + MessageDialog::critical(this, QString("Can not find keyword \"%1\" for \"%2\"").arg(keywordId, fileName_), QMessageBox::Ok); +} + +void HelpBrowser::contentWidgetClicked(const QModelIndex &index) +{ + QHelpContentItem *item = contentModel_->contentItemAt(index); + if (!item) + return; + + QUrl url = item->url(); + if (url.isValid()) + helpBrowser_->setSource(url); +} + +void HelpBrowser::resultWidgetClicked(const QModelIndex &index) +{ + HelpResultItem *item = resultModel_->itemAt(index); + if (!item) + return; + + QUrl url = item->url(); + if (url.isValid()) + helpBrowser_->setSource(url); +} + +void HelpBrowser::pathClicked(const QString &link) +{ + helpBrowser_->setSource(link); +} + +void HelpBrowser::resultCloseClicked() +{ + searchBox_->clear(); +} + +void HelpBrowser::contentsCreated() +{ + contentsCreated_ = true; +} + +/** + * QHelpBrowserProcess + */ + +QHelpBrowserProcess *HelpBrowser::help_browser_process_; + +QHelpBrowserProcess::QHelpBrowserProcess(QObject *parent, const QString &fileName) : QProcess(parent), fileName_(fileName) +{ + QStringList args; + args << "--help" << fileName; + start(QCoreApplication::applicationFilePath(), args); +} + +QHelpBrowserProcess::~QHelpBrowserProcess() +{ + if(state() != NotRunning) + kill(); +}
\ No newline at end of file diff --git a/VMProtect/help_browser.h b/VMProtect/help_browser.h new file mode 100644 index 0000000..1c9cf39 --- /dev/null +++ b/VMProtect/help_browser.h @@ -0,0 +1,125 @@ +#ifndef HELP_BROWSER_H +#define HELP_BROWSER_H + +class TextBrowser; +class QHelpEngine; +class QHelpSearchEngine; +class QPushButton; +class SearchLineEdit; +class QHelpContentItem; +class FindWidget; + +class HelpContentModel : public QIdentityProxyModel +{ +public: + HelpContentModel(QHelpEngine *engine, QObject *parent = 0); + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QHelpContentItem *contentItemAt(const QModelIndex &index) const; + QModelIndex indexOf(const QUrl &link); +private: + QModelIndex searchContentItem(const QModelIndex &parent, const QString &path); +}; + +class HelpResultItem +{ +public: + HelpResultItem(const QString &title, const QString &url, const QString &toolTip); + ~HelpResultItem(); + QString title() const { return title_; } + QString url() const { return url_; } + QString toolTip() const { return toolTip_; } + HelpResultItem *child(int index) const { return children_.value(index); }; + int childCount() const { return children_.size(); } + QList<HelpResultItem *> children() const { return children_; }; + HelpResultItem *parent() const { return parent_; }; + void clear(); + void addChild(HelpResultItem *child); + void insertChild(int index, HelpResultItem *child); + void removeChild(HelpResultItem *child); +private: + HelpResultItem *parent_; + QString title_; + QString url_; + QString toolTip_; + QList<HelpResultItem *> children_; +}; + +class HelpResultModel : public QAbstractItemModel +{ + Q_OBJECT +public: + HelpResultModel(QHelpEngine *engine, QObject *parent = 0); + ~HelpResultModel(); + void search(const QString &text); + virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + virtual QModelIndex parent(const QModelIndex &index) const; + virtual int rowCount(const QModelIndex &parent) const; + virtual int columnCount(const QModelIndex &parent) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + HelpResultItem *itemAt(const QModelIndex &index) const; +signals: + void finished(int hits); +protected slots: + void searchingFinished(); +private: + QHelpEngine *engine_; + HelpResultItem *root_; +}; + +class QHelpBrowserProcess : public QProcess +{ +public: + QHelpBrowserProcess(QObject *parent, const QString &fileName); + const QString fileName_; + ~QHelpBrowserProcess(); +}; + +class RemoteControl; +class HelpBrowser : public QMainWindow +{ + Q_OBJECT +public: + HelpBrowser(const QString &fileName); + static void showTopic(const QString &keywordId); + +private: + void navigateToKeyword(const QString &keywordId); + void keyPressEvent(QKeyEvent *e); + void updatePath(); + + static QHelpBrowserProcess *help_browser_process_; + + QString fileName_; + QHelpEngine *helpEngine_; + TextBrowser *helpBrowser_; + QAction *backButton_; + QAction *fwdButton_; + SearchLineEdit *searchBox_; + QStackedWidget *tabWidget_; + FindWidget *findWidget_; + QTreeView *contentWidget_; + QTreeView *resultWidget_; + HelpContentModel *contentModel_; + HelpResultModel *resultModel_; + RemoteControl *rc_; + bool contentsCreated_; + +protected Q_SLOTS: + void syncTree(const QUrl &); + void searchBoxChanged(); + void searchingFinished(); + void highlightSearchTerms(); + void findNext(); + void findPrevious(); + void find(const QString &ttf, bool forward, bool incremental); + void contentWidgetClicked(const QModelIndex &index); + void resultWidgetClicked(const QModelIndex &index); + void pathClicked(const QString &link); + void resultCloseClicked(); + void contentsCreated(); + void handleNavigateToKeywordCommand(const QString &arg); +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/images/add.png b/VMProtect/images/add.png Binary files differnew file mode 100644 index 0000000..4367857 --- /dev/null +++ b/VMProtect/images/add.png diff --git a/VMProtect/images/add_disabled.png b/VMProtect/images/add_disabled.png Binary files differnew file mode 100644 index 0000000..3311b86 --- /dev/null +++ b/VMProtect/images/add_disabled.png diff --git a/VMProtect/images/add_gray.png b/VMProtect/images/add_gray.png Binary files differnew file mode 100644 index 0000000..1e87c76 --- /dev/null +++ b/VMProtect/images/add_gray.png diff --git a/VMProtect/images/add_hover.png b/VMProtect/images/add_hover.png Binary files differnew file mode 100644 index 0000000..4d2f40a --- /dev/null +++ b/VMProtect/images/add_hover.png diff --git a/VMProtect/images/back.png b/VMProtect/images/back.png Binary files differnew file mode 100644 index 0000000..74de084 --- /dev/null +++ b/VMProtect/images/back.png diff --git a/VMProtect/images/back_disabled.png b/VMProtect/images/back_disabled.png Binary files differnew file mode 100644 index 0000000..ba06b7d --- /dev/null +++ b/VMProtect/images/back_disabled.png diff --git a/VMProtect/images/back_hover.png b/VMProtect/images/back_hover.png Binary files differnew file mode 100644 index 0000000..cd36cf8 --- /dev/null +++ b/VMProtect/images/back_hover.png diff --git a/VMProtect/images/boot_examples.png b/VMProtect/images/boot_examples.png Binary files differnew file mode 100644 index 0000000..c3f0713 --- /dev/null +++ b/VMProtect/images/boot_examples.png diff --git a/VMProtect/images/boot_help.png b/VMProtect/images/boot_help.png Binary files differnew file mode 100644 index 0000000..057b192 --- /dev/null +++ b/VMProtect/images/boot_help.png diff --git a/VMProtect/images/boot_open.png b/VMProtect/images/boot_open.png Binary files differnew file mode 100644 index 0000000..6bf314b --- /dev/null +++ b/VMProtect/images/boot_open.png diff --git a/VMProtect/images/box.png b/VMProtect/images/box.png Binary files differnew file mode 100644 index 0000000..d53555c --- /dev/null +++ b/VMProtect/images/box.png diff --git a/VMProtect/images/branch_closed.png b/VMProtect/images/branch_closed.png Binary files differnew file mode 100644 index 0000000..dbb2111 --- /dev/null +++ b/VMProtect/images/branch_closed.png diff --git a/VMProtect/images/branch_open.png b/VMProtect/images/branch_open.png Binary files differnew file mode 100644 index 0000000..01095be --- /dev/null +++ b/VMProtect/images/branch_open.png diff --git a/VMProtect/images/browse.png b/VMProtect/images/browse.png Binary files differnew file mode 100644 index 0000000..4066d17 --- /dev/null +++ b/VMProtect/images/browse.png diff --git a/VMProtect/images/bullet_delete.png b/VMProtect/images/bullet_delete.png Binary files differnew file mode 100644 index 0000000..4b76652 --- /dev/null +++ b/VMProtect/images/bullet_delete.png diff --git a/VMProtect/images/bullet_import.png b/VMProtect/images/bullet_import.png Binary files differnew file mode 100644 index 0000000..5fae0b6 --- /dev/null +++ b/VMProtect/images/bullet_import.png diff --git a/VMProtect/images/bullet_key.png b/VMProtect/images/bullet_key.png Binary files differnew file mode 100644 index 0000000..d3039c7 --- /dev/null +++ b/VMProtect/images/bullet_key.png diff --git a/VMProtect/images/bullet_link.png b/VMProtect/images/bullet_link.png Binary files differnew file mode 100644 index 0000000..ac0ee16 --- /dev/null +++ b/VMProtect/images/bullet_link.png diff --git a/VMProtect/images/bullet_warning.png b/VMProtect/images/bullet_warning.png Binary files differnew file mode 100644 index 0000000..c2df800 --- /dev/null +++ b/VMProtect/images/bullet_warning.png diff --git a/VMProtect/images/calc.png b/VMProtect/images/calc.png Binary files differnew file mode 100644 index 0000000..41687c4 --- /dev/null +++ b/VMProtect/images/calc.png diff --git a/VMProtect/images/cancel.png b/VMProtect/images/cancel.png Binary files differnew file mode 100644 index 0000000..0124c47 --- /dev/null +++ b/VMProtect/images/cancel.png diff --git a/VMProtect/images/cancel_gray.png b/VMProtect/images/cancel_gray.png Binary files differnew file mode 100644 index 0000000..260dabc --- /dev/null +++ b/VMProtect/images/cancel_gray.png diff --git a/VMProtect/images/cancel_hover.png b/VMProtect/images/cancel_hover.png Binary files differnew file mode 100644 index 0000000..3f686f3 --- /dev/null +++ b/VMProtect/images/cancel_hover.png diff --git a/VMProtect/images/check_off.png b/VMProtect/images/check_off.png Binary files differnew file mode 100644 index 0000000..bf49304 --- /dev/null +++ b/VMProtect/images/check_off.png diff --git a/VMProtect/images/check_off_hover.png b/VMProtect/images/check_off_hover.png Binary files differnew file mode 100644 index 0000000..25c2f54 --- /dev/null +++ b/VMProtect/images/check_off_hover.png diff --git a/VMProtect/images/check_on.png b/VMProtect/images/check_on.png Binary files differnew file mode 100644 index 0000000..fd827bb --- /dev/null +++ b/VMProtect/images/check_on.png diff --git a/VMProtect/images/check_on_hover.png b/VMProtect/images/check_on_hover.png Binary files differnew file mode 100644 index 0000000..537ec9d --- /dev/null +++ b/VMProtect/images/check_on_hover.png diff --git a/VMProtect/images/checkbox.png b/VMProtect/images/checkbox.png Binary files differnew file mode 100644 index 0000000..b2f3cd9 --- /dev/null +++ b/VMProtect/images/checkbox.png diff --git a/VMProtect/images/checkbox_checked.png b/VMProtect/images/checkbox_checked.png Binary files differnew file mode 100644 index 0000000..0ab5940 --- /dev/null +++ b/VMProtect/images/checkbox_checked.png diff --git a/VMProtect/images/code.png b/VMProtect/images/code.png Binary files differnew file mode 100644 index 0000000..483c941 --- /dev/null +++ b/VMProtect/images/code.png diff --git a/VMProtect/images/compile.png b/VMProtect/images/compile.png Binary files differnew file mode 100644 index 0000000..fe3392e --- /dev/null +++ b/VMProtect/images/compile.png diff --git a/VMProtect/images/compile_disabled.png b/VMProtect/images/compile_disabled.png Binary files differnew file mode 100644 index 0000000..0c42618 --- /dev/null +++ b/VMProtect/images/compile_disabled.png diff --git a/VMProtect/images/compile_hover.png b/VMProtect/images/compile_hover.png Binary files differnew file mode 100644 index 0000000..2ac6032 --- /dev/null +++ b/VMProtect/images/compile_hover.png diff --git a/VMProtect/images/copy.png b/VMProtect/images/copy.png Binary files differnew file mode 100644 index 0000000..4be1934 --- /dev/null +++ b/VMProtect/images/copy.png diff --git a/VMProtect/images/copy_disabled.png b/VMProtect/images/copy_disabled.png Binary files differnew file mode 100644 index 0000000..1f52616 --- /dev/null +++ b/VMProtect/images/copy_disabled.png diff --git a/VMProtect/images/copy_hover.png b/VMProtect/images/copy_hover.png Binary files differnew file mode 100644 index 0000000..cf1ff30 --- /dev/null +++ b/VMProtect/images/copy_hover.png diff --git a/VMProtect/images/cut.png b/VMProtect/images/cut.png Binary files differnew file mode 100644 index 0000000..35c71be --- /dev/null +++ b/VMProtect/images/cut.png diff --git a/VMProtect/images/cut_disabled.png b/VMProtect/images/cut_disabled.png Binary files differnew file mode 100644 index 0000000..1063861 --- /dev/null +++ b/VMProtect/images/cut_disabled.png diff --git a/VMProtect/images/cut_hover.png b/VMProtect/images/cut_hover.png Binary files differnew file mode 100644 index 0000000..b2deaaa --- /dev/null +++ b/VMProtect/images/cut_hover.png diff --git a/VMProtect/images/database.png b/VMProtect/images/database.png Binary files differnew file mode 100644 index 0000000..fe6cafd --- /dev/null +++ b/VMProtect/images/database.png diff --git a/VMProtect/images/database_export.png b/VMProtect/images/database_export.png Binary files differnew file mode 100644 index 0000000..fbf15f9 --- /dev/null +++ b/VMProtect/images/database_export.png diff --git a/VMProtect/images/database_import.png b/VMProtect/images/database_import.png Binary files differnew file mode 100644 index 0000000..241c58b --- /dev/null +++ b/VMProtect/images/database_import.png diff --git a/VMProtect/images/delete.png b/VMProtect/images/delete.png Binary files differnew file mode 100644 index 0000000..ace289e --- /dev/null +++ b/VMProtect/images/delete.png diff --git a/VMProtect/images/details.png b/VMProtect/images/details.png Binary files differnew file mode 100644 index 0000000..fcd52a5 --- /dev/null +++ b/VMProtect/images/details.png diff --git a/VMProtect/images/details_checked.png b/VMProtect/images/details_checked.png Binary files differnew file mode 100644 index 0000000..d250789 --- /dev/null +++ b/VMProtect/images/details_checked.png diff --git a/VMProtect/images/details_hover.png b/VMProtect/images/details_hover.png Binary files differnew file mode 100644 index 0000000..b49afe3 --- /dev/null +++ b/VMProtect/images/details_hover.png diff --git a/VMProtect/images/disabled.png b/VMProtect/images/disabled.png Binary files differnew file mode 100644 index 0000000..3b1dc3c --- /dev/null +++ b/VMProtect/images/disabled.png diff --git a/VMProtect/images/disk.png b/VMProtect/images/disk.png Binary files differnew file mode 100644 index 0000000..b302afb --- /dev/null +++ b/VMProtect/images/disk.png diff --git a/VMProtect/images/disk_disabled.png b/VMProtect/images/disk_disabled.png Binary files differnew file mode 100644 index 0000000..b3d9b21 --- /dev/null +++ b/VMProtect/images/disk_disabled.png diff --git a/VMProtect/images/disk_hover.png b/VMProtect/images/disk_hover.png Binary files differnew file mode 100644 index 0000000..9dc5260 --- /dev/null +++ b/VMProtect/images/disk_hover.png diff --git a/VMProtect/images/down_arrow.png b/VMProtect/images/down_arrow.png Binary files differnew file mode 100644 index 0000000..3ea6d05 --- /dev/null +++ b/VMProtect/images/down_arrow.png diff --git a/VMProtect/images/down_arrow_checked.png b/VMProtect/images/down_arrow_checked.png Binary files differnew file mode 100644 index 0000000..be2a7b0 --- /dev/null +++ b/VMProtect/images/down_arrow_checked.png diff --git a/VMProtect/images/down_arrow_disabled.png b/VMProtect/images/down_arrow_disabled.png Binary files differnew file mode 100644 index 0000000..358672c --- /dev/null +++ b/VMProtect/images/down_arrow_disabled.png diff --git a/VMProtect/images/down_arrow_hover.png b/VMProtect/images/down_arrow_hover.png Binary files differnew file mode 100644 index 0000000..f8a940a --- /dev/null +++ b/VMProtect/images/down_arrow_hover.png diff --git a/VMProtect/images/dump.png b/VMProtect/images/dump.png Binary files differnew file mode 100644 index 0000000..5ab876b --- /dev/null +++ b/VMProtect/images/dump.png diff --git a/VMProtect/images/error.png b/VMProtect/images/error.png Binary files differnew file mode 100644 index 0000000..e6fd672 --- /dev/null +++ b/VMProtect/images/error.png diff --git a/VMProtect/images/execute.png b/VMProtect/images/execute.png Binary files differnew file mode 100644 index 0000000..55fcbfc --- /dev/null +++ b/VMProtect/images/execute.png diff --git a/VMProtect/images/execute_disabled.png b/VMProtect/images/execute_disabled.png Binary files differnew file mode 100644 index 0000000..46d34fd --- /dev/null +++ b/VMProtect/images/execute_disabled.png diff --git a/VMProtect/images/execute_hover.png b/VMProtect/images/execute_hover.png Binary files differnew file mode 100644 index 0000000..45a9534 --- /dev/null +++ b/VMProtect/images/execute_hover.png diff --git a/VMProtect/images/export.png b/VMProtect/images/export.png Binary files differnew file mode 100644 index 0000000..7a5db0d --- /dev/null +++ b/VMProtect/images/export.png diff --git a/VMProtect/images/file_open.png b/VMProtect/images/file_open.png Binary files differnew file mode 100644 index 0000000..762dd1b --- /dev/null +++ b/VMProtect/images/file_open.png diff --git a/VMProtect/images/file_open_hover.png b/VMProtect/images/file_open_hover.png Binary files differnew file mode 100644 index 0000000..71f4951 --- /dev/null +++ b/VMProtect/images/file_open_hover.png diff --git a/VMProtect/images/folder.png b/VMProtect/images/folder.png Binary files differnew file mode 100644 index 0000000..617e91d --- /dev/null +++ b/VMProtect/images/folder.png diff --git a/VMProtect/images/folder_close.png b/VMProtect/images/folder_close.png Binary files differnew file mode 100644 index 0000000..3a64725 --- /dev/null +++ b/VMProtect/images/folder_close.png diff --git a/VMProtect/images/forward.png b/VMProtect/images/forward.png Binary files differnew file mode 100644 index 0000000..179a3ba --- /dev/null +++ b/VMProtect/images/forward.png diff --git a/VMProtect/images/forward_disabled.png b/VMProtect/images/forward_disabled.png Binary files differnew file mode 100644 index 0000000..9ee92bb --- /dev/null +++ b/VMProtect/images/forward_disabled.png diff --git a/VMProtect/images/forward_hover.png b/VMProtect/images/forward_hover.png Binary files differnew file mode 100644 index 0000000..32dfd7c --- /dev/null +++ b/VMProtect/images/forward_hover.png diff --git a/VMProtect/images/functions.png b/VMProtect/images/functions.png Binary files differnew file mode 100644 index 0000000..3efb851 --- /dev/null +++ b/VMProtect/images/functions.png diff --git a/VMProtect/images/functions_checked.png b/VMProtect/images/functions_checked.png Binary files differnew file mode 100644 index 0000000..7895889 --- /dev/null +++ b/VMProtect/images/functions_checked.png diff --git a/VMProtect/images/functions_hover.png b/VMProtect/images/functions_hover.png Binary files differnew file mode 100644 index 0000000..99d3d35 --- /dev/null +++ b/VMProtect/images/functions_hover.png diff --git a/VMProtect/images/gear.png b/VMProtect/images/gear.png Binary files differnew file mode 100644 index 0000000..d959307 --- /dev/null +++ b/VMProtect/images/gear.png diff --git a/VMProtect/images/goto.png b/VMProtect/images/goto.png Binary files differnew file mode 100644 index 0000000..6140bb6 --- /dev/null +++ b/VMProtect/images/goto.png diff --git a/VMProtect/images/goto_disabled.png b/VMProtect/images/goto_disabled.png Binary files differnew file mode 100644 index 0000000..849c497 --- /dev/null +++ b/VMProtect/images/goto_disabled.png diff --git a/VMProtect/images/goto_hover.png b/VMProtect/images/goto_hover.png Binary files differnew file mode 100644 index 0000000..3e54db1 --- /dev/null +++ b/VMProtect/images/goto_hover.png diff --git a/VMProtect/images/help_gray.png b/VMProtect/images/help_gray.png Binary files differnew file mode 100644 index 0000000..1b71099 --- /dev/null +++ b/VMProtect/images/help_gray.png diff --git a/VMProtect/images/help_icon.png b/VMProtect/images/help_icon.png Binary files differnew file mode 100644 index 0000000..33e0585 --- /dev/null +++ b/VMProtect/images/help_icon.png diff --git a/VMProtect/images/import.png b/VMProtect/images/import.png Binary files differnew file mode 100644 index 0000000..2dcfe62 --- /dev/null +++ b/VMProtect/images/import.png diff --git a/VMProtect/images/information.png b/VMProtect/images/information.png Binary files differnew file mode 100644 index 0000000..85c1876 --- /dev/null +++ b/VMProtect/images/information.png diff --git a/VMProtect/images/item.png b/VMProtect/images/item.png Binary files differnew file mode 100644 index 0000000..7a21c09 --- /dev/null +++ b/VMProtect/images/item.png diff --git a/VMProtect/images/item_code.png b/VMProtect/images/item_code.png Binary files differnew file mode 100644 index 0000000..1fd1314 --- /dev/null +++ b/VMProtect/images/item_code.png diff --git a/VMProtect/images/item_export.png b/VMProtect/images/item_export.png Binary files differnew file mode 100644 index 0000000..0d9ab62 --- /dev/null +++ b/VMProtect/images/item_export.png diff --git a/VMProtect/images/item_file.png b/VMProtect/images/item_file.png Binary files differnew file mode 100644 index 0000000..63e671b --- /dev/null +++ b/VMProtect/images/item_file.png diff --git a/VMProtect/images/item_import.png b/VMProtect/images/item_import.png Binary files differnew file mode 100644 index 0000000..b57ca83 --- /dev/null +++ b/VMProtect/images/item_import.png diff --git a/VMProtect/images/item_key.png b/VMProtect/images/item_key.png Binary files differnew file mode 100644 index 0000000..844e650 --- /dev/null +++ b/VMProtect/images/item_key.png diff --git a/VMProtect/images/item_load_command.png b/VMProtect/images/item_load_command.png Binary files differnew file mode 100644 index 0000000..f7fb027 --- /dev/null +++ b/VMProtect/images/item_load_command.png diff --git a/VMProtect/images/item_m.png b/VMProtect/images/item_m.png Binary files differnew file mode 100644 index 0000000..5e8ecf4 --- /dev/null +++ b/VMProtect/images/item_m.png diff --git a/VMProtect/images/item_property.png b/VMProtect/images/item_property.png Binary files differnew file mode 100644 index 0000000..918e0c2 --- /dev/null +++ b/VMProtect/images/item_property.png diff --git a/VMProtect/images/item_resource.png b/VMProtect/images/item_resource.png Binary files differnew file mode 100644 index 0000000..db8de46 --- /dev/null +++ b/VMProtect/images/item_resource.png diff --git a/VMProtect/images/item_u.png b/VMProtect/images/item_u.png Binary files differnew file mode 100644 index 0000000..f6752fa --- /dev/null +++ b/VMProtect/images/item_u.png diff --git a/VMProtect/images/item_v.png b/VMProtect/images/item_v.png Binary files differnew file mode 100644 index 0000000..c32eb80 --- /dev/null +++ b/VMProtect/images/item_v.png diff --git a/VMProtect/images/key.png b/VMProtect/images/key.png Binary files differnew file mode 100644 index 0000000..3f9abc3 --- /dev/null +++ b/VMProtect/images/key.png diff --git a/VMProtect/images/key_gray.png b/VMProtect/images/key_gray.png Binary files differnew file mode 100644 index 0000000..f005fd3 --- /dev/null +++ b/VMProtect/images/key_gray.png diff --git a/VMProtect/images/lightning.png b/VMProtect/images/lightning.png Binary files differnew file mode 100644 index 0000000..7e0381b --- /dev/null +++ b/VMProtect/images/lightning.png diff --git a/VMProtect/images/link.png b/VMProtect/images/link.png Binary files differnew file mode 100644 index 0000000..afb074b --- /dev/null +++ b/VMProtect/images/link.png diff --git a/VMProtect/images/logo.png b/VMProtect/images/logo.png Binary files differnew file mode 100644 index 0000000..6c10e19 --- /dev/null +++ b/VMProtect/images/logo.png diff --git a/VMProtect/images/menu_arrow.png b/VMProtect/images/menu_arrow.png Binary files differnew file mode 100644 index 0000000..7c4cf2d --- /dev/null +++ b/VMProtect/images/menu_arrow.png diff --git a/VMProtect/images/menu_arrow_disabled.png b/VMProtect/images/menu_arrow_disabled.png Binary files differnew file mode 100644 index 0000000..d560755 --- /dev/null +++ b/VMProtect/images/menu_arrow_disabled.png diff --git a/VMProtect/images/menu_arrow_hover.png b/VMProtect/images/menu_arrow_hover.png Binary files differnew file mode 100644 index 0000000..3b5203a --- /dev/null +++ b/VMProtect/images/menu_arrow_hover.png diff --git a/VMProtect/images/next.png b/VMProtect/images/next.png Binary files differnew file mode 100644 index 0000000..b752694 --- /dev/null +++ b/VMProtect/images/next.png diff --git a/VMProtect/images/open.png b/VMProtect/images/open.png Binary files differnew file mode 100644 index 0000000..18096b6 --- /dev/null +++ b/VMProtect/images/open.png diff --git a/VMProtect/images/open_disabled.png b/VMProtect/images/open_disabled.png Binary files differnew file mode 100644 index 0000000..ac4b1e4 --- /dev/null +++ b/VMProtect/images/open_disabled.png diff --git a/VMProtect/images/open_hover.png b/VMProtect/images/open_hover.png Binary files differnew file mode 100644 index 0000000..f05953d --- /dev/null +++ b/VMProtect/images/open_hover.png diff --git a/VMProtect/images/paste.png b/VMProtect/images/paste.png Binary files differnew file mode 100644 index 0000000..98b12b0 --- /dev/null +++ b/VMProtect/images/paste.png diff --git a/VMProtect/images/paste_disabled.png b/VMProtect/images/paste_disabled.png Binary files differnew file mode 100644 index 0000000..ea102b1 --- /dev/null +++ b/VMProtect/images/paste_disabled.png diff --git a/VMProtect/images/paste_hover.png b/VMProtect/images/paste_hover.png Binary files differnew file mode 100644 index 0000000..92dcac0 --- /dev/null +++ b/VMProtect/images/paste_hover.png diff --git a/VMProtect/images/previous.png b/VMProtect/images/previous.png Binary files differnew file mode 100644 index 0000000..44a68a3 --- /dev/null +++ b/VMProtect/images/previous.png diff --git a/VMProtect/images/processor.png b/VMProtect/images/processor.png Binary files differnew file mode 100644 index 0000000..b036cf9 --- /dev/null +++ b/VMProtect/images/processor.png diff --git a/VMProtect/images/project.png b/VMProtect/images/project.png Binary files differnew file mode 100644 index 0000000..c16ab8b --- /dev/null +++ b/VMProtect/images/project.png diff --git a/VMProtect/images/project_checked.png b/VMProtect/images/project_checked.png Binary files differnew file mode 100644 index 0000000..4fa43fb --- /dev/null +++ b/VMProtect/images/project_checked.png diff --git a/VMProtect/images/project_hover.png b/VMProtect/images/project_hover.png Binary files differnew file mode 100644 index 0000000..4767d02 --- /dev/null +++ b/VMProtect/images/project_hover.png diff --git a/VMProtect/images/radiobutton.png b/VMProtect/images/radiobutton.png Binary files differnew file mode 100644 index 0000000..cde4d31 --- /dev/null +++ b/VMProtect/images/radiobutton.png diff --git a/VMProtect/images/radiobutton_checked.png b/VMProtect/images/radiobutton_checked.png Binary files differnew file mode 100644 index 0000000..8d56e50 --- /dev/null +++ b/VMProtect/images/radiobutton_checked.png diff --git a/VMProtect/images/reference.png b/VMProtect/images/reference.png Binary files differnew file mode 100644 index 0000000..1d1884e --- /dev/null +++ b/VMProtect/images/reference.png diff --git a/VMProtect/images/script.png b/VMProtect/images/script.png Binary files differnew file mode 100644 index 0000000..5bba9d3 --- /dev/null +++ b/VMProtect/images/script.png diff --git a/VMProtect/images/scroll_down.png b/VMProtect/images/scroll_down.png Binary files differnew file mode 100644 index 0000000..09dd30b --- /dev/null +++ b/VMProtect/images/scroll_down.png diff --git a/VMProtect/images/scroll_down_hover.png b/VMProtect/images/scroll_down_hover.png Binary files differnew file mode 100644 index 0000000..7706a6b --- /dev/null +++ b/VMProtect/images/scroll_down_hover.png diff --git a/VMProtect/images/scroll_left.png b/VMProtect/images/scroll_left.png Binary files differnew file mode 100644 index 0000000..b4e1a90 --- /dev/null +++ b/VMProtect/images/scroll_left.png diff --git a/VMProtect/images/scroll_left_hover.png b/VMProtect/images/scroll_left_hover.png Binary files differnew file mode 100644 index 0000000..87b1634 --- /dev/null +++ b/VMProtect/images/scroll_left_hover.png diff --git a/VMProtect/images/scroll_right.png b/VMProtect/images/scroll_right.png Binary files differnew file mode 100644 index 0000000..c558ef8 --- /dev/null +++ b/VMProtect/images/scroll_right.png diff --git a/VMProtect/images/scroll_right_hover.png b/VMProtect/images/scroll_right_hover.png Binary files differnew file mode 100644 index 0000000..9f6edd7 --- /dev/null +++ b/VMProtect/images/scroll_right_hover.png diff --git a/VMProtect/images/scroll_up.png b/VMProtect/images/scroll_up.png Binary files differnew file mode 100644 index 0000000..48fdd5d --- /dev/null +++ b/VMProtect/images/scroll_up.png diff --git a/VMProtect/images/scroll_up_hover.png b/VMProtect/images/scroll_up_hover.png Binary files differnew file mode 100644 index 0000000..ad88fe7 --- /dev/null +++ b/VMProtect/images/scroll_up_hover.png diff --git a/VMProtect/images/search.png b/VMProtect/images/search.png Binary files differnew file mode 100644 index 0000000..de199dd --- /dev/null +++ b/VMProtect/images/search.png diff --git a/VMProtect/images/search_gray.png b/VMProtect/images/search_gray.png Binary files differnew file mode 100644 index 0000000..9b663f6 --- /dev/null +++ b/VMProtect/images/search_gray.png diff --git a/VMProtect/images/star.png b/VMProtect/images/star.png Binary files differnew file mode 100644 index 0000000..d7717cd --- /dev/null +++ b/VMProtect/images/star.png diff --git a/VMProtect/images/star_gray.png b/VMProtect/images/star_gray.png Binary files differnew file mode 100644 index 0000000..dca3713 --- /dev/null +++ b/VMProtect/images/star_gray.png diff --git a/VMProtect/images/tool.png b/VMProtect/images/tool.png Binary files differnew file mode 100644 index 0000000..35e268b --- /dev/null +++ b/VMProtect/images/tool.png diff --git a/VMProtect/images/up_arrow.png b/VMProtect/images/up_arrow.png Binary files differnew file mode 100644 index 0000000..4318e98 --- /dev/null +++ b/VMProtect/images/up_arrow.png diff --git a/VMProtect/images/up_arrow_disabled.png b/VMProtect/images/up_arrow_disabled.png Binary files differnew file mode 100644 index 0000000..a483121 --- /dev/null +++ b/VMProtect/images/up_arrow_disabled.png diff --git a/VMProtect/images/up_down.png b/VMProtect/images/up_down.png Binary files differnew file mode 100644 index 0000000..d157d36 --- /dev/null +++ b/VMProtect/images/up_down.png diff --git a/VMProtect/images/up_down_checked.png b/VMProtect/images/up_down_checked.png Binary files differnew file mode 100644 index 0000000..b4396e9 --- /dev/null +++ b/VMProtect/images/up_down_checked.png diff --git a/VMProtect/images/up_down_disabled.png b/VMProtect/images/up_down_disabled.png Binary files differnew file mode 100644 index 0000000..2b4b2d7 --- /dev/null +++ b/VMProtect/images/up_down_disabled.png diff --git a/VMProtect/images/up_down_hover.png b/VMProtect/images/up_down_hover.png Binary files differnew file mode 100644 index 0000000..60cb6c9 --- /dev/null +++ b/VMProtect/images/up_down_hover.png diff --git a/VMProtect/images/warning.png b/VMProtect/images/warning.png Binary files differnew file mode 100644 index 0000000..cb17d2e --- /dev/null +++ b/VMProtect/images/warning.png diff --git a/VMProtect/import_license_dialog.cc b/VMProtect/import_license_dialog.cc new file mode 100644 index 0000000..cf38c02 --- /dev/null +++ b/VMProtect/import_license_dialog.cc @@ -0,0 +1,79 @@ +#include "../core/objects.h" +#include "../core/lang.h" +#include "import_license_dialog.h" +#include "widgets.h" +#include "moc/moc_import_license_dialog.cc" +#include "help_browser.h" + +/** + * ImportLicenseDialog + */ + +ImportLicenseDialog::ImportLicenseDialog(QWidget *parent) + : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint) +{ + setWindowTitle(QString::fromUtf8(language[lsImportLicense].c_str())); + + QLabel *serialLabel = new QLabel(this); + serialLabel->setObjectName("header"); + serialLabel->setText(QString::fromUtf8(language[lsPasteSerialNumber].c_str())); + serialEdit_ = new QPlainTextEdit(this); + QFont font = serialEdit_->font(); + font.setFamily(MONOSPACE_FONT_FAMILY); + serialEdit_->setFont(font); + + QToolButton *helpButton = new QToolButton(this); + helpButton->setShortcut(HelpContentsKeySequence()); + helpButton->setIconSize(QSize(20, 20)); + helpButton->setIcon(QIcon(":/images/help_gray.png")); + helpButton->setToolTip(QString::fromUtf8(language[lsHelp].c_str())); + connect(helpButton, SIGNAL(clicked(bool)), this, SLOT(helpClicked())); + + okButton_ = new PushButton(QString::fromUtf8(language[lsOK].c_str())); + okButton_->setEnabled(false); + QPushButton *cancelButton = new PushButton(QString::fromUtf8(language[lsCancel].c_str())); + QHBoxLayout *buttonLayout = new QHBoxLayout(); + buttonLayout->setContentsMargins(0, 0, 0, 0); + buttonLayout->setSpacing(10); + buttonLayout->addWidget(helpButton); + buttonLayout->addStretch(); + +#ifdef __APPLE__ + buttonLayout->addWidget(cancelButton); + buttonLayout->addWidget(okButton_); +#else + buttonLayout->addWidget(okButton_); + buttonLayout->addWidget(cancelButton); +#endif + + QVBoxLayout *layout = new QVBoxLayout(); + layout->setContentsMargins(10, 10, 10, 10); + layout->setSpacing(10); + layout->addWidget(serialLabel); + layout->addWidget(serialEdit_); + layout->addLayout(buttonLayout); + setLayout(layout); + + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + connect(okButton_, SIGNAL(clicked()), this, SLOT(accept())); + connect(serialEdit_, SIGNAL(textChanged()), this, SLOT(serialChanged())); + + resize(580, 250); +} + +void ImportLicenseDialog::serialChanged() +{ + okButton_->setEnabled(!serial().isEmpty()); +} + +void ImportLicenseDialog::helpClicked() +{ + HelpBrowser::showTopic("project::licenses"); +} + +QString ImportLicenseDialog::serial() const +{ + QString str = serialEdit_->toPlainText().simplified(); + str.replace(" ", ""); + return str; +} diff --git a/VMProtect/import_license_dialog.h b/VMProtect/import_license_dialog.h new file mode 100644 index 0000000..95512cc --- /dev/null +++ b/VMProtect/import_license_dialog.h @@ -0,0 +1,18 @@ +#ifndef IMPORT_LICENSE_DIALOG_H +#define IMPORT_LICENSE_DIALOG_H + +class ImportLicenseDialog : public QDialog +{ + Q_OBJECT +public: + ImportLicenseDialog(QWidget *parent = NULL); + QString serial() const; +private slots: + void serialChanged(); + void helpClicked(); +private: + QPlainTextEdit *serialEdit_; + QPushButton *okButton_; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/license_dialog.cc b/VMProtect/license_dialog.cc new file mode 100644 index 0000000..755076f --- /dev/null +++ b/VMProtect/license_dialog.cc @@ -0,0 +1,369 @@ +#ifdef ULTIMATE +#include "../core/objects.h" +#include "../core/core.h" +#include "../core/lang.h" +#include "widgets.h" +#include "license_dialog.h" +#include "moc/moc_license_dialog.cc" +#include "message_dialog.h" +#include "wait_cursor.h" +#include "help_browser.h" +#include "application.h" + +/** + * LicenseDialog + */ + +LicenseDialog::LicenseDialog(LicensingManager *manager, License *license, QWidget *parent) + : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint | Qt::MSWindowsFixedSizeDialogHint), manager_(manager), license_(license) +{ + setWindowTitle(QString::fromUtf8(language[lsAddLicense].c_str())); + + QFont font; + font.setBold(true); + + QLabel *details = new QLabel(QString::fromUtf8(language[lsDetails].c_str()), this); + details->setObjectName("header"); + QFrame *groupDetails = new QFrame(this); + groupDetails->setObjectName("gridEditor"); + groupDetails->setFrameShape(QFrame::StyledPanel); + + QGridLayout *layout = new QGridLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setHorizontalSpacing(0); + layout->setVerticalSpacing(1); + layout->setColumnMinimumWidth(0, 180 * Application::stylesheetScaleFactor()); + layout->setColumnStretch(1, 1); + + QLabel *nameLabel = new QLabel(QString::fromUtf8(language[lsCustomerName].c_str()), this); + nameLabel->setObjectName("editor"); + nameEdit_ = new LineEdit(this); + nameEdit_->setFrame(false); + nameEdit_->setFont(font); + + QLabel *emailLabel = new QLabel(QString::fromUtf8(language[lsEmail].c_str()), this); + emailLabel->setObjectName("editor"); + emailEdit_ = new LineEdit(this); + emailEdit_->setFrame(false); + emailEdit_->setFont(font); + + QLabel *dateLabel = new QLabel(QString::fromUtf8(language[lsDate].c_str()), this); + dateLabel->setObjectName("editor"); + dateEdit_ = new QDateEdit(this); + dateEdit_->setFrame(false); + dateEdit_->setDate(QDate::currentDate()); + dateEdit_->setFont(font); + + QLabel *orderLabel = new QLabel(QString::fromUtf8(language[lsOrderRef].c_str()), this); + orderLabel->setObjectName("editor"); + orderEdit_ = new LineEdit(this); + orderEdit_->setFrame(false); + orderEdit_->setFont(font); + + QLabel *commentsLabel = new QLabel(QString::fromUtf8(language[lsComments].c_str()), this); + commentsLabel->setAlignment(Qt::AlignTop); + commentsLabel->setObjectName("editor"); + commentsEdit_ = new QPlainTextEdit(this); + commentsEdit_->setFrameShape(QFrame::NoFrame); + commentsEdit_->setMaximumHeight(40 * Application::stylesheetScaleFactor()); + commentsEdit_->setFont(font); + commentsEdit_->setTabChangesFocus(true); + + layout->addWidget(nameLabel, 0, 0); + layout->addWidget(nameEdit_, 0, 1); + layout->addWidget(emailLabel, 1, 0); + layout->addWidget(emailEdit_, 1, 1); + layout->addWidget(dateLabel, 2, 0); + layout->addWidget(dateEdit_, 2, 1); + layout->addWidget(orderLabel, 3, 0); + layout->addWidget(orderEdit_, 3, 1); + layout->addWidget(commentsLabel, 4, 0); + layout->addWidget(commentsEdit_, 4, 1); + layout->setRowStretch(4, 1); + groupDetails->setLayout(layout); + + QLabel *serial = new QLabel(QString::fromUtf8(language[lsSerialNumberContents].c_str()), this); + serial->setObjectName("header"); + QFrame *groupSerial = new QFrame(this); + groupSerial->setObjectName("gridEditor"); + groupSerial->setFrameShape(QFrame::StyledPanel); + + serialNameCheckBox_ = new QCheckBox(QString::fromUtf8(language[lsCustomerName].c_str()), this); + serialNameCheckBox_->setObjectName("editor"); + serialNameEdit_ = new LineEdit(this); + serialNameEdit_->setFrame(false); + serialNameEdit_->setFont(font); + serialNameEdit_->setMaxLength(255); + + serialEmailCheckBox_ = new QCheckBox(QString::fromUtf8(language[lsEmail].c_str()), this); + serialEmailCheckBox_->setObjectName("editor"); + serialEmailEdit_ = new LineEdit(this); + serialEmailEdit_->setFrame(false); + serialEmailEdit_->setFont(font); + serialEmailEdit_->setMaxLength(255); + + serialHWIDCheckBox_ = new QCheckBox(QString::fromUtf8(language[lsHardwareID].c_str()), this); + serialHWIDCheckBox_->setObjectName("editor"); + serialHWIDEdit_ = new LineEdit(this); + serialHWIDEdit_->setFrame(false); + serialHWIDEdit_->setFont(font); + + serialExpirationDateCheckBox_ = new QCheckBox(QString::fromUtf8(language[lsExpirationDate].c_str()), this); + serialExpirationDateCheckBox_->setObjectName("editor"); + serialExpirationDateEdit_ = new QDateEdit(this); + serialExpirationDateEdit_->setFrame(false); + serialExpirationDateEdit_->setDate(QDate::currentDate().addMonths(1)); + serialExpirationDateEdit_->setFont(font); + + serialTimeLimitCheckBox_ = new QCheckBox(QString::fromUtf8(language[lsRunningTimeLimit].c_str()), this); + serialTimeLimitCheckBox_->setObjectName("editor"); + serialTimeLimitEdit_ = new QSpinBox(this); + serialTimeLimitEdit_->setFrame(false); + serialTimeLimitEdit_->setRange(0, 255); + serialTimeLimitEdit_->setValue(30); + serialTimeLimitEdit_->setFont(font); + + serialMaxBuildDateCheckBox_ = new QCheckBox(QString::fromUtf8(language[lsMaxBuildDate].c_str()), this); + serialMaxBuildDateCheckBox_->setObjectName("editor"); + serialMaxBuildDateEdit_ = new QDateEdit(this); + serialMaxBuildDateEdit_->setFrame(false); + serialMaxBuildDateEdit_->setDate(QDate::currentDate().addYears(1)); + serialMaxBuildDateEdit_->setFont(font); + + QFrame *serialUserDataFrame = new QFrame(this); + serialUserDataFrame->setObjectName("editor"); + serialUserDataCheckBox_ = new QCheckBox(QString::fromUtf8(language[lsUserData].c_str()), serialUserDataFrame); + serialUserDataCheckBox_->setObjectName("editor"); + serialUserDataEdit_ = new BinEditor(this); + serialUserDataEdit_->setFrameShape(QFrame::NoFrame); + serialUserDataEdit_->setOverwriteMode(false); + serialUserDataEdit_->setMaxLength(255); + serialUserDataEdit_->setMaximumHeight(40 * Application::stylesheetScaleFactor()); + font = serialUserDataEdit_->font(); + font.setBold(true); + serialUserDataEdit_->setFont(font); + + layout = new QGridLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setHorizontalSpacing(0); + layout->setVerticalSpacing(1); + layout->setColumnMinimumWidth(0, 180 * Application::stylesheetScaleFactor()); + layout->setColumnStretch(1, 1); + layout->addWidget(serialNameCheckBox_, 0, 0); + layout->addWidget(serialNameEdit_, 0, 1); + layout->addWidget(serialEmailCheckBox_, 1, 0); + layout->addWidget(serialEmailEdit_, 1, 1); + layout->addWidget(serialHWIDCheckBox_, 2, 0); + layout->addWidget(serialHWIDEdit_, 2, 1); + layout->addWidget(serialExpirationDateCheckBox_, 3, 0); + layout->addWidget(serialExpirationDateEdit_, 3, 1); + layout->addWidget(serialTimeLimitCheckBox_, 4, 0); + layout->addWidget(serialTimeLimitEdit_, 4, 1); + layout->addWidget(serialMaxBuildDateCheckBox_, 5, 0); + layout->addWidget(serialMaxBuildDateEdit_, 5, 1); + layout->addWidget(serialUserDataFrame, 6, 0); + layout->addWidget(serialUserDataEdit_, 6, 1); + + groupSerial->setLayout(layout); + + QToolButton *helpButton = new QToolButton(this); + helpButton->setShortcut(HelpContentsKeySequence()); + helpButton->setIconSize(QSize(20, 20)); + helpButton->setIcon(QIcon(":/images/help_gray.png")); + helpButton->setToolTip(QString::fromUtf8(language[lsHelp].c_str())); + connect(helpButton, SIGNAL(clicked(bool)), this, SLOT(helpClicked())); + + QPushButton *okButton = new PushButton(QString::fromUtf8(language[lsAddLicense].c_str()), this); + QPushButton *cancelButton = new PushButton(QString::fromUtf8(language[lsCancel].c_str()), this); + QHBoxLayout *buttonLayout = new QHBoxLayout(); + buttonLayout->setContentsMargins(0, 0, 0, 0); + buttonLayout->setSpacing(10); + buttonLayout->addWidget(helpButton); + buttonLayout->addStretch(); +#ifdef __APPLE__ + buttonLayout->addWidget(cancelButton); + buttonLayout->addWidget(okButton); +#else + buttonLayout->addWidget(okButton); + buttonLayout->addWidget(cancelButton); +#endif + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->setContentsMargins(10, 10, 10, 10); + mainLayout->setSpacing(10); + mainLayout->addWidget(details); + mainLayout->addWidget(groupDetails); + mainLayout->addStretch(1); + mainLayout->addWidget(serial); + mainLayout->addWidget(groupSerial); + mainLayout->addLayout(buttonLayout); + + if (license) { + nameEdit_->setText(QString::fromUtf8(license->customer_name().c_str())); + emailEdit_->setText(QString::fromUtf8(license->customer_email().c_str())); + LicenseDate date = license->date(); + dateEdit_->setDate(QDate(date.Year, date.Month, date.Day)); + orderEdit_->setText(QString::fromUtf8(license->order_ref().c_str())); + commentsEdit_->setPlainText(QString::fromUtf8(license->comments().c_str())); + + LicenseInfo *license_info = license_->info(); + if (license_info) { + if (license_info->Flags & HAS_USER_NAME) { + serialNameCheckBox_->setChecked(true); + serialNameEdit_->setText(QString::fromUtf8(license_info->CustomerName.c_str())); + } + if (license_info->Flags & HAS_EMAIL) { + serialEmailCheckBox_->setChecked(true); + serialEmailEdit_->setText(QString::fromUtf8(license_info->CustomerEmail.c_str())); + } + if (license_info->Flags & HAS_HARDWARE_ID) { + serialHWIDCheckBox_->setChecked(true); + serialHWIDEdit_->setText(QString::fromLatin1(license_info->HWID.c_str())); + } + if (license_info->Flags & HAS_TIME_LIMIT) { + serialTimeLimitCheckBox_->setChecked(true); + serialTimeLimitEdit_->setValue(license_info->RunningTimeLimit); + } + if (license_info->Flags & HAS_EXP_DATE) { + serialExpirationDateCheckBox_->setChecked(true); + serialExpirationDateEdit_->setDate(QDate(license_info->ExpireDate.Year, license_info->ExpireDate.Month, license_info->ExpireDate.Day)); + } + if (license_info->Flags & HAS_MAX_BUILD_DATE) { + serialMaxBuildDateCheckBox_->setChecked(true); + serialMaxBuildDateEdit_->setDate(QDate(license_info->MaxBuildDate.Year, license_info->MaxBuildDate.Month, license_info->MaxBuildDate.Day)); + } + if (license_info->Flags & HAS_USER_DATA) { + serialUserDataCheckBox_->setChecked(true); + serialUserDataEdit_->setData(QByteArray(license_info->UserData.c_str(), (int)license_info->UserData.size())); + } + } + } + + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + connect(okButton, SIGNAL(clicked()), this, SLOT(okButtonClicked())); + connect(nameEdit_, SIGNAL(textChanged(const QString &)), this, SLOT(nameChanged())); + connect(emailEdit_, SIGNAL(textChanged(const QString &)), this, SLOT(emailChanged())); + connect(serialNameEdit_, SIGNAL(textChanged(const QString &)), this, SLOT(serialNameChanged())); + connect(serialEmailEdit_, SIGNAL(textChanged(const QString &)), this, SLOT(serialEmailChanged())); + connect(serialHWIDEdit_, SIGNAL(textChanged(const QString &)), this, SLOT(HWIDChanged())); + connect(serialExpirationDateEdit_, SIGNAL(dateChanged(const QDate &)), this, SLOT(expirationDateChanged())); + connect(serialTimeLimitEdit_, SIGNAL(valueChanged(int)), this, SLOT(timeLimitChanged())); + connect(serialMaxBuildDateEdit_, SIGNAL(dateChanged(const QDate &)), this, SLOT(maxBuildDateChanged())); + connect(serialUserDataEdit_, SIGNAL(dataChanged()), this, SLOT(userDataChanged())); + + setLayout(mainLayout); + setMinimumSize(450 * Application::stylesheetScaleFactor(), 300 * Application::stylesheetScaleFactor()); +} + +void LicenseDialog::nameChanged() +{ + serialNameEdit_->setText(nameEdit_->text()); +} + +void LicenseDialog::emailChanged() +{ + serialEmailEdit_->setText(emailEdit_->text()); +} + +void LicenseDialog::serialNameChanged() +{ + serialNameCheckBox_->setChecked(!serialNameEdit_->text().isEmpty()); +} + +void LicenseDialog::serialEmailChanged() +{ + serialEmailCheckBox_->setChecked(!serialEmailEdit_->text().isEmpty()); +} + +void LicenseDialog::HWIDChanged() +{ + serialHWIDCheckBox_->setChecked(!serialHWIDEdit_->text().isEmpty()); +} + +void LicenseDialog::expirationDateChanged() +{ + serialExpirationDateCheckBox_->setChecked(true); +} + +void LicenseDialog::timeLimitChanged() +{ + serialTimeLimitCheckBox_->setChecked(true); +} + +void LicenseDialog::maxBuildDateChanged() +{ + serialMaxBuildDateCheckBox_->setChecked(true); +} + +void LicenseDialog::userDataChanged() +{ + serialUserDataCheckBox_->setChecked(serialUserDataEdit_->data().size()); +} + +void LicenseDialog::okButtonClicked() +{ + LicenseInfo licenseInfo; + + if (serialNameCheckBox_->checkState() == Qt::Checked) { + licenseInfo.Flags |= HAS_USER_NAME; + licenseInfo.CustomerName = serialNameEdit_->text().toUtf8().constData(); + } + + if (serialEmailCheckBox_->checkState() == Qt::Checked) { + licenseInfo.Flags |= HAS_EMAIL; + licenseInfo.CustomerEmail = serialEmailEdit_->text().toUtf8().constData(); + } + + if (serialHWIDCheckBox_->checkState() == Qt::Checked) { + licenseInfo.Flags |= HAS_HARDWARE_ID; + licenseInfo.HWID = serialHWIDEdit_->text().toUtf8().constData(); + } + + if (serialExpirationDateCheckBox_->checkState() == Qt::Checked) { + licenseInfo.Flags |= HAS_EXP_DATE; + QDate date = serialExpirationDateEdit_->date(); + licenseInfo.ExpireDate = LicenseDate(date.year(), date.month(), date.day()); + } + + if (serialTimeLimitCheckBox_->checkState() == Qt::Checked) { + licenseInfo.Flags |= HAS_TIME_LIMIT; + licenseInfo.RunningTimeLimit = (uint8_t)serialTimeLimitEdit_->value(); + } + + if (serialMaxBuildDateCheckBox_->checkState() == Qt::Checked) { + licenseInfo.Flags |= HAS_MAX_BUILD_DATE; + QDate date = serialMaxBuildDateEdit_->date(); + licenseInfo.MaxBuildDate = LicenseDate(date.year(), date.month(), date.day()); + } + + if (serialUserDataCheckBox_->checkState() == Qt::Checked) { + licenseInfo.Flags |= HAS_USER_DATA; + QByteArray data = serialUserDataEdit_->data(); + licenseInfo.UserData = std::string(data.constData(), data.size()); + } + + try { + WaitCursor wc; + std::string serialNumber = manager_->GenerateSerialNumber(licenseInfo); + QDate date = dateEdit_->date(); + license_ = manager_->Add(LicenseDate(date.year(), date.month(), date.day()), + nameEdit_->text().toUtf8().constData(), + emailEdit_->text().toUtf8().constData(), + orderEdit_->text().toUtf8().constData(), + commentsEdit_->toPlainText().toUtf8().constData(), + serialNumber, + false); + } catch (const std::runtime_error &e) { + MessageDialog::critical(this, QString("%1:\n%2").arg(QString::fromUtf8(language[lsSerialNumberError].c_str())).arg(QString::fromUtf8(e.what())), QMessageBox::Ok); + return; + } + + accept(); +} + +void LicenseDialog::helpClicked() +{ + HelpBrowser::showTopic("project::licenses"); +} + +#endif
\ No newline at end of file diff --git a/VMProtect/license_dialog.h b/VMProtect/license_dialog.h new file mode 100644 index 0000000..743e13c --- /dev/null +++ b/VMProtect/license_dialog.h @@ -0,0 +1,48 @@ +#ifndef LICENSE_DIALOG_H +#define LICENSE_DIALOG_H + +class LicenseDialog : public QDialog +{ + Q_OBJECT +public: + LicenseDialog(LicensingManager *manager, License *license, QWidget *parent = NULL); + License *license() const { return license_; } +private slots: + void okButtonClicked(); + void nameChanged(); + void emailChanged(); + void serialNameChanged(); + void serialEmailChanged(); + void HWIDChanged(); + void expirationDateChanged(); + void timeLimitChanged(); + void maxBuildDateChanged(); + void userDataChanged(); + void helpClicked(); +private: + LicensingManager *manager_; + License *license_; + + QLineEdit *nameEdit_; + QLineEdit *emailEdit_; + QDateEdit *dateEdit_; + QLineEdit *orderEdit_; + QPlainTextEdit *commentsEdit_; + + QCheckBox *serialNameCheckBox_; + QLineEdit *serialNameEdit_; + QCheckBox *serialEmailCheckBox_; + QLineEdit *serialEmailEdit_; + QCheckBox *serialHWIDCheckBox_; + QLineEdit *serialHWIDEdit_; + QCheckBox *serialExpirationDateCheckBox_; + QDateEdit *serialExpirationDateEdit_; + QCheckBox *serialTimeLimitCheckBox_; + QSpinBox *serialTimeLimitEdit_; + QCheckBox *serialMaxBuildDateCheckBox_; + QDateEdit *serialMaxBuildDateEdit_; + QCheckBox *serialUserDataCheckBox_; + BinEditor *serialUserDataEdit_; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/lin_gui.mak b/VMProtect/lin_gui.mak new file mode 100644 index 0000000..1be6363 --- /dev/null +++ b/VMProtect/lin_gui.mak @@ -0,0 +1,57 @@ +SOURCES := about_dialog.cc export_key_pair_dialog.cc function_dialog.cc import_license_dialog.cc license_dialog.cc main.cc mainwindow.cc message_dialog.cc remotecontrol.cc template_save_dialog.cc templates_window.cc \ + models.cc progress_dialog.cc property_editor.cc resources.cc settings_dialog.cc watermark_dialog.cc watermarks_window.cc widgets.cc help_browser.cc \ + ../third-party/scintilla/ScintillaQt.cc ../third-party/scintilla/ScintillaEditBase.cc \ + ../third-party/scintilla/PlatQt.cc + +MOC_HEADERS := application.h mainwindow.h property_editor.h widgets.h models.h about_dialog.h watermark_dialog.h message_dialog.h settings_dialog.h watermarks_window.h remotecontrol.h \ + export_key_pair_dialog.h function_dialog.h import_license_dialog.h license_dialog.h progress_dialog.h help_browser.h template_save_dialog.h templates_window.h + +SC_MOC_HEADERS := ScintillaQt.h ScintillaEditBase.h + +PROJECT := vmprotect_gui +TARGET := $(PROJECT) +QT_DIR := /home/vano/Qt/5.6/gcc_$(ARCH_DIR) +BIN_DIR := ../bin/$(ARCH_DIR)/$(CFG_DIR) +APP_NAME := vmprotect_gui.unarc +APP_DIR := $(BIN_DIR)/$(APP_NAME) +SDK_DYLIB := libVMProtectSDK$(ARCH_DIR).so +TMP_ARCH_DIR := ../tmp/lin/gui/$(ARCH_DIR) +TMP_DIR := $(TMP_ARCH_DIR)/$(CFG_DIR)/$(PROJECT) +PCH_DIR := $(TMP_DIR)/$(PROJECT).gch +DEFINES := $(CONFIG) -DTIXML_USE_STL -DSCI_NAMESPACE +LFLAGS := -Wl,-rpath,\$$ORIGIN,-rpath-link,$(QT_DIR)/lib +LIBS := $(SDK_LIBS) -L$(QT_DIR)/lib -lQt5Gui -lQt5Core -lQt5Help -lQt5Widgets -Wl,--no-as-needed -L../bin -lVMProtectSDK$(ARCH_DIR) -ldl -Wl,--as-needed +OBJCOMP := ../bin/$(ARCH_DIR)/$(CFG_DIR)/core.a ../bin/$(ARCH_DIR)/invariant_core.a ../third-party/libffi/libffi$(ARCH_DIR).a /usr/lib/$(ARCH)/libcrypto.a +DYLIBS := +PCH_DIR := $(TMP_DIR) +MOC_TEMPLATE := moc/moc_ +SC_MOC_TEMPLATE := ../VMProtect/moc/moc_ +INCFLAGS := -I$(QT_DIR)/include/ + +include ../lin_common.mak + +OBJECTS := $(addprefix $(TMP_DIR)/, $(SOURCES:.cc=.o)) +MOC_RESULTS := $(addprefix $(MOC_TEMPLATE), $(MOC_HEADERS:.h=.cc)) +SC_MOC_RESULTS := $(addprefix $(SC_MOC_TEMPLATE), $(SC_MOC_HEADERS:.h=.cc)) + +clean: + -$(DEL_FILE) $(OBJECTS) + -$(DEL_FILE) $(PCH_CPP) + -$(DEL_FILE) $(BIN_TARGET) + -$(DEL_FILE) $(MOC_RESULTS) + -$(DEL_FILE) $(SC_MOC_RESULTS) + -$(DEL_DIR) $(APP_DIR) + +all:: $(BIN_TARGET) + +$(BIN_TARGET): moc/.sentinel $(MOC_RESULTS) $(SC_MOC_RESULTS) $(OBJECTS) $(BIN_DIR)/.sentinel $(OBJCOMP) + $(LINK) $(LFLAGS) -o $(BIN_TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP) + +$(TMP_DIR)/%.o: %.cc $(PCH_CPP) $(TMP_DIR)/%/../.sentinel + $(CXX) -c -include-pch $(PCH_CPP) $(CXXFLAGS) $(INCFLAGS) -o $(abspath $@) $(abspath $<) + +$(MOC_TEMPLATE)%.cc: %.h + moc -DSCI_NAMESPACE -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_HAVE_MMX -DQT_HAVE_3DNOW -DQT_HAVE_SSE -DQT_HAVE_MMXEXT -DQT_HAVE_SSE2 -DQT_THREAD_SUPPORT $(abspath $<) -o $(abspath $@) + +$(SC_MOC_TEMPLATE)%.cc: ../third-party/scintilla/%.h + moc -DSCI_NAMESPACE -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_HAVE_MMX -DQT_HAVE_3DNOW -DQT_HAVE_SSE -DQT_HAVE_MMXEXT -DQT_HAVE_SSE2 -DQT_THREAD_SUPPORT $(abspath $<) -o $(abspath $@) diff --git a/VMProtect/lin_gui32.mak b/VMProtect/lin_gui32.mak new file mode 100644 index 0000000..ca64dab --- /dev/null +++ b/VMProtect/lin_gui32.mak @@ -0,0 +1,3 @@ +ARCH := i386-linux-gnu +ARCH_DIR := 32 +include lin_gui.mak diff --git a/VMProtect/lin_gui64.mak b/VMProtect/lin_gui64.mak new file mode 100644 index 0000000..98a8c0b --- /dev/null +++ b/VMProtect/lin_gui64.mak @@ -0,0 +1,3 @@ +ARCH := x86_64-linux-gnu +ARCH_DIR := 64 +include lin_gui.mak diff --git a/VMProtect/mac_gui.mak b/VMProtect/mac_gui.mak new file mode 100644 index 0000000..24a92e0 --- /dev/null +++ b/VMProtect/mac_gui.mak @@ -0,0 +1,61 @@ +SOURCES := about_dialog.cc export_key_pair_dialog.cc function_dialog.cc import_license_dialog.cc license_dialog.cc main.cc mainwindow.cc message_dialog.cc remotecontrol.cc template_save_dialog.cc templates_window.cc \ + models.cc progress_dialog.cc property_editor.cc resources.cc settings_dialog.cc watermark_dialog.cc watermarks_window.cc widgets.cc help_browser.cc \ + ../third-party/scintilla/ScintillaQt.cc ../third-party/scintilla/ScintillaEditBase.cc \ + ../third-party/scintilla/PlatQt.cc + +MOC_HEADERS := application.h mainwindow.h property_editor.h widgets.h models.h about_dialog.h watermark_dialog.h message_dialog.h settings_dialog.h watermarks_window.h remotecontrol.h \ + export_key_pair_dialog.h function_dialog.h import_license_dialog.h license_dialog.h progress_dialog.h help_browser.h template_save_dialog.h templates_window.h + +SC_MOC_HEADERS := ScintillaQt.h ScintillaEditBase.h + +PROJECT := vmprotect_gui +TARGET := $(PROJECT) +QT_DIR := /Users/vano/Qt/5.6/clang_64 +BIN_DIR := ../bin/$(ARCH_DIR)/$(CFG_DIR) +APP_NAME := vmprotect_gui.app +APP_DIR := $(BIN_DIR)/$(APP_NAME) +SDK_DYLIB := libVMProtectSDK.dylib +TMP_ARCH_DIR := ../tmp/mac/gui/$(ARCH_DIR) +TMP_DIR := $(TMP_ARCH_DIR)/$(CFG_DIR)/$(PROJECT) +PCH_DIR := $(TMP_DIR)/$(PROJECT).gch +DEFINES := $(CONFIG) -DTIXML_USE_STL -DSCI_NAMESPACE +LFLAGS := -Wl,-rpath,$(QT_DIR)/lib +LIBS := -F$(QT_DIR)/lib -framework QtGui -framework QtCore -framework CoreServices -framework QtHelp -framework Security -framework QtWidgets -framework AppKit +OBJCOMP := ../bin/$(ARCH_DIR)/invariant_core.a ../bin/$(ARCH_DIR)/$(CFG_DIR)/core.a /usr/local/opt/libffi/lib/libffi.a +DYLIBS := ../bin/$(SDK_DYLIB) +PCH_DIR := $(TMP_DIR) +MOC_TEMPLATE := moc/moc_ +SC_MOC_TEMPLATE := ../VMProtect/moc/moc_ +INCFLAGS := -F$(QT_DIR)/lib + +include ../mac_common.mak + +OBJECTS := $(addprefix $(TMP_DIR)/, $(SOURCES:.cc=.o)) +MOC_RESULTS := $(addprefix $(MOC_TEMPLATE), $(MOC_HEADERS:.h=.cc)) +SC_MOC_RESULTS := $(addprefix $(SC_MOC_TEMPLATE), $(SC_MOC_HEADERS:.h=.cc)) + +clean: + -$(DEL_FILE) $(TMP_DIR)/app_icon.mmo + -$(DEL_FILE) $(OBJECTS) + -$(DEL_FILE) $(PCH_CPP) + -$(DEL_FILE) $(BIN_TARGET) + -$(DEL_FILE) $(MOC_RESULTS) + -$(DEL_FILE) $(SC_MOC_RESULTS) + -$(DEL_DIR) $(APP_DIR) + +all:: $(BIN_TARGET) + +$(BIN_TARGET): moc/.sentinel $(MOC_RESULTS) $(SC_MOC_RESULTS) $(OBJECTS) $(BIN_DIR)/.sentinel $(OBJCOMP) $(DYLIBS) $(TMP_DIR)/app_icon.mmo + $(LINK) $(LFLAGS) -o $(BIN_TARGET) $(OBJECTS) $(LIBS) $(OBJCOMP) $(DYLIBS) $(TMP_DIR)/app_icon.mmo + +$(TMP_DIR)/app_icon.mmo: app_icon.mm + $(CXX) -c $(CXXFLAGS) $(INCFLAGS) -o $(abspath $@) $(abspath $<) + +$(TMP_DIR)/%.o: %.cc $(PCH_CPP) $(TMP_DIR)/%/../.sentinel + $(CXX) -c -include-pch $(PCH_CPP) $(CXXFLAGS) $(INCFLAGS) -o $(abspath $@) $(abspath $<) + +$(MOC_TEMPLATE)%.cc: %.h + $(QT_DIR)/bin/moc -DSCI_NAMESPACE -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_HAVE_MMX -DQT_HAVE_3DNOW -DQT_HAVE_SSE -DQT_HAVE_MMXEXT -DQT_HAVE_SSE2 -DQT_THREAD_SUPPORT -I$(QT_DIR)/mkspecs/macs-xcode $(abspath $<) -o $(abspath $@) + +$(SC_MOC_TEMPLATE)%.cc: ../third-party/scintilla/%.h + $(QT_DIR)/bin/moc -DSCI_NAMESPACE -DUNICODE -DQT_LARGEFILE_SUPPORT -DQT_DLL -DQT_NO_DEBUG -DQT_GUI_LIB -DQT_CORE_LIB -DQT_HAVE_MMX -DQT_HAVE_3DNOW -DQT_HAVE_SSE -DQT_HAVE_MMXEXT -DQT_HAVE_SSE2 -DQT_THREAD_SUPPORT -I$(QT_DIR)/mkspecs/macs-xcode $(abspath $<) -o $(abspath $@) diff --git a/VMProtect/mac_gui32.mak b/VMProtect/mac_gui32.mak new file mode 100644 index 0000000..e936685 --- /dev/null +++ b/VMProtect/mac_gui32.mak @@ -0,0 +1,3 @@ +ARCH := i386 +ARCH_DIR := 32 +include mac_gui.mak diff --git a/VMProtect/mac_gui64.mak b/VMProtect/mac_gui64.mak new file mode 100644 index 0000000..ba9a152 --- /dev/null +++ b/VMProtect/mac_gui64.mak @@ -0,0 +1,3 @@ +ARCH := x86_64 +ARCH_DIR := 64 +include mac_gui.mak diff --git a/VMProtect/main.cc b/VMProtect/main.cc new file mode 100644 index 0000000..6c97308 --- /dev/null +++ b/VMProtect/main.cc @@ -0,0 +1,228 @@ +#include "../core/objects.h" +#include "../core/osutils.h" +#include "application.h" +#include "moc/moc_application.cc" +#include "mainwindow.h" +#include "help_browser.h" + +#ifndef VMP_GNU +#ifndef _DEBUG +#include <QtCore\QtPlugin> +Q_IMPORT_PLUGIN(QWindowsIntegrationPlugin); +#endif +#endif + +class PatchedProxyStyle : public QProxyStyle +{ +public: + PatchedProxyStyle() : QProxyStyle("windows") {} + + int styleHint(StyleHint hint, const QStyleOption *opt, const QWidget *widget, + QStyleHintReturn *returnData) const + { + int ret = 0; + switch (hint) + { + case QStyle::SH_MainWindow_SpaceBelowMenuBar: + ret = 0; + break; + default: + ret = QProxyStyle::styleHint(hint, opt, widget, returnData); + break; + } + return ret; + } + + void drawPrimitive(PrimitiveElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const + { + if(element == QStyle::PE_FrameFocusRect) + { + if (dynamic_cast<const QTabBar *>(widget)) + { + // compensate 'const int OFFSET = 1 + pixelMetric(PM_DefaultFrameWidth)' at qcommonstyle.cpp:1891 + const_cast<QStyleOption *>(option)->rect.adjust(-8, -3, 8, 3); + } + } + QProxyStyle::drawPrimitive(element, option, painter, widget); + } +}; + +/* + Application + */ + +Application::Application(int &argc, char **argv) + : QApplication(argc, argv) +{ + installStylesheet(); + + QStringList arguments = QCoreApplication::arguments(); + if (arguments.length() >= 3 && 0 == arguments.at(1).compare("--help")) + { + help_filename_ = arguments.at(2); + } +#ifdef VMP_GNU + if (isHelpMode()) { + QIcon icon(":/images/help_icon.png"); +#ifdef __APPLE__ + void qt_mac_set_app_icon(const QIcon &); + qt_mac_set_app_icon(icon); +#endif + setWindowIcon(icon); + } +#ifdef __unix__ + else + { + QIcon icon(":/images/logo.png"); + setWindowIcon(icon); + } +#endif +#else + HICON icon = static_cast<HICON>(LoadImageA(GetModuleHandle(NULL), + MAKEINTRESOURCEA(isHelpMode() ? 3 : 1), + IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADTRANSPARENT)); + setWindowIcon(QtWin::fromHICON(icon)); + ::DestroyIcon(icon); +#endif +} + +double Application::stylesheetScaleFactor_ = 96.0 / 72.0, Application::devicePixelRatio_ = 1.0; +void Application::initScalingConstants() +{ + double dpi = 96.0; + QScreen *srn = QApplication::primaryScreen(); + if (srn) + dpi = (double)srn->logicalDotsPerInch(); + + devicePixelRatio_ = +#ifdef __APPLE__ + 1.4 * // ïðîâåðÿë íà âèðòóàëêå (RENDER_DPI äëÿ ìàêà, ãîâîðÿò, ïðèìåðíî âî ñòîëüêî ðàç ìåíüøå), íî ïîäîçðåâàþ, ÷òî íà ìàêáóêå ñ ðåòèíîé ïîëó÷èì ñþðïðèç +#endif + devicePixelRatio(); + + double dprOverride = QString(qgetenv("VMP_PIXEL_RATIO")).toDouble(); + if (dprOverride != 0.0) + { + devicePixelRatio_ = dprOverride; + } + stylesheetScaleFactor_ = dpi * devicePixelRatio_ / 72.0; // 'point' to pixel +} + +Application::~Application() +{ + QFile t(os::CombineThisAppDataDirectory("styles.qss.tmp").c_str()); + if (t.exists()) + t.remove(); +} + +bool Application::event(QEvent *event) +{ + switch (event->type()) { + case QEvent::FileOpen: + if (isHelpMode() == false) + { + emit fileOpenEvent(static_cast<QFileOpenEvent *>(event)->file()); + return true; + } + default: + return QApplication::event(event); + } + +} + +void Application::installStylesheet() +{ + initScalingConstants(); + std::string qssFileName = os::CombineThisAppDataDirectory("styles.qss"); + if (!QFile::exists(qssFileName.c_str())) + qssFileName = ":/styles.qss"; + + QFile f(qssFileName.c_str()); + if (f.open(QIODevice::ReadOnly)) + { + QByteArray qssData = f.readAll(); + QByteArray qssDataTransformed = transformStylesheet(qssData); + QFile t(os::CombineThisAppDataDirectory("styles.qss.tmp").c_str()); + if (t.open(QIODevice::WriteOnly | QIODevice::Truncate)) + { + t.write(qssDataTransformed); + } + setStyleSheet(qssDataTransformed); + } +} + +QByteArray Application::transformStylesheet(const QByteArray &qssData) +{ + enum { + OUTSIDE, INSIDE + } state = OUTSIDE; + QByteArray ret; + ret.reserve(qssData.length() * 2); + QString current; + for(int idx = 0; idx < qssData.length(); ++idx) + { + char ch = qssData[idx]; + switch(state) + { + case OUTSIDE: + if (ch == '<') + state = INSIDE; + else + ret.append(ch); + break; + case INSIDE: + if (ch == '>') + { + double val = stylesheetScaleFactor_ * current.toDouble(); + char buf[30]; + sprintf_s(buf, "%dpx", int(val + 0.5)); + ret.append(buf); + current.clear(); + state = OUTSIDE; + } else + { + current.append(ch); + } + break; + } + } + return ret; +} + +int main(int argc, char *argv[]) +{ + QString file_name; + +#ifdef VMP_GNU + file_name = QString::fromUtf8(argv[0]); +#else + wchar_t **argv_w = CommandLineToArgvW(GetCommandLineW(), &argc); + if (argc) + file_name = QString::fromWCharArray(argv_w[0]); + LocalFree(argv_w); +#endif + + QDir dir = QFileInfo(file_name).absoluteDir(); +#ifdef __APPLE__ + dir.cdUp(); +#endif + dir.cd("PlugIns"); + + //QApplication::setLibraryPaths(QStringList(dir.absolutePath())); + QApplication::setAttribute(Qt::AA_EnableHighDpiScaling); + QApplication::setStyle(new PatchedProxyStyle()); + + Application app(argc, argv); + std::auto_ptr<QMainWindow> win; + if(app.isHelpMode()) + { + win.reset(new HelpBrowser(app.helpFileName())); + win->show(); + } else + { + win.reset(new MainWindow); + win->connect(&app, SIGNAL(fileOpenEvent(const QString &)), win.get(), SLOT(loadFile(const QString &))); + win->showMaximized(); + } + return app.exec(); +} diff --git a/VMProtect/mainwindow.cc b/VMProtect/mainwindow.cc new file mode 100644 index 0000000..70e27a7 --- /dev/null +++ b/VMProtect/mainwindow.cc @@ -0,0 +1,3712 @@ +#include "../core/objects.h" +#include "../core/files.h" +#include "../core/core.h" +#include "../core/processors.h" +#include "../core/script.h" +#include "../core/lang.h" +#include "../core/inifile.h" + +#include "models.h" +#include "widgets.h" +#include "property_editor.h" +#include "progress_dialog.h" +#include "mainwindow.h" +#include "moc/moc_mainwindow.cc" +#include "function_dialog.h" +#ifdef ULTIMATE +#include "license_dialog.h" +#include "import_license_dialog.h" +#include "export_key_pair_dialog.h" +#endif +#include "watermarks_window.h" +#include "settings_dialog.h" +#include "message_dialog.h" +#include "about_dialog.h" +#include "wait_cursor.h" +#include "help_browser.h" +#include "template_save_dialog.h" +#include "templates_window.h" +#include "application.h" + +#ifndef VMP_GNU +// cannot include header - name conflict with our "Folder" +#define CSIDL_COMMON_DOCUMENTS 0x002e // All Users\Documents +SHSTDAPI_(BOOL) SHGetSpecialFolderPathW(__reserved HWND hwnd, __out_ecount(MAX_PATH) LPWSTR pszPath, __in int csidl, __in BOOL fCreate); +#endif + +/** + * MainWindow + */ + +MainWindow::MainWindow() + : QMainWindow(), temp_function_(NULL), fileChanged_(false) +{ + installEventFilter(this); + + VMProtectBeginVirtualization("Caption"); +#ifdef DEMO + caption_ = QString::fromLatin1(Core::edition()).append(' ').append(QString::fromLatin1(VMProtectDecryptStringA("[demo]"))); +#else + bool is_registered = false; + { + VMProtectSerialNumberData serial_data; + if (VMProtectSetSerialNumber(VMProtectDecryptStringA("SerialNumber")) == SERIAL_STATE_SUCCESS && VMProtectGetSerialNumberData(&serial_data, sizeof(serial_data))) { + if (Core::check_license_edition(serial_data)) + is_registered = true; + else + VMProtectSetSerialNumber(NULL); + } + } + caption_ = QString::fromLatin1(Core::edition()).append(' ').append(QString::fromLatin1(is_registered ? VMProtectDecryptStringA("[registered]") : VMProtectDecryptStringA("[unregistered]"))); +#endif + setWindowTitle(caption_); + VMProtectEnd(); + + // create internal objects + log_ = new GUILog(this); + connect(log_, SIGNAL(notify(MessageType, IObject *, const QString &)), this, SLOT(notify(MessageType, IObject *, const QString &))); + + core_ = new Core(qobject_cast<ILog*>(log_)); + + watermarks_model_ = new WatermarksModel(this); + watermarks_model_->setCore(core_); + WatermarksWindow::setModel(watermarks_model_); + + templates_model_ = new TemplatesModel(this); + templates_model_->setCore(core_); + TemplatesWindow::setModel(templates_model_); + + project_model_ = new ProjectModel(this); + connect(project_model_, SIGNAL(modified()), this, SLOT(projectModified())); + connect(project_model_, SIGNAL(nodeRemoved(ProjectNode *)), this, SLOT(projectNodeRemoved(ProjectNode *))); + connect(project_model_, SIGNAL(objectRemoved(void *)), this, SLOT(projectObjectRemoved(void *))); + + search_model_ = new SearchModel(this); + directory_model_ = new DirectoryModel(this); + log_model_ = new LogModel(this); + function_property_manager_ = new FunctionPropertyManager(this); + core_property_manager_ = new CorePropertyManager(this); +#ifndef LITE + functions_model_ = new FunctionsModel(this); + info_model_ = new InfoModel(this); + connect(info_model_, SIGNAL(modified()), this, SLOT(projectModified())); + + dump_model_ = new DumpModel(this); + disasm_model_ = new DisasmModel(this); + section_property_manager_ = new SectionPropertyManager(this); + segment_property_manager_ = new SegmentPropertyManager(this); + import_property_manager_ = new ImportPropertyManager(this); + export_property_manager_ = new ExportPropertyManager(this); + resource_property_manager_ = new ResourcePropertyManager(this); + loadcommand_property_manager_ = new LoadCommandPropertyManager(this); + address_calculator_manager_ = new AddressCalculator(this); +#endif +#ifdef ULTIMATE + license_property_manager_ = new LicensePropertyManager(this); + internal_file_property_manager_ = new InternalFilePropertyManager(this); + assembly_property_manager_ = new AssemblyPropertyManager(this); +#endif + + // create actions + QIcon icon = QIcon(":/images/open.png"); + icon.addPixmap(QPixmap(":/images/open_hover.png"), QIcon::Active, QIcon::Off); + icon.addPixmap(QPixmap(":/images/open_disabled.png"), QIcon::Disabled, QIcon::Off); + open_act_ = new QAction(icon, QString::fromUtf8(language[lsOpen].c_str()) + "...", this); + open_act_->setShortcut(QString("Ctrl+O")); + connect(open_act_, SIGNAL(triggered()), this, SLOT(open())); + + icon = QIcon(":/images/disk.png"); + icon.addPixmap(QPixmap(":/images/disk_hover.png"), QIcon::Active, QIcon::Off); + icon.addPixmap(QPixmap(":/images/disk_disabled.png"), QIcon::Disabled, QIcon::Off); + save_act_ = new QAction(icon, QString::fromUtf8(language[lsSaveProject].c_str()), this); + save_act_->setShortcut(QString("Ctrl+S")); + save_act_->setEnabled(false); + connect(save_act_, SIGNAL(triggered()), this, SLOT(save())); + + save_as_act_ = new QAction(QString::fromUtf8(language[lsSaveProjectAs].c_str()) + "...", this); + save_as_act_->setShortcut(QKeySequence::SaveAs); + save_as_act_->setEnabled(false); + connect(save_as_act_, SIGNAL(triggered()), this, SLOT(saveAs())); + + close_act_ = new QAction(QString::fromUtf8(language[lsClose].c_str()), this); + close_act_->setShortcut(QString("Ctrl+W")); + close_act_->setEnabled(false); + connect(close_act_, SIGNAL(triggered()), this, SLOT(closeFile())); + + exit_act_ = new QAction(QString::fromUtf8(language[lsExit].c_str()), this); + connect(exit_act_, SIGNAL(triggered()), this, SLOT(close())); + + help_act_ = new QAction(QString::fromUtf8(language[lsContents].c_str()), this); + help_act_->setShortcut(HelpContentsKeySequence()); + connect(help_act_, SIGNAL(triggered()), this, SLOT(help())); + + home_page_act_ = new QAction(QString::fromUtf8(language[lsHomePage].c_str()), this); + home_page_act_->setToolTip("http://www.vmpsoft.com"); + connect(home_page_act_, SIGNAL(triggered()), this, SLOT(homePage())); + + about_act_ = new QAction(QString::fromUtf8(language[lsAbout].c_str()) + "...", this); + connect(about_act_, SIGNAL(triggered()), this, SLOT(about())); + + undo_act_ = new QAction(QString::fromUtf8(language[lsUndo].c_str()), this); + undo_act_->setShortcut(QKeySequence::Undo); + undo_act_->setEnabled(false); + connect(undo_act_, SIGNAL(triggered()), this, SLOT(undo())); + + redo_act_ = new QAction(QString::fromUtf8(language[lsRedo].c_str()), this); + redo_act_->setShortcut(QKeySequence::Redo); + redo_act_->setEnabled(false); + connect(redo_act_, SIGNAL(triggered()), this, SLOT(redo())); + + icon = QIcon(":/images/cut.png"); + icon.addPixmap(QPixmap(":/images/cut_hover.png"), QIcon::Active, QIcon::Off); + icon.addPixmap(QPixmap(":/images/cut_disabled.png"), QIcon::Disabled, QIcon::Off); + cut_act_ = new QAction(icon, QString::fromUtf8(language[lsCut].c_str()), this); + cut_act_->setShortcut(QKeySequence::Cut); + cut_act_->setEnabled(false); + connect(cut_act_, SIGNAL(triggered()), this, SLOT(cut())); + + icon = QIcon(":/images/copy.png"); + icon.addPixmap(QPixmap(":/images/copy_hover.png"), QIcon::Active, QIcon::Off); + icon.addPixmap(QPixmap(":/images/copy_disabled.png"), QIcon::Disabled, QIcon::Off); + copy_act_ = new QAction(icon, QString::fromUtf8(language[lsCopy].c_str()), this); + copy_act_->setShortcut(QKeySequence::Copy); + copy_act_->setEnabled(false); + connect(copy_act_, SIGNAL(triggered()), this, SLOT(copy())); + + icon = QIcon(":/images/paste.png"); + icon.addPixmap(QPixmap(":/images/paste_hover.png"), QIcon::Active, QIcon::Off); + icon.addPixmap(QPixmap(":/images/paste_disabled.png"), QIcon::Disabled, QIcon::Off); + paste_act_ = new QAction(icon, QString::fromUtf8(language[lsPaste].c_str()), this); + paste_act_->setShortcut(QKeySequence::Paste); + paste_act_->setEnabled(false); + connect(paste_act_, SIGNAL(triggered()), this, SLOT(paste())); + + cut_act2_ = new QAction(cut_act_->icon(), QString::fromUtf8(language[lsCut].c_str()), this); + cut_act2_->setEnabled(false); + cut_act2_->setVisible(false); + connect(cut_act2_, SIGNAL(triggered()), this, SLOT(cut())); + + copy_act2_ = new QAction(copy_act_->icon(), QString::fromUtf8(language[lsCopy].c_str()), this); + copy_act2_->setEnabled(false); + copy_act2_->setVisible(false); + connect(copy_act2_, SIGNAL(triggered()), this, SLOT(copy())); + + paste_act2_ = new QAction(paste_act_->icon(), QString::fromUtf8(language[lsPaste].c_str()), this); + paste_act2_->setEnabled(false); + paste_act2_->setVisible(false); + connect(paste_act2_, SIGNAL(triggered()), this, SLOT(paste())); + +#ifdef LITE + icon = QIcon(":/images/check_off.png"); + icon.addPixmap(QPixmap(":/images/check_on.png"), QIcon::Normal, QIcon::On); + icon.addPixmap(QPixmap(":/images/check_off_hover.png"), QIcon::Active, QIcon::Off); + icon.addPixmap(QPixmap(":/images/check_on_hover.png"), QIcon::Active, QIcon::On); + show_act_ = new QAction(icon, QString::fromUtf8(language[lsShowProtectedFunctions].c_str()), this); + show_act_->setCheckable(true); + show_act_->setVisible(false); + connect(show_act_, SIGNAL(triggered()), this, SLOT(showProtected())); +#else + goto_act_ = new QAction(icon, QString::fromUtf8(language[lsGoTo].c_str()) + "...", this); + goto_act_->setShortcut(QString("Ctrl+G")); + goto_act_->setEnabled(false); + connect(goto_act_, SIGNAL(triggered()), this, SLOT(goTo())); + + icon = QIcon(":/images/goto.png"); + icon.addPixmap(QPixmap(":/images/goto_hover.png"), QIcon::Active, QIcon::Off); + icon.addPixmap(QPixmap(":/images/goto_disabled.png"), QIcon::Disabled, QIcon::Off); + goto_act2_ = new QAction(icon, QString::fromUtf8(language[lsGoTo].c_str()), this); + goto_act2_->setVisible(false); + connect(goto_act2_, SIGNAL(triggered()), this, SLOT(goTo())); + + add_function_act_ = new QAction(QString::fromUtf8(language[lsAddFunction].c_str()) + "...", this); + add_function_act_->setEnabled(false); + connect(add_function_act_, SIGNAL(triggered()), this, SLOT(addFunction())); + + add_folder_act_ = new QAction(QString::fromUtf8(language[lsAddFolder].c_str()) + "...", this); + add_folder_act_->setEnabled(false); + connect(add_folder_act_, SIGNAL(triggered()), this, SLOT(addFolder())); + + icon = QIcon(":/images/add.png"); + icon.addPixmap(QPixmap(":/images/add_hover.png"), QIcon::Active, QIcon::Off); + icon.addPixmap(QPixmap(":/images/add_disabled.png"), QIcon::Disabled, QIcon::Off); + add_function_act2_ = new QAction(icon, QString::fromUtf8(language[lsAddFunction].c_str()), this); + add_function_act2_->setShortcut(QString("Ins")); + add_function_act2_->setVisible(false); + connect(add_function_act2_, SIGNAL(triggered()), this, SLOT(addFunction())); + + watermarks_act_ = new QAction(QString::fromUtf8(language[lsWatermarks].c_str()) + "...", this); + connect(watermarks_act_, SIGNAL(triggered()), this, SLOT(watermarks())); +#endif + +#ifdef ULTIMATE + save_licenses_act_ = new QAction(QString::fromUtf8(language[lsSaveLicensesAs].c_str()) + "...", this); + save_licenses_act_->setEnabled(false); + connect(save_licenses_act_, SIGNAL(triggered()), this, SLOT(saveLicenses())); + + add_license_act_ = new QAction(QString::fromUtf8(language[lsAddLicense].c_str()) + "...", this); + add_license_act_->setEnabled(false); + connect(add_license_act_, SIGNAL(triggered()), this, SLOT(addLicense())); + add_license_act2_ = new QAction(icon, QString::fromUtf8(language[lsAddLicense].c_str()), this); + add_license_act2_->setShortcut(QString("Ins")); + add_license_act2_->setVisible(false); + connect(add_license_act2_, SIGNAL(triggered()), this, SLOT(addLicense())); + + add_file_act_ = new QAction((language[lsAddFile] + "...").c_str(), this); + add_file_act_->setEnabled(false); + connect(add_file_act_, SIGNAL(triggered()), this, SLOT(addFile())); + add_file_act2_ = new QAction(icon, QString::fromUtf8(language[lsAddFile].c_str()), this); + add_file_act2_->setShortcut(QString("Ins")); + add_file_act2_->setVisible(false); + connect(add_file_act2_, SIGNAL(triggered()), this, SLOT(addFile())); + + import_license_act_ = new QAction(QString::fromUtf8(language[lsImportLicense].c_str()) + "...", this); + import_license_act_->setShortcut(QString("Ctrl+I")); + import_license_act_->setEnabled(false); + connect(import_license_act_, SIGNAL(triggered()), this, SLOT(importLicense())); + + import_project_act_ = new QAction(QString::fromUtf8(language[lsImportLicensesFromProjectFile].c_str()) + "...", this); + import_project_act_->setShortcut(QString("Ctrl+Shift+I")); + import_project_act_->setEnabled(false); + connect(import_project_act_, SIGNAL(triggered()), this, SLOT(importProject())); + + export_key_act_ = new QAction((language[lsExportKeyPair] + "...").c_str(), this); + export_key_act_->setEnabled(false); + connect(export_key_act_, SIGNAL(triggered()), this, SLOT(exportKeyPair())); +#endif + + delete_act_ = new QAction(QString::fromUtf8(language[lsDelete].c_str()), this); + delete_act_->setShortcut(QString("Del")); + delete_act_->setEnabled(false); + connect(delete_act_, SIGNAL(triggered()), this, SLOT(del())); + + rename_act_ = new QAction(QString::fromUtf8(language[lsRename].c_str()), this); + rename_act_->setShortcut(QString("F2")); + rename_act_->setEnabled(false); + connect(rename_act_, SIGNAL(triggered()), this, SLOT(rename())); + + exclude_act_ = new QAction(QString::fromUtf8(language[lsExcludedFromCompilation].c_str()), this); + exclude_act_->setEnabled(false); + exclude_act_->setCheckable(true); + connect(exclude_act_, SIGNAL(triggered()), this, SLOT(excludeFromCompilation())); + + block_act_ = new QAction(QString::fromUtf8(language[lsBlocked].c_str()), this); + block_act_->setEnabled(false); + block_act_->setCheckable(true); + connect(block_act_, SIGNAL(triggered()), this, SLOT(block())); + + icon = QIcon(":/images/compile.png"); + icon.addPixmap(QPixmap(":/images/compile_hover.png"), QIcon::Active, QIcon::Off); + icon.addPixmap(QPixmap(":/images/compile_disabled.png"), QIcon::Disabled, QIcon::Off); + compile_act_ = new QAction(icon, QString::fromUtf8(language[lsCompile].c_str()), this); + compile_act_->setShortcut(QString("F9")); + compile_act_->setEnabled(false); + connect(compile_act_, SIGNAL(triggered()), this, SLOT(compile())); + + icon = QIcon(":/images/execute.png"); + icon.addPixmap(QPixmap(":/images/execute_hover.png"), QIcon::Active, QIcon::Off); + icon.addPixmap(QPixmap(":/images/execute_disabled.png"), QIcon::Disabled, QIcon::Off); + execute_act_ = new QAction(icon, QString::fromUtf8(language[lsExecute].c_str()), this); + execute_act_->setShortcut(QString("F5")); + execute_act_->setEnabled(false); + connect(execute_act_, SIGNAL(triggered()), this, SLOT(execute())); + + execute_original_act_ = new ElidedAction(this); + execute_original_act_->setEnabled(false); + connect(execute_original_act_, SIGNAL(triggered()), this, SLOT(executeOriginal())); + + execute_protected_act_ = new ElidedAction("", this); + execute_protected_act_->setVisible(false); + connect(execute_protected_act_, SIGNAL(triggered()), this, SLOT(executeProtected())); + + execute_parameters_act_ = new QWidgetAction(this); + + search_act_ = new QAction(icon, QString::fromUtf8(language[lsSearch].c_str()), this); + search_act_->setShortcut(QString("Ctrl+F")); + search_act_->setEnabled(false); + connect(search_act_, SIGNAL(triggered()), this, SLOT(search())); + + QList<QAction *> action_list = this->findChildren<QAction *>(); + for (QList<QAction *>::ConstIterator it = action_list.constBegin(); it != action_list.constEnd(); it++) { + (*it)->setIconVisibleInMenu(false); + } + + settings_act_ = new QAction(QString::fromUtf8(language[lsSettings].c_str()), this); + connect(settings_act_, SIGNAL(triggered()), this, SLOT(settings())); + + // create menu + file_menu_ = menuBar()->addMenu(QString::fromUtf8(language[lsFile].c_str())); + file_menu_->addAction(open_act_); + file_menu_->addAction(save_act_); + file_menu_->addAction(save_as_act_); +#ifdef ULTIMATE + file_menu_->addAction(save_licenses_act_); +#endif + file_menu_->addAction(close_act_); + history_separator_ = file_menu_->addSeparator(); + history_separator_->setVisible(false); + file_menu_->addSeparator(); + file_menu_->addAction(exit_act_); + + edit_menu_ = menuBar()->addMenu(QString::fromUtf8(language[lsEdit].c_str())); + edit_menu_->addAction(undo_act_); + edit_menu_->addAction(redo_act_); + edit_menu_->addSeparator(); + edit_menu_->addAction(cut_act_); + edit_menu_->addAction(copy_act_); + edit_menu_->addAction(paste_act_); + edit_menu_->addAction(delete_act_); + + edit_menu_->addSeparator(); + edit_menu_->addAction(search_act_); +#ifndef LITE + edit_menu_->addAction(goto_act_); +#endif + + project_menu_ = menuBar()->addMenu(QString::fromUtf8(language[lsProject].c_str())); +#ifndef LITE + add_menu_ = project_menu_->addMenu(QString::fromUtf8(language[lsAdd].c_str())); + add_menu_->setEnabled(false); + add_menu_->addAction(add_function_act_); +#endif +#ifdef ULTIMATE + add_menu_->addAction(add_license_act_); + add_menu_->addAction(add_file_act_); +#endif +#ifndef LITE + add_menu_->addAction(add_folder_act_); +#endif +#ifdef ULTIMATE + project_menu_->addSeparator(); + project_menu_->addAction(export_key_act_); + import_menu_ = project_menu_->addMenu(QString::fromUtf8(language[lsImport].c_str())); + import_menu_->setEnabled(false); + import_menu_->addAction(import_license_act_); + import_menu_->addAction(import_project_act_); +#endif +#ifndef LITE + project_menu_->addSeparator(); +#endif + project_menu_->addAction(compile_act_); + project_menu_->addAction(execute_act_); + + tools_menu_ = menuBar()->addMenu(QString::fromUtf8(language[lsTools].c_str())); +#ifndef LITE + tools_menu_->addAction(watermarks_act_); +#endif + tools_menu_->addAction(settings_act_); + + help_menu_ = menuBar()->addMenu(QString::fromUtf8(language[lsHelp].c_str())); + help_menu_->addAction(help_act_); + help_menu_->addSeparator(); + help_menu_->addAction(home_page_act_); + help_menu_->addAction(about_act_); + + function_ext_address_act_ = new QAction(QString::fromUtf8(language[lsExternalAddress].c_str()), this); + connect(function_ext_address_act_, SIGNAL(triggered()), this, SLOT(functionExtAddress())); + function_end_address_act_ = new QAction(QString::fromUtf8(language[lsBreakAddress].c_str()), this); + connect(function_end_address_act_, SIGNAL(triggered()), this, SLOT(functionEndAddress())); + function_del_act_ = new QAction(QString::fromUtf8(language[lsDelete].c_str()), this); + connect(function_del_act_, SIGNAL(triggered()), this, SLOT(functionDel())); + + script_menu_ = new QMenu(this); + script_menu_->addAction(undo_act_); + script_menu_->addAction(redo_act_); + script_menu_->addSeparator(); + script_menu_->addAction(cut_act_); + script_menu_->addAction(copy_act_); + script_menu_->addAction(paste_act_); + script_menu_->addAction(delete_act_); + script_menu_->addSeparator(); + script_menu_->addAction(search_act_); + + // create widgets + project_filter_ = new SearchLineEdit(this); + project_filter_->setFrame(false); + project_filter_->setFixedWidth(200); + connect(project_filter_, SIGNAL(textChanged(const QString &)), this, SLOT(projectFilterChanged())); + connect(project_filter_, SIGNAL(returnPressed()), this, SLOT(projectFilterChanged())); + + QWidget *widget = new QWidget(this); + QLabel *label = new QLabel(QString::fromUtf8(language[lsParameters].c_str()) + ":", this); + parameters_edit_ = new LineEdit(this); + QBoxLayout *layout = new QHBoxLayout(); + layout->setContentsMargins(16, 0, 0, 0); + layout->addWidget(label); + layout->addWidget(parameters_edit_); + widget->setLayout(layout); + execute_parameters_act_->setDefaultWidget(widget); + + execute_menu_ = new QMenu(this); + execute_menu_->addAction(execute_original_act_); + execute_menu_->addAction(execute_protected_act_); + execute_menu_->addSeparator(); + execute_menu_->addAction(execute_parameters_act_); + + setContextMenuPolicy(Qt::NoContextMenu); + + QToolBar *tool_bar = addToolBar(""); + tool_bar->setMovable(false); + tool_bar->setIconSize(QSize(20, 20)); + tool_bar->addSeparator(); + tool_bar->addAction(open_act_); + tool_bar->addAction(save_act_); + tool_bar->addSeparator(); + spacer_ = new ToolButtonElided(this); + spacer_->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + spacer_->setCursor(Qt::PointingHandCursor); + spacer_->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); + spacer_->setFixedWidth(0); + connect(spacer_, SIGNAL(clicked()), this, SLOT(showFile())); + tool_bar->addWidget(spacer_); + tool_bar->addAction(compile_act_); + tool_bar->addAction(execute_act_); + QToolButton *button = reinterpret_cast<QToolButton *>(tool_bar->widgetForAction(execute_act_)); + button->setMenu(execute_menu_); + button->setPopupMode(QToolButton::MenuButtonPopup); + project_separator_ = tool_bar->addSeparator(); + //project_separator_->setVisible(false); + project_separator_widget_ = tool_bar->widgetForAction(project_separator_); + tool_bar->addAction(cut_act2_); + tool_bar->addAction(copy_act2_); + tool_bar->addAction(paste_act2_); +#ifdef LITE + tool_bar->addAction(show_act_); + reinterpret_cast<QToolButton*>(tool_bar->widgetForAction(show_act_))->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); +#else + tool_bar->addAction(add_function_act2_); + reinterpret_cast<QToolButton*>(tool_bar->widgetForAction(add_function_act2_))->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + tool_bar->addAction(goto_act2_); + reinterpret_cast<QToolButton*>(tool_bar->widgetForAction(goto_act2_))->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); +#endif +#ifdef ULTIMATE + tool_bar->addAction(add_license_act2_); + reinterpret_cast<QToolButton*>(tool_bar->widgetForAction(add_license_act2_))->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + tool_bar->addAction(add_file_act2_); + reinterpret_cast<QToolButton*>(tool_bar->widgetForAction(add_file_act2_))->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); +#endif + + templates_save_act_ = new QAction(QString::fromUtf8(language[lsSaveTemplateAs].c_str()) + "...", this); + connect(templates_save_act_, SIGNAL(triggered()), this, SLOT(templatesSave())); + + templates_edit_act_ = new QAction(QString::fromUtf8(language[lsEdit].c_str()) + "...", this); + connect(templates_edit_act_, SIGNAL(triggered()), this, SLOT(templatesEdit())); + + templates_menu_ = new QMenu(this); + templates_menu_->addSeparator(); + templates_menu_->addAction(templates_save_act_); + templates_menu_->addAction(templates_edit_act_); + connect(templates_menu_, SIGNAL(aboutToShow()), this, SLOT(templatesShow())); + updateTemplates(); + + templates_act_ = new QAction(copy_act_->icon(), QString::fromUtf8(language[lsTemplates].c_str()), this); + templates_act_->setVisible(false); + + tool_bar->addAction(templates_act_); + QToolButton *template_button = reinterpret_cast<QToolButton*>(tool_bar->widgetForAction(templates_act_)); + template_button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + template_button->setPopupMode(QToolButton::InstantPopup); + template_button->setMenu(templates_menu_); + + QWidget *spacer = new QWidget(this); + spacer->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + tool_bar->addWidget(spacer); + project_filter_act_ = tool_bar->addWidget(project_filter_); + project_filter_act_->setVisible(false); + + project_frame_ = new QFrame(this); + status_bar_ = new QStatusBar(this); + + project_tree_ = new TreeView(this); + project_tree_->setObjectName("project"); + project_tree_->setFrameShape(QFrame::NoFrame); + project_tree_->header()->setObjectName("project"); + project_tree_->setIconSize(QSize(18, 18)); + project_tree_->setModel(project_model_); + project_tree_->setContextMenuPolicy(Qt::CustomContextMenu); + project_tree_->setDragDropMode(QAbstractItemView::DragDrop); + project_tree_->setItemDelegate(new ProjectTreeDelegate(this)); + connect(project_tree_->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(projectItemChanged())); + connect(project_tree_, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(projectContextMenu(const QPoint &))); + +#ifndef LITE + functions_tree_ = new TreeView(this); + functions_tree_->setObjectName("project"); + functions_tree_->setFrameShape(QFrame::NoFrame); + functions_tree_->header()->setObjectName("project"); + functions_tree_->setIconSize(QSize(18, 18)); + functions_tree_->setModel(functions_model_); + functions_tree_->setContextMenuPolicy(Qt::CustomContextMenu); + connect(functions_tree_->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(projectItemChanged())); + connect(functions_tree_, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(projectContextMenu(const QPoint &))); + + info_tree_ = new TreeView(this); + info_tree_->setObjectName("project"); + info_tree_->setFrameShape(QFrame::NoFrame); + info_tree_->header()->setObjectName("project"); + info_tree_->setIconSize(QSize(18, 18)); + info_tree_->setModel(info_model_); + connect(info_tree_->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(projectItemChanged())); +#endif + + project_tab_ = new TabWidget(this); + project_tab_->tabBar()->hide(); + project_tab_->resize(240 * Application::stylesheetScaleFactor(), 10); + + QFrame *tab_bar = new QFrame(this); + tab_bar->setObjectName("desktop"); + + icon_project_ = new QRadioButton(this); + icon_project_->setObjectName("project"); + icon_project_->setChecked(true); + connect(icon_project_, SIGNAL(toggled(bool)), this, SLOT(projectTabClicked())); + +#ifndef LITE + icon_functions_ = new QRadioButton(this); + icon_functions_->setObjectName("functions"); + connect(icon_functions_, SIGNAL(toggled(bool)), this, SLOT(projectTabClicked())); + + icon_details_ = new QRadioButton(this); + icon_details_->setObjectName("details"); + connect(icon_details_, SIGNAL(toggled(bool)), this, SLOT(projectTabClicked())); +#endif + + layout = new QVBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(icon_project_); +#ifndef LITE + layout->addWidget(icon_functions_); + layout->addWidget(icon_details_); +#endif + layout->addStretch(1); + tab_bar->setLayout(layout); + + project_tab_->addTab(project_tree_, ""); +#ifndef LITE + project_tab_->addTab(functions_tree_, ""); + project_tab_->addTab(info_tree_, ""); +#endif + connect(project_tab_, SIGNAL(currentChanged(int)), this, SLOT(projectFilterChanged())); + connect(project_tab_, SIGNAL(resized()), this, SLOT(projectTabMoved())); + + search_tree_ = new TreeView(this); + search_tree_->setObjectName("grid"); + search_tree_->setIconSize(QSize(18, 18)); + search_tree_->setRootIsDecorated(false); + search_tree_->setFrameShape(QFrame::NoFrame); + search_tree_->setModel(search_model_); + search_tree_->setEditTriggers(QAbstractItemView::NoEditTriggers); + search_tree_->header()->setSectionsMovable(false); + connect(search_tree_, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(treeItemDoubleClicked(QModelIndex))); + + directory_tree_ = new TreeView(this); + directory_tree_->setObjectName("grid"); + directory_tree_->setIconSize(QSize(18, 18)); + directory_tree_->setFrameShape(QFrame::NoFrame); + directory_tree_->setRootIsDecorated(false); + directory_tree_->setModel(directory_model_); + directory_tree_->setItemDelegate(new ProjectTreeDelegate(this)); + directory_tree_->header()->setSectionsMovable(false); + connect(directory_tree_, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(treeItemDoubleClicked(QModelIndex))); + connect(directory_tree_->header(), SIGNAL(sectionClicked(int)), this, SLOT(treeSectionClicked(int))); + directory_tree_->setContextMenuPolicy(Qt::CustomContextMenu); + connect(directory_tree_, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(projectContextMenu(const QPoint &))); + +#ifndef LITE + dump_view_ = new TableView(this); + dump_view_->setObjectName("grid"); + dump_view_->setIconSize(QSize(18, 18)); + dump_view_->setFrameShape(QFrame::NoFrame); + dump_view_->setModel(dump_model_); + dump_view_->setShowGrid(false); + dump_view_->setEditTriggers(QAbstractItemView::NoEditTriggers); + dump_view_->horizontalHeader()->resizeSection(0, 150 * Application::stylesheetScaleFactor()); + dump_view_->horizontalHeader()->resizeSection(1, 300 * Application::stylesheetScaleFactor()); + dump_view_->horizontalHeader()->setStretchLastSection(true); + dump_view_->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter); + dump_view_->horizontalHeader()->setSectionsClickable(false); + dump_view_->verticalHeader()->setDefaultSectionSize(dump_view_->verticalHeader()->minimumSectionSize()); + dump_view_->setSelectionBehavior(QAbstractItemView::SelectRows); + + disasm_view_ = new DisasmView(this); + disasm_view_->setObjectName("grid"); + disasm_view_->setIconSize(QSize(18, 18)); + disasm_view_->setFrameShape(QFrame::NoFrame); + disasm_view_->setModel(disasm_model_); + disasm_view_->setShowGrid(false); + disasm_view_->setEditTriggers(QAbstractItemView::NoEditTriggers); + disasm_view_->horizontalHeader()->resizeSection(0, 150 * Application::stylesheetScaleFactor()); + disasm_view_->horizontalHeader()->resizeSection(1, 300 * Application::stylesheetScaleFactor()); + disasm_view_->horizontalHeader()->setStretchLastSection(true); + disasm_view_->horizontalHeader()->setDefaultAlignment(Qt::AlignLeft | Qt::AlignVCenter); + disasm_view_->horizontalHeader()->setSectionsClickable(false); + disasm_view_->verticalHeader()->setDefaultSectionSize(dump_view_->verticalHeader()->minimumSectionSize()); + disasm_view_->setSelectionBehavior(QAbstractItemView::SelectRows); + connect(disasm_view_, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(disasmItemDoubleClicked(QModelIndex))); + +#endif + + script_editor_ = new ScriptEdit(this); + script_editor_->setContextMenuPolicy(Qt::CustomContextMenu); + connect(script_editor_, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(scriptContextMenu(const QPoint &))); + + project_file_name_ = new QLabel(this); + + script_line_ = new QLabel(this); + script_line_->setFixedWidth(100); + + script_column_ = new QLabel(this); + script_column_->setFixedWidth(100); + + script_mode_ = new Label(this); + script_mode_->setFixedWidth(30); + connect(script_mode_, SIGNAL(doubleClicked()), this, SLOT(scriptModeClicked())); + + status_bar_->addPermanentWidget(project_file_name_, 1); + status_bar_->addPermanentWidget(script_line_); + status_bar_->addPermanentWidget(script_column_); + status_bar_->addPermanentWidget(script_mode_); + + core_property_editor_ = new TreePropertyEditor(this); + core_property_editor_->setModel(core_property_manager_); + core_property_editor_->expandToDepth(0); + core_property_editor_->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + core_property_editor_->header()->setSectionsMovable(false); + + function_property_editor_ = new TreePropertyEditor(this); + function_property_editor_->setModel(function_property_manager_); + function_property_editor_->expandToDepth(0); + function_property_editor_->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + function_property_editor_->setContextMenuPolicy(Qt::CustomContextMenu); + function_property_editor_->setSelectionMode(QTreeView::ExtendedSelection); + function_property_editor_->header()->setSectionsMovable(false); + connect(function_property_editor_, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(functionContextMenu(const QPoint &))); + connect(function_property_editor_, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(functionItemDoubleClicked(QModelIndex))); + +#ifndef LITE + section_property_editor_ = new TreePropertyEditor(this); + section_property_editor_->setModel(section_property_manager_); + section_property_editor_->expandToDepth(0); + section_property_editor_->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + section_property_editor_->header()->setSectionsMovable(false); + + segment_property_editor_ = new TreePropertyEditor(this); + segment_property_editor_->setModel(segment_property_manager_); + segment_property_editor_->expandToDepth(0); + segment_property_editor_->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + segment_property_editor_->header()->setSectionsMovable(false); + + import_property_editor_ = new TreePropertyEditor(this); + import_property_editor_->setModel(import_property_manager_); + import_property_editor_->expandToDepth(0); + import_property_editor_->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + import_property_editor_->header()->setSectionsMovable(false); + + export_property_editor_ = new TreePropertyEditor(this); + export_property_editor_->setModel(export_property_manager_); + export_property_editor_->expandToDepth(0); + export_property_editor_->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + export_property_editor_->header()->setSectionsMovable(false); + + resource_property_editor_ = new TreePropertyEditor(this); + resource_property_editor_->setModel(resource_property_manager_); + resource_property_editor_->expandToDepth(0); + resource_property_editor_->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + resource_property_editor_->header()->setSectionsMovable(false); + + loadcommand_property_editor_ = new TreePropertyEditor(this); + loadcommand_property_editor_->setModel(loadcommand_property_manager_); + loadcommand_property_editor_->expandToDepth(0); + loadcommand_property_editor_->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + loadcommand_property_editor_->header()->setSectionsMovable(false); + + address_calculator_ = new TreePropertyEditor(this); + address_calculator_->setModel(address_calculator_manager_); + address_calculator_->expandToDepth(0); + address_calculator_->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + address_calculator_->header()->setSectionsMovable(false); +#endif + + QFont font; + font.setBold(true); + +#ifdef ULTIMATE + license_property_editor_ = new TreePropertyEditor(this); + license_property_editor_->setModel(license_property_manager_); + license_property_editor_->expandToDepth(0); + license_property_editor_->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + license_property_editor_->header()->setSectionsMovable(false); + + internal_file_property_editor_ = new TreePropertyEditor(this); + internal_file_property_editor_->setModel(internal_file_property_manager_); + internal_file_property_editor_->expandToDepth(0); + internal_file_property_editor_->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + internal_file_property_editor_->header()->setSectionsMovable(false); + + assembly_property_editor_ = new TreePropertyEditor(this); + assembly_property_editor_->setModel(assembly_property_manager_); + assembly_property_editor_->expandToDepth(0); + assembly_property_editor_->header()->resizeSection(0, 240 * Application::stylesheetScaleFactor()); + assembly_property_editor_->header()->setSectionsMovable(false); + + licensing_parameters_page_ = new QFrame(this); + licensing_parameters_page_->setObjectName("editor"); + + label = new QLabel(this); + label->setAlignment(Qt::AlignCenter); + label->setPixmap(QPixmap(":/images/key_gray.png")); + + licensing_parameters_help_ = new QLabel(this); + licensing_parameters_help_->setObjectName("note"); + licensing_parameters_help_->setAlignment(Qt::AlignCenter); + licensing_parameters_help_->setWordWrap(true); + licensing_parameters_help_->setText(QString::fromUtf8(language[lsKeyPairHelp].c_str())); + + QFrame *key_frame = new QFrame(this); + key_frame->setObjectName("gridEditor"); + key_frame->setFrameShape(QFrame::NoFrame); + + key_algo_label_ = new QLabel(QString::fromUtf8(language[lsKeyPairAlgorithm].c_str()), this); + key_algo_label_->setObjectName("editor"); + + QComboBox *comboKeyAlgo = new QComboBox(this); + comboKeyAlgo->setFrame(false); + comboKeyAlgo->setFont(font); + comboKeyAlgo->addItem("RSA"); + comboKeyAlgo->setCurrentIndex(0); + + key_len_label_ = new QLabel(QString::fromUtf8(language[lsKeyLength].c_str()), this); + key_len_label_->setObjectName("editor"); + + key_len_ = new QComboBox(this); + key_len_->setFrame(false); + key_len_->setFont(font); + key_len_->addItems(QStringList() << "1024" << "1536" << "2048" << "2560" << "3072" << "3584" << "4096"); + key_len_->setCurrentIndex(2); + + create_key_button_ = new PushButton(QString::fromUtf8(language[lsGenerate].c_str()), this); + //create_key_button_->setDefault(true); + connect(create_key_button_, SIGNAL(clicked()), this, SLOT(createKeyPair())); + + use_other_project_button_ = new PushButton(QString::fromUtf8(language[lsUseOtherProject].c_str()), this); + connect(use_other_project_button_, SIGNAL(clicked()), this, SLOT(useOtherProject())); + + QGridLayout *keyLayout = new QGridLayout(); + keyLayout->setContentsMargins(0, 1, 0, 1); + keyLayout->setHorizontalSpacing(0); + keyLayout->setVerticalSpacing(1); + keyLayout->addWidget(key_algo_label_, 0, 0); + keyLayout->addWidget(comboKeyAlgo, 0, 1); + keyLayout->addWidget(key_len_label_, 1, 0); + keyLayout->addWidget(key_len_, 1, 1); + key_frame->setLayout(keyLayout); + + QHBoxLayout *buttonLayout = new QHBoxLayout(); + buttonLayout->setContentsMargins(0, 0, 0, 0); + buttonLayout->setSpacing(10); + buttonLayout->addWidget(create_key_button_); + buttonLayout->addWidget(use_other_project_button_); + buttonLayout->setAlignment(Qt::AlignCenter); + + layout = new QVBoxLayout(); + layout->setContentsMargins(0, 50, 0, 0); + layout->setSpacing(30); + layout->addWidget(label); + layout->addWidget(licensing_parameters_help_); + layout->addWidget(key_frame); + layout->addLayout(buttonLayout); + layout->addStretch(1); + licensing_parameters_page_->setLayout(layout); +#endif + + QSplitter *splitter; +#ifndef LITE + splitter = new QSplitter(this); + splitter->setOrientation(Qt::Vertical); + dump_page_ = new QFrame(this); + dump_page_->setObjectName("gridEditor"); + layout = new QVBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(disasm_view_); + layout->addWidget(splitter); + layout->addWidget(dump_view_); + dump_page_->setLayout(layout); + + splitter->addWidget(disasm_view_); + splitter->addWidget(dump_view_); + splitter->setStretchFactor(0, 1); + splitter->setStretchFactor(1, 0); +#endif + + project_page_ = new QStackedWidget(this); + project_page_->addWidget(search_tree_); + project_page_->addWidget(directory_tree_); + project_page_->addWidget(function_property_editor_); + project_page_->addWidget(script_editor_); + project_page_->addWidget(core_property_editor_); +#ifndef LITE + project_page_->addWidget(section_property_editor_); + project_page_->addWidget(segment_property_editor_); + project_page_->addWidget(import_property_editor_); + project_page_->addWidget(export_property_editor_); + project_page_->addWidget(resource_property_editor_); + project_page_->addWidget(loadcommand_property_editor_); + project_page_->addWidget(address_calculator_); + project_page_->addWidget(dump_page_); +#endif +#ifdef ULTIMATE + project_page_->addWidget(licensing_parameters_page_); + project_page_->addWidget(license_property_editor_); + project_page_->addWidget(internal_file_property_editor_); + project_page_->addWidget(assembly_property_editor_); +#endif + + context_find_ = new FindWidget(this); + context_find_->hide(); + connect(context_find_, SIGNAL(findNext()), this, SLOT(contextFindNext())); + connect(context_find_, SIGNAL(findPrevious()), this, SLOT(contextFindPrevious())); + connect(context_find_, SIGNAL(find(QString, bool, bool)), this, + SLOT(contextFind(QString, bool, bool))); + connect(context_find_, SIGNAL(escapePressed()), this, SLOT(contextFindClosed())); + + QWidget *project_find = new QWidget(this); + layout = new QVBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(project_page_); + layout->addWidget(context_find_); + project_find->setLayout(layout); + + log_tree_ = new LogTreeView(this); + log_tree_->setFrameShape(QFrame::NoFrame); + log_tree_->setRootIsDecorated(false); + log_tree_->setModel(log_model_); + connect(log_tree_, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(logItemDoubleClicked(QModelIndex))); + + splitter = new QSplitter(this); + splitter->setOrientation(Qt::Vertical); + + QFrame *project_right = new QFrame(this); + layout = new QVBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(project_find); + layout->addWidget(splitter); + layout->addWidget(log_tree_); + project_right->setLayout(layout); + + splitter->addWidget(project_find); + splitter->addWidget(log_tree_); + splitter->setStretchFactor(0, 1); + splitter->setStretchFactor(1, 0); + + splitter = new QSplitter(this); + + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->setContentsMargins(0, 0, 0, 0); + gridLayout->setSpacing(0); + gridLayout->addWidget(tab_bar, 0, 0); + gridLayout->addWidget(project_tab_, 0, 1); + gridLayout->addWidget(splitter, 0, 2); + gridLayout->addWidget(project_right, 0, 3); + gridLayout->addWidget(status_bar_, 1, 0, 1, 4); + project_frame_->setLayout(gridLayout); + + splitter->addWidget(project_tab_); + splitter->addWidget(project_right); + splitter->setStretchFactor(0, 0); + splitter->setStretchFactor(1, 1); + + boot_frame_ = new QFrame(this); + boot_frame_->setObjectName("desktop"); + + boot_panel_ = new QFrame(this); + boot_panel_->setObjectName("boot"); + boot_panel_->setMinimumSize(500, 300); + + layout = new QVBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(boot_panel_); + layout->setAlignment(boot_panel_, Qt::AlignCenter); + boot_frame_->setLayout(layout); + + QFrame *top = new QFrame(this); + top->setObjectName("bootTop"); + + QLabel *logo = new QLabel(this); + logo->setPixmap(QPixmap(":/images/logo.png")); + + welcome_label_ = new QLabel(QString::fromUtf8(language[lsWelcome].c_str()), this); + welcome_label_->setObjectName("version"); + + QLabel *version = new QLabel(QString::fromLatin1(Core::edition()) + " v " + QString::fromLatin1(Core::version()), this); + version->setObjectName("version"); + + QGridLayout *grid_layout = new QGridLayout(); + grid_layout->setContentsMargins(30, 30, 30, 20); + grid_layout->setSpacing(0); + grid_layout->setColumnStretch(1, 1); + grid_layout->addWidget(logo, 0, 0, 2, 1); + grid_layout->addWidget(welcome_label_, 0, 1, Qt::AlignCenter); + grid_layout->addWidget(version, 1, 1, Qt::AlignCenter); + top->setLayout(grid_layout); + + QFrame *line1 = new QFrame(this); + line1->setObjectName("bootHSeparator"); + line1->setFixedHeight(1); + + recent_files_label_ = new QLabel(QString::fromUtf8(language[lsRecentFiles].c_str()), this); + recent_files_label_->setObjectName("boot"); + + quick_start_label_ = new QLabel(QString::fromUtf8(language[lsQuickStart].c_str()), this); + quick_start_label_->setObjectName("boot"); + + QFrame *left = new QFrame(this); + left->setFixedWidth(boot_panel_->minimumSize().width() / 2); + recent_files_layout_ = new QVBoxLayout(); + recent_files_layout_->setContentsMargins(10, 10, 10, 10); + recent_files_layout_->setSpacing(0); + recent_files_layout_->addWidget(recent_files_label_); + recent_files_layout_->addSpacing(10); + recent_files_layout_->addStretch(1); + left->setLayout(recent_files_layout_); + + recent_file_open_act_ = new QAction(QString::fromUtf8(language[lsOpen].c_str()), this); + connect(recent_file_open_act_, SIGNAL(triggered()), this, SLOT(openRecentFile())); + + recent_file_remove_act_ = new QAction(QString::fromUtf8(language[lsDelete].c_str()), this); + connect(recent_file_remove_act_, SIGNAL(triggered()), this, SLOT(removeRecentFile())); + + recent_file_menu_ = new QMenu(this); + recent_file_menu_->addAction(recent_file_open_act_); + recent_file_menu_->addAction(recent_file_remove_act_); + + open_button_ = new QToolButton(this); + open_button_->setObjectName("boot"); + open_button_->setIconSize(QSize(24, 24)); + open_button_->setIcon(QIcon(":/images/boot_open.png")); + open_button_->setText(QString::fromUtf8(language[lsOpen].c_str()) + "..."); + open_button_->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + open_button_->setAutoRaise(true); + open_button_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + connect(open_button_, SIGNAL(clicked(bool)), this, SLOT(open())); + + examples_button_ = new QToolButton(this); + examples_button_->setObjectName("boot"); + examples_button_->setIconSize(QSize(24, 24)); + examples_button_->setIcon(QIcon(":/images/boot_examples.png")); + examples_button_->setText(QString::fromUtf8(language[lsExamples].c_str()) + "..."); + examples_button_->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + examples_button_->setAutoRaise(true); + examples_button_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + connect(examples_button_, SIGNAL(clicked(bool)), this, SLOT(examples())); + + help_button_ = new QToolButton(this); + help_button_->setObjectName("boot"); + help_button_->setIconSize(QSize(24, 24)); + help_button_->setIcon(QIcon(":/images/boot_help.png")); + help_button_->setText(QString::fromUtf8(language[lsHelp].c_str())); + help_button_->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + help_button_->setAutoRaise(true); + help_button_->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + connect(help_button_, SIGNAL(clicked(bool)), this, SLOT(help())); + + QFrame *right = new QFrame(this); + layout = new QVBoxLayout(); + layout->setContentsMargins(10, 10, 10, 10); + layout->setSpacing(0); + layout->addWidget(quick_start_label_); + layout->addSpacing(10); + layout->addWidget(open_button_); + layout->addWidget(examples_button_); + layout->addWidget(help_button_); + layout->addStretch(1); + right->setLayout(layout); + + QFrame *line3 = new QFrame(this); + line3->setObjectName("bootVSeparator"); + line3->setFixedWidth(1); + + QFrame *center = new QFrame(this); + layout = new QHBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(left); + layout->addWidget(line3); + layout->addWidget(right); + center->setLayout(layout); + + layout = new QVBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setSpacing(0); + layout->addWidget(top); + layout->addWidget(line1); + layout->addWidget(center, 1); + boot_panel_->setLayout(layout); + + desktop_page_ = new QStackedWidget(this); + desktop_page_->addWidget(boot_frame_); + desktop_page_->addWidget(project_frame_); + desktop_page_->setCurrentWidget(boot_frame_); + setCentralWidget(desktop_page_); + + connect(QAbstractEventDispatcher::instance(), SIGNAL(awake()), SLOT(updateEditActions())); + connect(&fs_watcher_, SIGNAL(fileChanged(const QString &)), this, SLOT(fileChanged(const QString &))); + + setAcceptDrops(true); + + std::vector<std::string> project_list = settings_file().project_list(); + if (project_list.size() > 10) + project_list.resize(10); + for (int i = 0; i < (int)project_list.size(); i++) { + addRecentFile(i, QString::fromUtf8(project_list[i].c_str())); + } + + localize(); + + QStringList args = QCoreApplication::arguments(); + if (args.length() > 1) { + QString fileName(QFileInfo(args[1]).canonicalFilePath()); + if (fileName.isEmpty()) // no file found -> will use original argument in error message + fileName = args[1]; + loadFile(QDir::toNativeSeparators(fileName)); + } +} + +MainWindow::~MainWindow() +{ + delete core_; + delete log_; +} + +void MainWindow::addRecentFile(int index, const QString file_name) +{ + history_separator_->setVisible(true); + + QAction *action = new QAction(file_name, this); + connect(action, SIGNAL(triggered()), this, SLOT(loadFileFromHistory())); + int file_pos = file_menu_->actions().indexOf(history_separator_) + 1; + file_menu_->insertAction(file_menu_->actions().at(file_pos + index), action); + + QFileInfo fileInfo(file_name); + + QToolButton *button = new QToolButton(this); + button->setObjectName("boot"); + button->setIconSize(QSize(16, 16)); + button->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + button->setAutoRaise(true); + button->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); + button->setText(fileInfo.fileName()); + button->setToolTip(file_name); + button->setContextMenuPolicy(Qt::CustomContextMenu); + connect(button, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(recentFileContextMenu(const QPoint &))); + + QFileIconProvider ip; + QIcon icon = ip.icon(fileInfo); + if (icon.isNull()) + icon = ip.icon(QFileIconProvider::File); + button->setIcon(icon); + connect(button, SIGNAL(clicked(bool)), this, SLOT(loadFileFromBoot())); + + recent_files_layout_->insertWidget(2 + index, button); +} + +void MainWindow::recentFileContextMenu(const QPoint &p) +{ + recent_file_ = -1; + QToolButton *widget = qobject_cast<QToolButton*>(sender()); + if (widget) { + for (int i = 2; i < recent_files_layout_->count(); ++i) { + if (recent_files_layout_->itemAt(i)->widget() == widget) { + recent_file_ = i - 2; + break; + } + } + if (recent_file_ >= 0) { + widget->setDown(true); + recent_file_menu_->exec(qobject_cast<QWidget*>(sender())->mapToGlobal(p)); + if (recent_file_ >= 0) + widget->setDown(false); + } + } +} + +void MainWindow::openRecentFile() +{ + if (recent_file_ < 0) + return; + + QToolButton *button = qobject_cast<QToolButton *>(recent_files_layout_->itemAt(2 + recent_file_)->widget()); + if (button) + loadFile(button->toolTip()); +} + +void MainWindow::removeRecentFile() +{ + if (recent_file_ < 0) + return; + + int file_pos = file_menu_->actions().indexOf(history_separator_) + 1; + QAction *action = file_menu_->actions().at(file_pos + recent_file_); + file_menu_->removeAction(action); + delete action; + + QWidget *widget = recent_files_layout_->itemAt(2 + recent_file_)->widget(); + recent_files_layout_->removeWidget(widget); + delete widget; + + recent_file_ = -1; + + saveRecentFiles(); +} + +void MainWindow::saveRecentFiles() +{ + std::vector<std::string> project_list; + int file_pos = file_menu_->actions().indexOf(history_separator_) + 1; + QList<QAction*> actions = file_menu_->actions(); + for (int i = file_pos; i < actions.size() - 2; i++) { + QAction *action = actions[i]; + project_list.push_back(action->text().toUtf8().constData()); + } + settings_file().set_project_list(project_list); +} + +void MainWindow::localize() +{ + file_menu_->setTitle(QString::fromUtf8(language[lsFile].c_str())); + open_act_->setText(QString::fromUtf8(language[lsOpen].c_str()) + "..."); + save_act_->setText(QString::fromUtf8(language[lsSaveProject].c_str())); + save_as_act_->setText(QString::fromUtf8(language[lsSaveProjectAs].c_str()) + "..."); + close_act_->setText(QString::fromUtf8(language[lsClose].c_str())); + exit_act_->setText(QString::fromUtf8(language[lsExit].c_str())); + project_filter_->setPlaceholderText(QString::fromUtf8(language[lsSearch].c_str())); + + edit_menu_->setTitle(QString::fromUtf8(language[lsEdit].c_str())); + redo_act_->setText(QString::fromUtf8(language[lsRedo].c_str())); + undo_act_->setText(QString::fromUtf8(language[lsUndo].c_str())); + cut_act_->setText(QString::fromUtf8(language[lsCut].c_str())); + copy_act_->setText(QString::fromUtf8(language[lsCopy].c_str())); + paste_act_->setText(QString::fromUtf8(language[lsPaste].c_str())); + exclude_act_->setText(QString::fromUtf8(language[lsExcludedFromCompilation].c_str())); + block_act_->setText(QString::fromUtf8(language[lsBlocked].c_str())); + rename_act_->setText(QString::fromUtf8(language[lsRename].c_str())); + delete_act_->setText(QString::fromUtf8(language[lsDelete].c_str())); + cut_act2_->setText(cut_act_->text()); + copy_act2_->setText(copy_act_->text()); + paste_act2_->setText(paste_act_->text()); + search_act_->setText(QString::fromUtf8(language[lsSearch].c_str())); + + project_menu_->setTitle(QString::fromUtf8(language[lsProject].c_str())); +#ifdef LITE + show_act_->setText(QString::fromUtf8(language[lsShowProtectedFunctions].c_str())); +#else + add_menu_->setTitle(QString::fromUtf8(language[lsAdd].c_str())); + add_function_act_->setText(QString::fromUtf8(language[lsAddFunction].c_str()) + "..."); + add_function_act2_->setText(add_function_act_->text()); + add_folder_act_->setText(QString::fromUtf8(language[lsAddFolder].c_str()) + "..."); + goto_act_->setText(QString::fromUtf8(language[lsGoTo].c_str()) + "..."); + goto_act2_->setText(goto_act_->text()); + templates_act_->setText(QString::fromUtf8(language[lsTemplates].c_str())); + templates_save_act_->setText(QString::fromUtf8(language[lsSaveTemplateAs].c_str()) + "..."); + templates_edit_act_->setText(QString::fromUtf8(language[lsEdit].c_str()) + "..."); + if (templates_menu_->actions().size() > 3) + templates_menu_->actions().at(0)->setText("(" + QString::fromUtf8(language[lsDefault].c_str()) + ")"); +#endif +#ifdef ULTIMATE + save_licenses_act_->setText(QString::fromUtf8(language[lsSaveLicensesAs].c_str()) + "..."); + add_license_act_->setText(QString::fromUtf8(language[lsAddLicense].c_str()) + "..."); + add_file_act_->setText(QString::fromUtf8(language[lsAddFile].c_str()) + "..."); + add_license_act2_->setText(add_license_act_->text()); + add_file_act2_->setText(add_file_act_->text()); + import_menu_->setTitle(QString::fromUtf8(language[lsImport].c_str())); + import_license_act_->setText(QString::fromUtf8(language[lsImportLicenseFromSerialNumber].c_str()) + "..."); + import_project_act_->setText(QString::fromUtf8(language[lsImportLicensesFromProjectFile].c_str()) + "..."); + export_key_act_->setText(QString::fromUtf8(language[lsExportKeyPair].c_str()) + "..."); +#endif + compile_act_->setText(QString::fromUtf8(language[lsCompile].c_str())); + execute_act_->setText(QString::fromUtf8(language[lsExecute].c_str())); + + tools_menu_->setTitle(QString::fromUtf8(language[lsTools].c_str())); +#ifndef LITE + watermarks_act_->setText(QString::fromUtf8(language[lsWatermarks].c_str()) + "..."); +#endif + settings_act_->setText(QString::fromUtf8(language[lsSettings].c_str()) + "..."); + + help_menu_->setTitle(QString::fromUtf8(language[lsHelp].c_str())); + help_act_->setText(QString::fromUtf8(language[lsContents].c_str())); + home_page_act_->setText(QString::fromUtf8(language[lsHomePage].c_str())); + about_act_->setText(QString::fromUtf8(language[lsAbout].c_str()) + "..."); + + icon_project_->setToolTip(QString::fromUtf8(language[lsProject].c_str())); +#ifndef LITE + icon_functions_->setToolTip(QString::fromUtf8(language[lsFunctions].c_str())); + icon_details_->setToolTip(QString::fromUtf8(language[lsDetails].c_str())); +#endif + + function_end_address_act_->setText(QString::fromUtf8(language[lsBreakAddress].c_str())); + function_ext_address_act_->setText(QString::fromUtf8(language[lsExternalAddress].c_str())); + function_del_act_->setText(QString::fromUtf8(language[lsDelete].c_str())); + +#ifdef ULTIMATE + licensing_parameters_help_->setText(QString::fromUtf8(language[lsKeyPairHelp].c_str())); + key_algo_label_->setText(QString::fromUtf8(language[lsKeyPairAlgorithm].c_str())); + key_len_label_->setText(QString::fromUtf8(language[lsKeyLength].c_str())); + create_key_button_->setText(QString::fromUtf8(language[lsGenerate].c_str())); + use_other_project_button_->setText(QString::fromUtf8(language[lsUseOtherProject].c_str())); +#endif + + open_button_->setText(QString::fromUtf8(language[lsOpen].c_str()) + "..."); + examples_button_->setText(QString::fromUtf8(language[lsExamples].c_str()) + "..."); + help_button_->setText(QString::fromUtf8(language[lsHelp].c_str())); + + recent_files_label_->setText(QString::fromUtf8(language[lsRecentFiles].c_str())); + recent_file_open_act_->setText(QString::fromUtf8(language[lsOpen].c_str())); + recent_file_remove_act_->setText(QString::fromUtf8(language[lsDelete].c_str())); + + quick_start_label_->setText(QString::fromUtf8(language[lsQuickStart].c_str())); + welcome_label_->setText(QString::fromUtf8(language[lsWelcome].c_str())); + + function_property_manager_->localize(); + core_property_manager_->localize(); + project_model_->localize(); +#ifndef LITE + info_model_->localize(); + section_property_manager_->localize(); + segment_property_manager_->localize(); + import_property_manager_->localize(); + export_property_manager_->localize(); + resource_property_manager_->localize(); + loadcommand_property_manager_->localize(); + address_calculator_manager_->localize(); +#endif +#ifdef ULTIMATE + license_property_manager_->localize(); + internal_file_property_manager_->localize(); + assembly_property_manager_->localize(); +#endif +} + +void MainWindow::dragEnterEvent(QDragEnterEvent *event) +{ + if (event->mimeData()->hasUrls()) + event->acceptProposedAction(); +} + +void MainWindow::dropEvent(QDropEvent *event) +{ + if (!event->mimeData()->hasUrls()) + return; + + loadFile(QDir::toNativeSeparators(event->mimeData()->urls().at(0).toLocalFile())); +} + +bool MainWindow::internalLoadFile(const QString &filename) +{ + bool res = false; + try { + res = core_->Open(filename.toUtf8().constData()); + } catch(canceled_error &error) { + core_->Notify(mtWarning, NULL, error.what()); + } catch(std::runtime_error &error) { + core_->Notify(mtError, NULL, error.what()); + } + return res; +} + +void MainWindow::loadFile(const QString &filename) +{ + if (!closeFile()) + return; + + boot_panel_->hide(); + { + QFutureWatcher<bool> watcher; + ProgressDialog progress(this); + log_->reset(); + + connect(&watcher, SIGNAL(finished()), &progress, SLOT(reject())); + connect(&progress, SIGNAL(cancel()), log_, SLOT(cancel())); + connect(log_, SIGNAL(startProgress(const QString &, unsigned long long)), &progress, SLOT(startProgress(const QString &, unsigned long long))); + connect(log_, SIGNAL(stepProgress(unsigned long long)), &progress, SLOT(stepProgress(unsigned long long))); + + watcher.setFuture(QtConcurrent::run(this, &MainWindow::internalLoadFile, filename)); + progress.exec(); + watcher.waitForFinished(); + if (!watcher.result()) { + boot_panel_->show(); + return; + } + } + + if (core_->input_file()) + fs_watcher_.addPath(QString::fromUtf8(core_->input_file()->file_name().c_str())); + + QString input_file_name = QDir::toNativeSeparators(QDir::cleanPath(core_->input_file() ? QString::fromUtf8(core_->input_file()->file_name().c_str()) : filename)); + QFileInfo fileInfo(input_file_name); + spacer_->setText(fileInfo.fileName()); + spacer_->setToolTip(input_file_name); + QFileIconProvider ip; + QIcon icon = ip.icon(fileInfo); + if (icon.isNull()) + icon = ip.icon(QFileIconProvider::File); + QPixmap pixmap = icon.pixmap(QSize(20, 20)); + QImage image = pixmap.toImage(); + for (int i = 0; i < pixmap.width(); ++i) { + for (int j = 0; j < pixmap.height(); ++j) { + QRgb col = image.pixel(i, j); + int gray = qGray(col); + image.setPixel(i, j, qRgba(gray, gray, gray, qAlpha(col))); + } + } + QIcon newIcon; + newIcon.addPixmap(pixmap, QIcon::Active, QIcon::Off); + newIcon.addPixmap(QPixmap::fromImage(image), QIcon::Normal, QIcon::Off); + spacer_->setIcon(newIcon); + + IFile *file = core_->input_file(); + if (file) + file->map_function_list()->ReadFromFile(*file); + + bool is_found = false; + QList<QAction*> actions = file_menu_->actions(); + int file_pos = actions.indexOf(history_separator_) + 1; + for (int i = file_pos; i < actions.size() - 2; i++) { + QAction *action = actions[i]; + if (action->text() == filename) { + file_menu_->removeAction(action); + file_menu_->insertAction(file_menu_->actions().at(file_pos), action); + + QWidget *button = recent_files_layout_->itemAt(2 + i - file_pos)->widget(); + recent_files_layout_->removeWidget(button); + recent_files_layout_->insertWidget(2, button); + is_found = true; + break; + } + } + if (!is_found) { + addRecentFile(0, filename); + + if (actions.size() - file_pos - 2 == 10) { + QAction *action = actions[9 + file_pos]; + file_menu_->removeAction(action); + delete action; + } + + if (recent_files_layout_->count() == 14) { + QWidget *widget = recent_files_layout_->itemAt(12)->widget(); + recent_files_layout_->removeWidget(widget); + delete widget; + } + } + + saveRecentFiles(); + + project_model_->setCore(core_); + ProjectNode *options = project_model_->indexToNode(project_model_->optionsIndex()); + if (options) + options->setPropertyManager(core_property_manager_); + project_tree_->setCurrentIndex(project_model_->index(0, 0)); + +#ifndef LITE + functions_model_->setCore(core_); + functions_tree_->setCurrentIndex(functions_model_->index(0, 0)); + + info_model_->setCore(core_); + info_tree_->setCurrentIndex(info_model_->index(0, 0)); +#endif + + script_editor_->setText(QString(core_->script()->text().c_str())); + connect(script_editor_, SIGNAL(notify(SCNotification *)), this, SLOT(scriptNotify(SCNotification *))); + core_property_manager_->setCore(core_); + + desktop_page_->setCurrentWidget(project_frame_); + icon_project_->setChecked(true); + project_tree_->setFocus(); + project_filter_act_->setVisible(true); + save_as_act_->setEnabled(true); + close_act_->setEnabled(true); + search_act_->setEnabled(true); + + bool file_loaded = core_->input_file() != NULL; + compile_act_->setEnabled(file_loaded); +#ifndef LITE + icon_functions_->setVisible(file_loaded); + icon_details_->setVisible(file_loaded); + add_menu_->setEnabled(file_loaded); + add_function_act_->setEnabled(file_loaded); + add_folder_act_->setEnabled(file_loaded); + goto_act_->setEnabled(file_loaded); +#endif + + bool is_executable = core_->input_file() && core_->input_file()->is_executable(); + execute_act_->setEnabled(is_executable); + execute_original_act_->setEnabled(is_executable); + execute_original_act_->setFullText(input_file_name); + execute_menu_->setDefaultAction(execute_original_act_); +#ifdef ULTIMATE + add_file_act_->setEnabled(file_loaded && (core_->input_file()->disable_options() & cpVirtualFiles) == 0); + import_menu_->setEnabled(true); + import_project_act_->setEnabled(true); + updateLicensingActions(); +#endif + projectTabMoved(); + + updateCaption(); +} + +void MainWindow::loadFileFromHistory() +{ + QAction *action = qobject_cast<QAction *>(sender()); + if (action) + loadFile(action->text()); +} + +void MainWindow::loadFileFromBoot() +{ + QToolButton *button = qobject_cast<QToolButton *>(sender()); + if (button) + loadFile(button->toolTip()); +} + +bool MainWindow::closeFile() +{ + if (project_model_->isEmpty()) + return true; + + if (save_act_->isEnabled()) { + switch (MessageDialog::question(this, QString("%1 \"%2\"?").arg(QString::fromUtf8(language[lsSave].c_str())).arg(QString::fromUtf8(core_->project_file_name().c_str())), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Yes)) { + case QMessageBox::Yes: + if (!save()) + return false; + break; + case QMessageBox::No: + // do nothing + break; + default: + return false; + } + } + + fs_watcher_.removePaths(fs_watcher_.files()); + fileChanged_ = false; + + log_model_->clear(); + project_model_->setCore(NULL); + directory_model_->setDirectory(NULL); + search_model_->clear(); + disconnect(script_editor_, SIGNAL(notify(SCNotification *)), this, SLOT(scriptNotify(SCNotification *))); + script_editor_->setText(""); + core_property_manager_->setCore(NULL); + function_property_manager_->setValue(NULL); +#ifndef LITE + functions_model_->setCore(NULL); + info_model_->setCore(NULL); + disasm_model_->setFile(NULL); + dump_model_->setFile(NULL); + section_property_manager_->setValue(NULL); + segment_property_manager_->setValue(NULL); + import_property_manager_->setValue(NULL); + export_property_manager_->setValue(NULL); + resource_property_manager_->setValue(NULL); + loadcommand_property_manager_->setValue(NULL); + address_calculator_manager_->setValue(NULL); +#endif +#ifdef ULTIMATE + license_property_manager_->setValue(NULL); + internal_file_property_manager_->setValue(NULL); + assembly_property_manager_->setValue(NULL); +#endif + if (temp_function_) { + for (size_t i = 0; i < temp_function_->count(); i++) { + delete temp_function_->item(i)->func(); + } + delete temp_function_; + temp_function_ = NULL; + } + core_->Close(); + + spacer_->setFixedWidth(0); + spacer_->setText(""); + spacer_->setToolTip(""); + spacer_->setIcon(QIcon()); + project_filter_act_->setVisible(false); + project_filter_->clear(); + boot_panel_->show(); + desktop_page_->setCurrentWidget(boot_frame_); + save_act_->setEnabled(false); + save_as_act_->setEnabled(false); + close_act_->setEnabled(false); + redo_act_->setEnabled(false); + undo_act_->setEnabled(false); + cut_act_->setEnabled(false); + copy_act_->setEnabled(false); + paste_act_->setEnabled(false); + block_act_->setEnabled(false); + exclude_act_->setEnabled(false); + rename_act_->setEnabled(false); + delete_act_->setEnabled(false); + search_act_->setEnabled(false); + //project_separator_->setVisible(false); + cut_act2_->setVisible(false); + copy_act2_->setVisible(false); + paste_act2_->setVisible(false); +#ifdef LITE + show_act_->setVisible(false); +#else + add_menu_->setEnabled(false); + add_function_act2_->setVisible(false); + goto_act_->setEnabled(false); + goto_act2_->setVisible(false); + add_function_act_->setEnabled(false); + add_folder_act_->setEnabled(false); +#endif + templates_act_->setVisible(false); +#ifdef ULTIMATE + save_licenses_act_->setEnabled(false); + add_license_act2_->setEnabled(false); + add_license_act2_->setVisible(false); + add_file_act2_->setVisible(false); + import_license_act_->setEnabled(false); + import_project_act_->setEnabled(false); + add_license_act_->setEnabled(false); + export_key_act_->setEnabled(false); + import_menu_->setEnabled(false); +#endif + compile_act_->setEnabled(false); + execute_act_->setEnabled(false); + execute_protected_act_->setVisible(false); + updateCaption(); + + return true; +} + +void MainWindow::open() +{ + QString fileName = FileDialog::getOpenFileName(this, QString::fromUtf8(language[lsOpen].c_str()), FileDialog::defaultPath(), + QString("%1 (" +#ifdef VMP_GNU + "*.app *.dylib *.exe *.dll *.bpl *.ocx *.sys *.scr *.so);;%2 (*.vmp);;%3 (*)" +#else + "*.exe *.dll *.bpl *.ocx *.sys *.scr *.dylib *.so);;%2 (*.vmp);;%3 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsExecutableFiles].c_str())).arg(QString::fromUtf8(language[lsProjectFiles].c_str())).arg(QString::fromUtf8(language[lsAllFiles].c_str()))); + + if (fileName.isEmpty()) + return; + + loadFile(fileName); +} + +bool MainWindow::save() +{ + bool ret = core_->Save(); + if (ret) { + save_act_->setEnabled(false); + updateCaption(); + } else { + MessageDialog::critical(this, QString::fromUtf8(string_format(language[lsSaveFileError].c_str(), core_->project_file_name().c_str()).c_str()), QMessageBox::Ok); + } + + return ret; +} + +void MainWindow::saveAs() +{ + QString fileName = FileDialog::getSaveFileName(this, QString::fromUtf8(language[lsSave].c_str()), QString::fromUtf8(core_->project_file_name().c_str()), + QString( +#ifdef VMP_GNU + "%1 (*.vmp);;%2 (*)" +#else + "%1 (*.vmp);;%2 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsProjectFiles].c_str())).arg(QString::fromUtf8(language[lsAllFiles].c_str()))); + + if (fileName.isEmpty()) + return; + + if (core_->SaveAs(fileName.toUtf8().constData())) { + save_act_->setEnabled(false); + updateCaption(); + } else { + MessageDialog::critical(this, QString::fromUtf8(string_format(language[lsSaveFileError].c_str(), fileName.toUtf8().constData()).c_str()), QMessageBox::Ok); + } +} + +void MainWindow::saveLicenses() +{ +#ifdef ULTIMATE + QString fileName = FileDialog::getSaveFileName(this, QString::fromUtf8(language[lsSave].c_str()), QString::fromUtf8(core_->project_file_name().c_str()), + QString( +#ifdef VMP_GNU + "%1 (*.vmp);;%2 (*)" +#else + "%1 (*.vmp);;%2 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsProjectFiles].c_str())).arg(QString::fromUtf8(language[lsAllFiles].c_str()))); + + if (fileName.isEmpty()) + return; + + if (!core_->licensing_manager()->SaveAs(fileName.toUtf8().constData())) { + MessageDialog::critical(this, QString::fromUtf8(string_format(language[lsSaveFileError].c_str(), fileName.toUtf8().constData()).c_str()), QMessageBox::Ok); + return; + } +#endif +} + +void MainWindow::homePage() +{ + QDesktopServices::openUrl(QUrl("http://www.vmpsoft.com")); +} + +void MainWindow::help() +{ + QString keywordId; + ProjectNode *current = currentProjectNode(); + if (current) { + switch (current->type()) { + case NODE_ROOT: + break; + case NODE_OPTIONS: + keywordId = "project::options"; + break; + case NODE_SCRIPT: + case NODE_SCRIPT_BOOKMARK: + keywordId = "project::script"; + break; + case NODE_FILES: + case NODE_FILE: + case NODE_FILE_FOLDER: + case NODE_ASSEMBLIES: + keywordId = "project::files"; + break; + case NODE_LICENSES: + case NODE_LICENSE: + keywordId = "project::licenses"; + break; + case NODE_FUNCTIONS: + case NODE_FUNCTION: + case NODE_FOLDER: + keywordId = "project::functions"; + break; + case NODE_MAP_FUNCTION: + case NODE_MAP_FOLDER: + keywordId = "project::mapfunctions"; + break; + default: + keywordId = "project::details"; + break; + } + } + HelpBrowser::showTopic(keywordId); +} + +void MainWindow::about() +{ + AboutDialog dialog(this); + dialog.exec(); +} + +void MainWindow::examples() +{ +#ifdef VMP_GNU + QString path = QCoreApplication::applicationDirPath() + "/examples"; +#else + wchar_t buf[MAX_PATH]; + QString path; + // ïðèîðèòåòíàÿ ïàïêà, ñþäà äèñòðèáóòèâ ïèøåò + if (SHGetSpecialFolderPathW(0, buf, CSIDL_COMMON_DOCUMENTS, FALSE)) + { + path = QDir::fromNativeSeparators(QString::fromWCharArray(buf)) + "/VMProtect"; + if (!QDir(path).exists()) + path.clear(); + } + if (path.isEmpty()) + { + // åñëè íåñêîëüêî þçåðîâ ðàáîòàþò îäíîâðåìåííî, íàäî êàæäîìó ñêîïèðîâàòü ïàïêó èç CSIDL_COMMON_DOCUMENTS ê ñåáå â äîêóìåíòû, + // à èñõîäíóþ ãðîõíóòü - â èòîãå êàæäûé ðàáîòàåò ñî ñâîèì êàòàëîãîì + path = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first() + "/VMProtect"; + } +#endif + + QString fileName = FileDialog::getOpenFileName(this, QString::fromUtf8(language[lsOpen].c_str()), path, QString("%1 (" +#ifdef VMP_GNU + "*.app *.dylib *.exe *.dll *.bpl *.ocx *.sys *.scr *.so);;%2 (*.vmp);;%3 (*)" +#else + "*.exe *.dll *.bpl *.ocx *.sys *.scr *.dylib *.so);;%2 (*.vmp);;%3 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsExecutableFiles].c_str())).arg(QString::fromUtf8(language[lsProjectFiles].c_str())).arg(QString::fromUtf8(language[lsAllFiles].c_str()))); + + if (fileName.isEmpty()) + return; + + loadFile(fileName); +} + +void MainWindow::watermarks() +{ +#ifndef LITE + WatermarksWindow dialog(false, this); + dialog.exec(); +#endif +} + +void MainWindow::showFile() +{ + QString path = spacer_->toolTip(); +#ifdef __APPLE__ + QStringList scriptArgs; + scriptArgs << QLatin1String("-e") + << QString::fromLatin1("tell application \"Finder\" to reveal POSIX file \"%1\"") + .arg(path); + QProcess::execute(QLatin1String("/usr/bin/osascript"), scriptArgs); + scriptArgs.clear(); + scriptArgs << QLatin1String("-e") + << QLatin1String("tell application \"Finder\" to activate"); + QProcess::execute("/usr/bin/osascript", scriptArgs); +#else +#ifndef VMP_GNU + QString param; + if (!QFileInfo(path).isDir()) + param = QLatin1String("/select,"); + param += QDir::toNativeSeparators(path); + QProcess::startDetached("explorer " + param); +#else + // we cannot select a file here, because no file browser really supports it... + const QString folder = QDir::toNativeSeparators(QFileInfo(path).absoluteDir().absolutePath()); + QDesktopServices::openUrl(QUrl::fromLocalFile(folder)); +#endif +#endif +} + +void MainWindow::settings() +{ + std::string lang_id = settings_file().language(); + SettingsDialog dialog(this); + if (dialog.exec() == QDialog::Accepted) { + if (settings_file().language() != lang_id) + localize(); + } +} + +void MainWindow::closeEvent(QCloseEvent *event) +{ + if (closeFile()) + event->accept(); + else + event->ignore(); +} + +void MainWindow::projectModified() +{ + save_act_->setEnabled(true); + updateCaption(); +} + +void MainWindow::projectNodeRemoved(ProjectNode *node) +{ + directory_model_->removeNode(node); + search_model_->removeNode(node); +} + +void MainWindow::projectObjectRemoved(void *object) +{ + if (function_property_manager_->value() && function_property_manager_->value() == object) + function_property_manager_->setValue(NULL); + log_model_->removeObject(object); +} + +void MainWindow::updateCaption() +{ + QString caption = caption_; + if (!project_model_->isEmpty()) { + QString fileName = QString::fromUtf8(core_->project_file_name().c_str()); + QFileInfo fileInfo(fileName); + caption = QString("%1%2 %3 %4").arg(fileInfo.fileName()).arg(save_act_->isEnabled() ? "*" : "").arg(QString::fromUtf8("\xE2\x80\x94")).arg(caption_); + project_file_name_->setText(fileName); + } else { + project_file_name_->setText(""); + } + setWindowTitle(caption); +} + +QTreeView *MainWindow::currentTreeView() const +{ +#ifdef LITE + return project_tree_; +#else + if (project_tab_->currentWidget() == project_tree_) + return project_tree_; + else if (project_tab_->currentWidget() == functions_tree_) + return functions_tree_; + else + return info_tree_; +#endif +} + +ProjectNode *MainWindow::currentProjectNode(bool focusedTree) const +{ + QTreeView *tree_view = (focusedTree && focusWidget() == directory_tree_ && directory_tree_->selectionModel()->selectedIndexes().count()) ? directory_tree_ : currentTreeView(); + IProjectNodesModel *model = dynamic_cast<IProjectNodesModel *>(tree_view->model()); + return model ? model->indexToNode(tree_view->currentIndex()) : NULL; +} + +void MainWindow::projectItemChanged() +{ + if (project_filter_->text().isEmpty()) + showCurrentObject(); + else + project_filter_->clear(); +} + +void MainWindow::projectFilterChanged() +{ + if (project_filter_->text().isEmpty()) { + showCurrentObject(); + return; + } + + QAbstractItemModel *model = currentTreeView()->model(); + assert(model); + if (model == NULL) return; + + search_model_->search(reinterpret_cast<BaseModel *>(model)->root(), project_filter_->text() +#ifdef LITE + , (show_act_->isVisible() && show_act_->isChecked()) +#endif + ); + project_page_->setCurrentWidget(search_tree_); +} + +void MainWindow::showCurrentObject() +{ + ProjectNode *current = currentProjectNode(); + if (!current) + return; + + cut_act2_->setVisible(current->type() == NODE_SCRIPT || current->type() == NODE_SCRIPT_BOOKMARK); + copy_act2_->setVisible(current->type() == NODE_SCRIPT || current->type() == NODE_SCRIPT_BOOKMARK); + paste_act2_->setVisible(current->type() == NODE_SCRIPT || current->type() == NODE_SCRIPT_BOOKMARK); + script_line_->setVisible(current->type() == NODE_SCRIPT || current->type() == NODE_SCRIPT_BOOKMARK); + script_column_->setVisible(current->type() == NODE_SCRIPT || current->type() == NODE_SCRIPT_BOOKMARK); + script_mode_->setVisible(current->type() == NODE_SCRIPT || current->type() == NODE_SCRIPT_BOOKMARK); + templates_act_->setVisible(current->type() == NODE_OPTIONS); +#ifdef LITE + show_act_->setVisible(current->type() == NODE_FUNCTIONS || current->type() == NODE_MAP_FOLDER); +#else + add_folder_act_->setEnabled(current->type() == NODE_FUNCTIONS || current->type() == NODE_FOLDER || current->type() == NODE_FUNCTION || current->type() == NODE_FILES || current->type() == NODE_FILE_FOLDER || current->type() == NODE_FILE || current->type() == NODE_ASSEMBLIES); + goto_act2_->setVisible(icon_details_->isChecked()); +#endif + +#ifdef LITE + if (show_act_->isVisible() && show_act_->isChecked()) { + ProjectNode *root = reinterpret_cast<BaseModel *>(currentTreeView()->model())->root(); + search_model_->search(root, project_filter_->text(), true); + project_page_->setCurrentWidget(search_tree_); + context_find_->hide(); + return; + } +#endif + + switch (current->type()) { +#ifdef ULTIMATE + case NODE_LICENSES: + { + LicensingManager *licensingManager = static_cast<LicensingManager *>(current->data()); + if (licensingManager->empty()) { + project_page_->setCurrentWidget(licensing_parameters_page_); + break; + } + } +#endif + case NODE_ARCHITECTURE: + case NODE_LOAD_COMMANDS: + case NODE_SEGMENTS: + case NODE_FUNCTIONS: + case NODE_FOLDER: + case NODE_RESOURCES: + case NODE_RESOURCE_FOLDER: + case NODE_IMPORTS: + case NODE_IMPORT: + case NODE_EXPORTS: + case NODE_MAP_FOLDER: + case NODE_IMPORT_FOLDER: + case NODE_EXPORT_FOLDER: + case NODE_FILES: + case NODE_FILE_FOLDER: + case NODE_ASSEMBLIES: + directory_model_->setDirectory(current); + for (int i = 0; i < directory_tree_->header()->count(); i++) { + directory_tree_->header()->resizeSection(i, Application::stylesheetScaleFactor() *((i == 0) ? 240 : 100)); + } + + directory_tree_->header()->setSectionsClickable(current->type() == NODE_FUNCTIONS || current->type() == NODE_FOLDER || current->type() == NODE_FILES || current->type() == NODE_FILE_FOLDER || current->type() == NODE_LICENSES || current->type() == NODE_ASSEMBLIES); + project_page_->setCurrentWidget(directory_tree_); + break; + + case NODE_OPTIONS: + project_page_->setCurrentWidget(core_property_editor_); + break; + +#ifndef LITE + case NODE_SCRIPT: + project_page_->setCurrentWidget(script_editor_); + break; + + case NODE_SCRIPT_BOOKMARK: + project_page_->setCurrentWidget(script_editor_); + script_editor_->setFocus(); + script_editor_->send(SCI_GOTOPOS, project_model_->bookmarkNodeToPos(current)); + break; +#endif + + case NODE_MAP_FUNCTION: + { + MapFunctionBundle *map = static_cast<MapFunctionBundle *>(current->data()); + FunctionBundle *func = core_->input_file()->function_list()->GetFunctionByName(map->name()); + FunctionBundle *old_temp_function = NULL; + if (!func) { + old_temp_function = temp_function_; + temp_function_ = NULL; + func = new FunctionBundle(core_->input_file()->function_list(), map->full_name(), false); + for (size_t i = 0; i < map->count(); i++) { + MapFunctionArch *map_arch = map->item(i); + FunctionArch *func_arch = func->Add(map_arch->arch(), map_arch->arch()->function_list()->CreateFunction()); + func_arch->func()->set_need_compile(false); + func_arch->func()->set_compilation_type(ctVirtualization); + func_arch->func()->ReadFromFile(*map_arch->arch(), map_arch->func()->address()); + } + temp_function_ = func; + } + function_property_manager_->setValue(func); + + if (old_temp_function) { + for (size_t i = 0; i < old_temp_function->count(); i++) { + delete old_temp_function->item(i)->func(); + } + delete old_temp_function; + } + } + project_page_->setCurrentWidget(function_property_editor_); + break; + + case NODE_FUNCTION: + { + FunctionBundle *object = static_cast<FunctionBundle *>(current->data()); + function_property_manager_->setValue(object); + } + project_page_->setCurrentWidget(function_property_editor_); + break; + +#ifndef LITE + case NODE_SEGMENT: + { + ISection *object = static_cast<ISection *>(current->data()); + segment_property_manager_->setValue(object); + } + project_page_->setCurrentWidget(segment_property_editor_); + break; + + case NODE_SECTION: + { + ISection *object = static_cast<ISection *>(current->data()); + section_property_manager_->setValue(object); + } + project_page_->setCurrentWidget(section_property_editor_); + break; + + case NODE_IMPORT_FUNCTION: + { + IImportFunction *object = static_cast<IImportFunction *>(current->data()); + import_property_manager_->setValue(object); + } + project_page_->setCurrentWidget(import_property_editor_); + break; + + case NODE_EXPORT: + { + IExport *object = static_cast<IExport *>(current->data()); + export_property_manager_->setValue(object); + } + project_page_->setCurrentWidget(export_property_editor_); + break; + + case NODE_RESOURCE: + { + IResource *object = static_cast<IResource *>(current->data()); + resource_property_manager_->setValue(object); + } + project_page_->setCurrentWidget(resource_property_editor_); + break; + + case NODE_LOAD_COMMAND: + { + ILoadCommand *object = static_cast<ILoadCommand *>(current->data()); + loadcommand_property_manager_->setValue(object); + } + project_page_->setCurrentWidget(loadcommand_property_editor_); + break; + + case NODE_CALC: + { + IArchitecture *file = static_cast<IArchitecture *>(current->data()); + address_calculator_manager_->setValue(file); + } + project_page_->setCurrentWidget(address_calculator_); + break; + + case NODE_DUMP: + { + IArchitecture *file = static_cast<IArchitecture *>(current->data()); + QModelIndex index = disasm_view_->currentIndex(); + disasm_model_->setFile(file); + if (!index.isValid() && file->entry_point()) + goToDump(file, file->entry_point()); + dump_model_->setFile(file); + } + project_page_->setCurrentWidget(dump_page_); + break; +#endif + +#ifdef ULTIMATE + case NODE_LICENSE: + { + License *object = reinterpret_cast<License *>(current->data()); + license_property_manager_->setValue(object); + } + project_page_->setCurrentWidget(license_property_editor_); + break; + + case NODE_FILE: + if (project_model_->objectToNode(core_->file_manager()->folder_list())->type() == NODE_ASSEMBLIES) { + InternalFile *object = reinterpret_cast<InternalFile *>(current->data()); + assembly_property_manager_->setValue(object); + project_page_->setCurrentWidget(assembly_property_editor_); + } + else { + InternalFile *object = reinterpret_cast<InternalFile *>(current->data()); + internal_file_property_manager_->setValue(object); + project_page_->setCurrentWidget(internal_file_property_editor_); + } + break; +#endif + } + if(!isContextSearchApplicable()) + context_find_->hide(); +} + +void MainWindow::projectContextMenu(const QPoint &p) +{ + ProjectNode *current = currentProjectNode(true); + if (!current) + return; + + QMenu menu; + switch (current->type()) { + case NODE_FUNCTIONS: + case NODE_FUNCTION: + case NODE_FOLDER: +#ifndef LITE + menu.addAction(add_function_act2_); + menu.addAction(add_folder_act_); +#endif + break; +#ifdef ULTIMATE + case NODE_LICENSE: + { + License *object = reinterpret_cast<License *>(current->data()); + block_act_->setChecked(object->blocked()); + } + case NODE_LICENSES: + menu.addAction(add_license_act2_); + break; + case NODE_FILES: + case NODE_FILE_FOLDER: + case NODE_FILE: + case NODE_ASSEMBLIES: + menu.addAction(add_file_act2_); + menu.addAction(add_folder_act_); + break; +#endif + } + + switch (current->type()) { + case NODE_FUNCTION: + case NODE_FOLDER: + case NODE_LICENSE: + case NODE_FILE: + case NODE_FILE_FOLDER: + menu.addSeparator(); + menu.addAction(delete_act_); + if (current->type() != NODE_FUNCTION) + menu.addAction(rename_act_); + break; + } + + switch (current->type()) { + case NODE_LICENSE: + menu.addSeparator(); + menu.addAction(block_act_); + break; + case NODE_FILES: + case NODE_ASSEMBLIES: +#ifdef ULTIMATE + { + FileManager *object = static_cast<FileManager *>(current->data()); + exclude_act_->setChecked(!object->need_compile()); + } +#endif + menu.addSeparator(); + menu.addAction(exclude_act_); + break; + case NODE_FUNCTION: + { + FunctionBundle *object = static_cast<FunctionBundle *>(current->data()); + exclude_act_->setChecked(!object->need_compile()); + } + menu.addSeparator(); + menu.addAction(exclude_act_); + break; + case NODE_SCRIPT: + case NODE_SCRIPT_BOOKMARK: + { + Script *object = static_cast<Script *>(current->data()); + exclude_act_->setChecked(!object->need_compile()); + } + menu.addAction(exclude_act_); + break; + case NODE_MAP_FUNCTION: + { + MapFunctionBundle *map = static_cast<MapFunctionBundle *>(current->data()); + FunctionBundle *func = core_->input_file()->function_list()->GetFunctionByName(map->name()); + exclude_act_->setChecked(func ? !func->need_compile() : true); + } + menu.addAction(exclude_act_); + break; + } + + if (!menu.isEmpty()) + { + rename_act_->setEnabled(current->type() == NODE_FOLDER || current->type() == NODE_LICENSE || current->type() == NODE_FILE_FOLDER || current->type() == NODE_FILE); + block_act_->setEnabled(current->type() == NODE_LICENSE); + exclude_act_->setEnabled(current->type() == NODE_FUNCTION || current->type() == NODE_SCRIPT_BOOKMARK || current->type() == NODE_SCRIPT || current->type() == NODE_FILES || current->type() == NODE_MAP_FUNCTION || current->type() == NODE_ASSEMBLIES); + menu.exec((qobject_cast<QAbstractScrollArea *>(QObject::sender()))->viewport()->mapToGlobal(p)); + } +} + +void MainWindow::scriptContextMenu(const QPoint &p) +{ + script_menu_->exec(script_editor_->viewport()->mapToGlobal(p)); +} + +void MainWindow::functionContextMenu(const QPoint &p) +{ + ICommand *command = function_property_manager_->indexToCommand(function_property_editor_->currentIndex()); + if (command) { + QMenu menu; + menu.addAction(copy_act_); + menu.addSeparator(); + menu.addAction(function_ext_address_act_); + menu.addAction(function_end_address_act_); + menu.exec(function_property_editor_->viewport()->mapToGlobal(p)); + return; + } + + IFunction *func = function_property_manager_->indexToFunction(function_property_editor_->currentIndex()); + if (func) { + QMenu menu; + menu.addAction(function_del_act_); + menu.exec(function_property_editor_->viewport()->mapToGlobal(p)); + return; + } +} + +void MainWindow::functionExtAddress() +{ + ICommand *command = function_property_manager_->indexToCommand(function_property_editor_->currentIndex()); + if (!command) + return; + + ExtCommandList *extCommandList = command->owner()->ext_command_list(); + ExtCommand *extCommand = extCommandList->GetCommandByAddress(command->address()); + if (extCommand) { + delete extCommand; + } else { + extCommandList->Add(command->address()); + } +} + +void MainWindow::functionEndAddress() +{ + ICommand *command = function_property_manager_->indexToCommand(function_property_editor_->currentIndex()); + if (!command) + return; + + IFunction *func = command->owner(); + func->set_break_address(func->is_breaked_address(command->address()) ? 0 : command->address()); +} + +void MainWindow::functionDel() +{ + IFunction *func = function_property_manager_->indexToFunction(function_property_editor_->currentIndex()); + if (func) + delete func; +} + +void MainWindow::treeItemDoubleClicked(const QModelIndex &index) +{ + ProjectNode *current = static_cast<ProjectNode *>(index.internalPointer()); + if (!current) + return; + + QString term; + if (project_page_->currentWidget() == search_tree_) { + term = project_filter_->text(); + project_filter_->clear(); + } + + QTreeView *tree_view = currentTreeView(); + BaseModel *model = reinterpret_cast<BaseModel*>(tree_view->model()); + assert(model); + if (model == NULL) return; + + if (current->type() == NODE_PROPERTY) { + Property *prop = static_cast<Property *>(current->data()); + Property *root = prop; + while (root && root->parent()) { + root = root->parent(); + } + if (core_property_manager_->root() == root) { + current = project_model_->indexToNode(project_model_->optionsIndex()); + core_property_editor_->setCurrentIndex(core_property_manager_->propertyToIndex(prop)); + } + } + + tree_view->setCurrentIndex(reinterpret_cast<BaseModel*>(model)->nodeToIndex(current)); + + if (!term.isEmpty() && (current->type() == NODE_SCRIPT || current->type() == NODE_SCRIPT_BOOKMARK)) + context_find_->showAndClear(term); +} + +void MainWindow::notify(MessageType type, IObject *sender, const QString &message) +{ + if (sender) { + if (Watermark *watermark = dynamic_cast<Watermark *>(sender)) { + switch (type) { + case mtAdded: + watermarks_model_->addWatermark(watermark); + break; + case mtChanged: + watermarks_model_->updateWatermark(watermark); + break; + case mtDeleted: + watermarks_model_->removeWatermark(watermark); + break; + } + return; + } + if (ProjectTemplate *pt = dynamic_cast<ProjectTemplate *>(sender)) { + switch (type) { + case mtAdded: + templates_model_->addTemplate(pt); + break; + case mtChanged: + templates_model_->updateTemplate(pt); + break; + case mtDeleted: + templates_model_->removeTemplate(pt); + break; + } + updateTemplates(); + return; + } + } + + if (project_model_->isEmpty()) { + QApplication::restoreOverrideCursor(); + switch (type) { + case mtError: + MessageDialog::critical(this, message, QMessageBox::Ok); + break; + case mtWarning: + MessageDialog::warning(this, message, QMessageBox::Ok); + break; + case mtInformation: + MessageDialog::information(this, message, QMessageBox::Ok); + break; + } + return; + } + + QString add; + if (sender) { + if (dynamic_cast<Core *>(sender)) { + core_property_manager_->update(); + projectModified(); + } else if (IFunction *func = dynamic_cast<IFunction *>(sender)) { + switch (type) { + case mtAdded: + project_model_->addFunction(func); +#ifndef LITE + functions_model_->updateFunction(func); +#endif + function_property_manager_->addFunction(func); + break; + case mtChanged: + if (temp_function_ && temp_function_->GetArchByFunction(func)) { + for (size_t i = 0; i < temp_function_->count(); i++) { + FunctionArch *func_arch = temp_function_->item(i); + IFunction *func_src = func_arch->func(); + IFunction *func_dst = func_arch->arch()->function_list()->AddByAddress(func_src->address(), temp_function_->compilation_type(), temp_function_->compilation_options(), temp_function_->need_compile(), NULL); + if (func_dst) { + func_dst->set_break_address(func_src->break_address()); + for (size_t i = 0; i < func_src->ext_command_list()->count(); i++) { + func_dst->ext_command_list()->Add(func_src->ext_command_list()->item(i)->address()); + } + } + } + } + function_property_manager_->updateFunction(func); + project_model_->updateFunction(func); +#ifndef LITE + functions_model_->updateFunction(func); +#endif + break; + case mtDeleted: + { + bool needUpdate = function_property_manager_->removeFunction(func); + if (temp_function_) { + FunctionArch *func_arch = temp_function_->GetArchByFunction(func); + if (func_arch) + delete func_arch; + } + project_model_->removeFunction(func); + if (needUpdate) + function_property_manager_->update(); +#ifndef LITE + functions_model_->removeFunction(func); +#endif + } + break; + default: + { + IArchitecture *arch = func->owner()->owner(); + if (core_->input_file()->IndexOf(arch) == NOT_ID) { + sender = NULL; + arch = core_->input_file()->GetArchitectureByName(arch->name()); + if (arch) + sender = (func->type() == otUnknown) ? arch->function_list()->GetUnknownByName(func->name()) : arch->function_list()->GetFunctionByAddress(func->address()); + } + } + break; + } + } else if (Folder *folder = dynamic_cast<Folder *>(sender)) { + switch (type) { + case mtAdded: + project_model_->addFolder(folder); + break; + case mtChanged: + project_model_->updateFolder(folder); + break; + case mtDeleted: + project_model_->removeFolder(folder); + break; + } + } +#ifdef ULTIMATE + else if (License *license = dynamic_cast<License *>(sender)) { + switch (type) { + case mtAdded: + project_model_->addLicense(license); + break; + case mtChanged: + project_model_->updateLicense(license); + if (license_property_manager_->value() == license) + license_property_manager_->update(); + break; + case mtDeleted: + project_model_->removeLicense(license); + if (license_property_manager_->value() == license) + license_property_manager_->setValue(NULL); + break; + } + } else if (FileFolder *folder = dynamic_cast<FileFolder *>(sender)) { + switch (type) { + case mtAdded: + project_model_->addFileFolder(folder); + break; + case mtChanged: + project_model_->updateFileFolder(folder); + break; + case mtDeleted: + project_model_->removeFileFolder(folder); + break; + } + } else if (InternalFile *file = dynamic_cast<InternalFile *>(sender)) { + switch (type) { + case mtAdded: + project_model_->addFile(file); + break; + case mtChanged: + project_model_->updateFile(file); + if (internal_file_property_manager_->value() == file) + internal_file_property_manager_->update(); + else if (assembly_property_manager_->value() == file) + assembly_property_manager_->update(); + break; + case mtDeleted: + project_model_->removeFile(file); + if (internal_file_property_manager_->value() == file) + internal_file_property_manager_->update(); + else if (assembly_property_manager_->value() == file) + assembly_property_manager_->update(); + break; + } + } else if (/*LicensingManager *licensingManager = */dynamic_cast<LicensingManager *>(sender)) { + if (type == mtChanged) { + updateLicensingActions(); + core_property_manager_->update(); + projectModified(); + ProjectNode *current = currentProjectNode(); + if (current && current->type() == NODE_LICENSES) + showCurrentObject(); + } + } else if (dynamic_cast<FileManager *>(sender)) { + project_model_->updateFiles(); + projectModified(); + } +#endif + else if (dynamic_cast<Script *>(sender)) { + if (type == mtChanged) { + project_model_->updateScript(); + projectModified(); + } + } else if (ExtCommand *extCommand = dynamic_cast<ExtCommand *>(sender)) { + if (!extCommand->owner()) + return; + + IFunction *func = extCommand->owner()->owner(); + if (temp_function_ && temp_function_->GetArchByFunction(func)) + notify(mtChanged, func, ""); + + project_model_->updateFunction(func); + if (function_property_manager_->value() && function_property_manager_->value()->GetArchByFunction(func)) + function_property_manager_->update(); + } else if (ICommand *command = dynamic_cast<ICommand *>(sender)) { + IFunction *func = command->owner(); + IArchitecture *arch = func->owner()->owner(); + + std::string func_name = func->display_name(); + if (!func_name.empty()) + func_name += "."; + add = QString::fromUtf8(string_format("%s%.8llX: ", func_name.c_str(), command->address()).c_str()); + if (core_->input_file()->IndexOf(arch) == NOT_ID) { + sender = NULL; + arch = core_->input_file()->GetArchitectureByName(arch->name()); + if (arch) + sender = (func->type() == otUnknown) ? arch->function_list()->GetFunctionByName(func->name()) : arch->function_list()->GetFunctionByAddress(func->address()); + } else { + sender = func; + } + } +#ifndef LITE + else if (IResource *resource = dynamic_cast<IResource *>(sender)) { + switch (type) { + case mtChanged: + info_model_->updateResource(resource); + if (resource_property_manager_->value() == resource) + resource_property_manager_->update(); + break; + } + } else if (ISection *section = dynamic_cast<ISection *>(sender)) { + switch (type) { + case mtChanged: + info_model_->updateSegment(section); + if (segment_property_manager_->value() == section) + segment_property_manager_->update(); + break; + } + } else if (IImport *import = dynamic_cast<IImport *>(sender)) { + switch (type) { + case mtChanged: + info_model_->updateImport(import); + break; + } + } +#endif + } + + if (type == mtInformation || type == mtWarning || type == mtError || type == mtScript) + log_model_->addMessage(type, sender, add + message); +} + +void MainWindow::projectTabClicked() +{ +#ifdef LITE + icon_project_->setChecked(true); +#else + if (icon_details_->isChecked()) + project_tab_->setCurrentWidget(info_tree_); + else if (icon_functions_->isChecked()) + project_tab_->setCurrentWidget(functions_tree_); + else +#endif + project_tab_->setCurrentWidget(project_tree_); +} + +void MainWindow::projectTabMoved() +{ + spacer_->setFixedWidth((spacer_->width() > project_separator_widget_->pos().x() ? 0 : spacer_->width()) + project_tab_->width() + icon_project_->width() - project_separator_widget_->pos().x()); +} + +void MainWindow::scriptNotify(SCNotification *notification) +{ + switch (notification->nmhdr.code) { + case SCN_MODIFIED: + if (notification->modificationType & (SC_MOD_INSERTTEXT | SC_MOD_DELETETEXT)) { + core_->script()->set_text(script_editor_->text().toUtf8().constData()); + projectModified(); +#ifndef LITE + project_model_->updateScriptBookmarks(); +#endif + } + break; + + case SCN_UPDATEUI: + undo_act_->setEnabled(script_editor_->canUndo()); + redo_act_->setEnabled(script_editor_->canRedo()); + cut_act_->setEnabled(script_editor_->hasSelection()); + copy_act_->setEnabled(script_editor_->hasSelection()); + paste_act_->setEnabled(script_editor_->canPaste()); + + cut_act2_->setEnabled(cut_act_->isEnabled()); + copy_act2_->setEnabled(copy_act_->isEnabled()); + paste_act2_->setEnabled(paste_act_->isEnabled()); + + script_line_->setText(QString("Ln: %1").arg(script_editor_->currentPos().y() + 1)); + script_column_->setText(QString("Col: %2").arg(script_editor_->currentPos().x() + 1)); + script_mode_->setText(script_editor_->getOverType() ? "OVR" : "INS"); + + script_editor_->hilightView(); + break; + + case SCN_CHARADDED: + script_editor_->maintainIndentation(notification->ch); + break; + } +} + +void MainWindow::scriptModeClicked() +{ + script_editor_->setOverType(!script_editor_->getOverType()); + script_mode_->setText(script_editor_->getOverType() ? "OVR" : "INS"); +} + +void MainWindow::undo() +{ + QWidget *widget = focusWidget(); + if (widget == script_editor_) + script_editor_->undo(); + else if (QLineEdit *edit = qobject_cast<QLineEdit *>(widget)) + edit->undo(); + else if (QPlainTextEdit *edit = qobject_cast<QPlainTextEdit *>(widget)) + edit->undo(); + else if (QComboBox *comboBox = qobject_cast<QComboBox *>(widget)) + comboBox->lineEdit()->undo(); +} + +void MainWindow::redo() +{ + QWidget *widget = focusWidget(); + if (widget == script_editor_) + script_editor_->redo(); + else if (QLineEdit *edit = qobject_cast<QLineEdit *>(widget)) + edit->redo(); + else if (QPlainTextEdit *edit = qobject_cast<QPlainTextEdit *>(widget)) + edit->redo(); + else if (QComboBox *comboBox = qobject_cast<QComboBox *>(widget)) + comboBox->lineEdit()->redo(); +} + +void MainWindow::copy() +{ + QWidget *widget = focusWidget(); + if (widget == script_editor_) + script_editor_->copy(); + else if (QLineEdit *edit = qobject_cast<QLineEdit *>(widget)) + edit->copy(); + else if (QPlainTextEdit *edit = qobject_cast<QPlainTextEdit *>(widget)) + edit->copy(); + else if (QComboBox *comboBox = qobject_cast<QComboBox *>(widget)) + comboBox->lineEdit()->copy(); +#ifdef ULTIMATE + else if (widget == license_property_editor_ && license_property_manager_->indexToProperty(license_property_editor_->currentIndex()) == license_property_manager_->serialNumber()) + QApplication::clipboard()->setText(license_property_manager_->serialNumber()->value()); +#endif + else if (TreeView *tree = dynamic_cast<TreeView *>(widget)) + tree->copy(); + else if (TableView *table = dynamic_cast<TableView *>(widget)) + table->copy(); +} + +void MainWindow::cut() +{ + QWidget *widget = focusWidget(); + if (widget == script_editor_) + script_editor_->cut(); + else if (QLineEdit *edit = qobject_cast<QLineEdit *>(widget)) + edit->cut(); + else if (QPlainTextEdit *edit = qobject_cast<QPlainTextEdit *>(widget)) + edit->cut(); + else if (QComboBox *comboBox = qobject_cast<QComboBox *>(widget)) + comboBox->lineEdit()->cut(); +} + +void MainWindow::paste() +{ + QWidget *widget = focusWidget(); + if (widget == script_editor_) + script_editor_->paste(); + else if (QLineEdit *edit = qobject_cast<QLineEdit *>(widget)) + edit->paste(); + else if (QPlainTextEdit *edit = qobject_cast<QPlainTextEdit *>(widget)) + edit->paste(); + else if (QComboBox *comboBox = qobject_cast<QComboBox *>(widget)) + comboBox->lineEdit()->paste(); +} + +void MainWindow::addFunction() +{ + FunctionDialog dialog(core_->input_file(), NULL, smAddFunction, this); + + if (dialog.exec() == QDialog::Accepted) { + QList<AddressInfo> addresses = dialog.addresses(); + CompilationType compilationType = dialog.compilationType(); + uint32_t compilationOptions = dialog.compilationOptions(); + if (addresses.isEmpty()) + return; + + ProjectNode *node = currentProjectNode(); + assert(node); + if (node == NULL) return; + + while (node->type() == NODE_FUNCTION) { + node = node->parent(); + } + Folder *folder = (node->type() == NODE_FOLDER) ? reinterpret_cast<Folder *>(node->data()) : NULL; + + WaitCursor wc; + /* + if (addresses.size() > 1) + ProgressDialog::Start((language[lsLoading] + "...").c_str(), addresses.size()); + + + IFile *file = core_->input_file();*/ + IFunction *func = NULL; + for (int i = 0; i < addresses.size(); i++) { + //ProgressDialog::Step(1); + AddressInfo info = addresses[i]; + IFunction *tmp = info.arch->function_list()->AddByAddress(info.address, compilationType, compilationOptions, true, folder); + if (!func) + func = tmp; + } + //ProgressDialog::End(); + + if (func) + project_tree_->setCurrentIndex(project_model_->objectToIndex(func)); + } +} + +void MainWindow::addFolder() +{ + ProjectNode *node = currentProjectNode(); + assert(node); + if (node == NULL) return; + + switch (node->type()) { + case NODE_FUNCTIONS: + case NODE_FOLDER: + case NODE_FUNCTION: + addFunctionFolder(); + break; + case NODE_FILES: + case NODE_FILE_FOLDER: + case NODE_FILE: + case NODE_ASSEMBLIES: + addFileFolder(); + break; + } +} + +void MainWindow::addFunctionFolder() +{ + ProjectNode *node = currentProjectNode(); + assert(node); + if (node == NULL) return; + + while (node->type() == NODE_FUNCTION) { + node = node->parent(); + } + + Folder *parent = (node->type() == NODE_FOLDER) ? reinterpret_cast<Folder *>(node->data()) : core_->input_file()->folder_list(); + + QModelIndex index = project_model_->objectToIndex(parent->Add("")); + project_tree_->setCurrentIndex(index); + project_tree_->edit(index); +} + +#ifdef ULTIMATE +void MainWindow::updateLicensingActions() +{ + bool is_ok = !core_->licensing_manager()->empty(); + save_licenses_act_->setEnabled(is_ok); + export_key_act_->setEnabled(is_ok); + import_license_act_->setEnabled(is_ok); + add_license_act_->setEnabled(is_ok); + add_license_act2_->setEnabled(is_ok); +} + +void MainWindow::createLicense(License *license) +{ + LicenseDialog dialog(core_->licensing_manager(), license, this); + + if (dialog.exec() == QDialog::Accepted) { + license = dialog.license(); + project_tree_->setCurrentIndex(project_model_->objectToIndex(license)); + } +} +#endif + +void MainWindow::addLicense() +{ +#ifdef ULTIMATE + createLicense(NULL); +#endif +} + +void MainWindow::createKeyPair() +{ +#ifdef ULTIMATE + WaitCursor wc; + core_->licensing_manager()->Init(key_len_->currentText().toInt()); +#endif +} + +void MainWindow::exportKeyPair() +{ +#ifdef ULTIMATE + ExportKeyPairDialog dialog(this, core_->licensing_manager()); + + dialog.exec(); +#endif +} + +void MainWindow::useOtherProject() +{ +#ifdef ULTIMATE + QString fileName = FileDialog::getOpenFileName(this, QString::fromUtf8(language[lsOpen].c_str()), FileDialog::defaultPath(), + QString( +#ifdef VMP_GNU + "%1 (*.vmp);;%2 (*)" +#else + "%1 (*.vmp);;%2 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsProjectFiles].c_str())).arg(QString::fromUtf8(language[lsAllFiles].c_str()))); + + if (fileName.isEmpty()) + return; + + LicensingManager manager; + if (!manager.Open(fileName.toUtf8().constData())) { + MessageDialog::critical(this, QString::fromUtf8(string_format(language[lsOpenFileError].c_str(), fileName.toUtf8().constData()).c_str()), QMessageBox::Ok); + return; + } + + if (manager.algorithm() != alRSA) { + MessageDialog::critical(this, QString("The license data not found in the file \"%1\"").arg(fileName), QMessageBox::Ok); + return; + } + + core_->set_license_data_file_name(fileName.toUtf8().constData()); +#endif +} + +void MainWindow::importLicense() +{ +#ifdef ULTIMATE + ImportLicenseDialog dialog(this); + + if (dialog.exec() == QDialog::Accepted) { + std::string serialNumber = dialog.serial().toLatin1().constData(); + LicensingManager *licensingManager = core_->licensing_manager(); + License *license = licensingManager->GetLicenseBySerialNumber(serialNumber); + if (!license) { + LicenseInfo licenseInfo; + if (!licensingManager->DecryptSerialNumber(serialNumber, licenseInfo)) { + MessageDialog::critical(this, QString::fromUtf8(language[lsImportSerialNumberError].c_str()), QMessageBox::Ok); + return; + } + QDate date = QDate::currentDate(); + license = licensingManager->Add(LicenseDate(date.year(), date.month(), date.day()), + licenseInfo.CustomerName, + licenseInfo.CustomerEmail, + "", + "", + serialNumber, + false); + } + project_tree_->setCurrentIndex(project_model_->objectToIndex(license)); + } +#endif +} + +void MainWindow::importProject() +{ +#ifdef ULTIMATE + QString fileName = FileDialog::getOpenFileName(this, QString::fromUtf8(language[lsOpen].c_str()), FileDialog::defaultPath(), + QString( +#ifdef VMP_GNU + "%1 (*.vmp);;%2 (*)" +#else + "%1 (*.vmp);;%2 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsProjectFiles].c_str())).arg(QString::fromUtf8(language[lsAllFiles].c_str()))); + if (fileName.isEmpty()) + return; + + LicensingManager manager; + if (!manager.Open(fileName.toUtf8().constData())) { + MessageDialog::critical(this, QString::fromUtf8(string_format(language[lsOpenFileError].c_str(), fileName.toUtf8().constData()).c_str()), QMessageBox::Ok); + return; + } + + if (manager.algorithm() != alRSA) { + MessageDialog::critical(this, QString("The licensing parameters are not found in the file \"%1\"").arg(fileName), QMessageBox::Ok); + return; + } + + if (!core_->licensing_manager()->CompareParameters(manager)) { + MessageDialog::critical(this, QString::fromUtf8(language[lsImportLicensesError].c_str()), QMessageBox::Ok); + return; + } + + size_t c = 0; + size_t b = 0; + for (size_t i = 0; i < manager.count(); i++) { + License *src_license = manager.item(i); + License *dst_license = core_->licensing_manager()->GetLicenseBySerialNumber(src_license->serial_number()); + if (dst_license) { + if (!dst_license->blocked() && src_license->blocked()) { + dst_license->set_blocked(src_license->blocked()); + b++; + } + } else { + /*dst_license =*/ core_->licensing_manager()->Add(src_license->date(), + src_license->customer_name(), + src_license->customer_email(), + src_license->order_ref(), + src_license->comments(), + src_license->serial_number(), + src_license->blocked()); + c++; + } + } + MessageDialog::information(this, QString::fromUtf8(string_format(language[lsImportLicensesResult].c_str(), c, b).c_str()), QMessageBox::Ok); +#endif +} + +void MainWindow::addFileFolder() +{ +#ifdef ULTIMATE + ProjectNode *node = currentProjectNode(); + assert(node); + if (node == NULL) return; + + while (node->type() == NODE_FILE) { + node = node->parent(); + } + + FileFolder *parent = (node->type() == NODE_FILE_FOLDER) ? reinterpret_cast<FileFolder *>(node->data()) : core_->file_manager()->folder_list(); + + QModelIndex index = project_model_->objectToIndex(parent->Add("")); + project_tree_->setCurrentIndex(index); + project_tree_->edit(index); +#endif +} + +void MainWindow::addFile() +{ +#ifdef ULTIMATE + QString filter; + if (project_model_->objectToNode(core_->file_manager()->folder_list())->type() == NODE_ASSEMBLIES) { + filter = QString( + "%1 (*.dll);;%2 (*.*)" + ).arg(QString::fromUtf8(language[lsAssemblies].c_str())).arg(QString::fromUtf8(language[lsAllFiles].c_str())); + } + else { + filter = QString( +#ifdef VMP_GNU + "%1 (*)" +#else + "%1 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsAllFiles].c_str())); + } + + QString fileName = FileDialog::getOpenFileName(this, QString::fromUtf8(language[lsOpen].c_str()), FileDialog::defaultPath(), filter); + if (fileName.isEmpty()) + return; + + QString tmp = QDir(QString::fromUtf8(core_->project_path().c_str())).relativeFilePath(fileName); + if (tmp.mid(0, 2) != "..") + fileName = tmp; + + ProjectNode *node = currentProjectNode(); + while (node->type() == NODE_FILE) { + node = node->parent(); + } + FileFolder *folder = (node->type() == NODE_FILE_FOLDER) ? reinterpret_cast<FileFolder *>(node->data()) : NULL; + + FileManager *file_manager = core_->file_manager(); + InternalFile *file = file_manager->Add(QFileInfo(fileName).fileName().toUtf8().constData(), fileName.toUtf8().constData(), faNone, folder); + if (file) + project_tree_->setCurrentIndex(project_model_->objectToIndex(file)); +#endif +} + +void MainWindow::rename() +{ + QTreeView *tree_view = qobject_cast<QTreeView *>(focusWidget()); + if (tree_view) + tree_view->edit(tree_view->currentIndex()); +} + +void MainWindow::excludeFromCompilation() +{ + ProjectNode *node = currentProjectNode(true); + if (!node) + return; + + switch (node->type()) { + case NODE_FUNCTION: + { + FunctionBundle *object = reinterpret_cast<FunctionBundle *>(node->data()); + object->set_need_compile(!object->need_compile()); + } + break; + case NODE_SCRIPT: + case NODE_SCRIPT_BOOKMARK: + { + Script *object = reinterpret_cast<Script *>(node->data()); + object->set_need_compile(!object->need_compile()); + } + break; +#ifdef ULTIMATE + case NODE_FILES: + case NODE_ASSEMBLIES: + { + FileManager *object = reinterpret_cast<FileManager *>(node->data()); + object->set_need_compile(!object->need_compile()); + } + break; +#endif + case NODE_MAP_FUNCTION: + { + MapFunctionBundle *object = static_cast<MapFunctionBundle *>(node->data()); + FunctionBundle *func = core_->input_file()->function_list()->GetFunctionByName(object->name()); + if (func) { + func->set_need_compile(!func->need_compile()); + } else { + for (size_t i = 0; i < object->count(); i++) { + MapFunctionArch *map_arch = object->item(i); + map_arch->arch()->function_list()->AddByAddress(map_arch->func()->address(), ctVirtualization, 0, true, NULL); + } + } + } + break; + } +} + +void MainWindow::block() +{ +#ifdef ULTIMATE + ProjectNode *node = currentProjectNode(true); + if (!node) + return; + + switch (node->type()) { + case NODE_LICENSE: + { + License *license = reinterpret_cast<License *>(node->data()); + license->set_blocked(!license->blocked()); + } + break; + } +#endif +} + +void MainWindow::del() +{ + ProjectNode *node = currentProjectNode(true); + if (!node) + return; + + switch (node->type()) { + case NODE_SCRIPT: + case NODE_SCRIPT_BOOKMARK: + script_editor_->del(); + break; + case NODE_FOLDER: + { + Folder *folder = reinterpret_cast<Folder *>(node->data()); + if (MessageDialog::question(this, QString::fromUtf8(language[lsDeleteFolder].c_str()) + "?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + delete folder; + } + break; + case NODE_FUNCTION: + { + FunctionBundle *func = reinterpret_cast<FunctionBundle *>(node->data()); + if (MessageDialog::question(this, QString::fromUtf8(language[lsDeleteFunction].c_str()) + "?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + for (size_t i = func->count(); i > 0; i--) { + delete func->item(i - 1)->func(); + } + } + } + break; +#ifdef ULTIMATE + case NODE_LICENSE: + { + License *license = reinterpret_cast<License *>(node->data()); + if (MessageDialog::question(this, QString::fromUtf8(language[lsDeleteLicense].c_str()) + "?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + delete license; + } + break; + case NODE_FILE_FOLDER: + { + FileFolder *folder = reinterpret_cast<FileFolder *>(node->data()); + if (MessageDialog::question(this, QString::fromUtf8(language[lsDeleteFolder].c_str()) + "?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + delete folder; + } + break; + case NODE_FILE: + { + InternalFile *file = reinterpret_cast<InternalFile *>(node->data()); + if (MessageDialog::question(this, QString::fromUtf8(language[lsDeleteFile].c_str()) + "?", QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + delete file; + } + break; +#endif + default: + { + QWidget *widget = focusWidget(); + if (QLineEdit *edit = qobject_cast<QLineEdit *>(widget)) + edit->del(); + else if (QPlainTextEdit *edit = qobject_cast<QPlainTextEdit *>(widget)) + edit->textCursor().removeSelectedText(); + else if (QComboBox *comboBox = qobject_cast<QComboBox *>(widget)) + comboBox->lineEdit()->del(); + } + } +} + +bool MainWindow::internalCompile() +{ + bool res = false; + try { + res = core_->Compile(); + if (res && QFileInfo(QString::fromUtf8(core_->input_file()->file_name().c_str())) == QFileInfo(QString::fromUtf8(core_->absolute_output_file_name().c_str()))) + fileChanged_ = false; + } catch(canceled_error &error) { + core_->Notify(mtWarning, NULL, error.what()); + } catch(std::runtime_error &error) { + core_->Notify(mtError, NULL, error.what()); + } + return res; +} + +void MainWindow::compile() +{ + log_model_->clear(); + + { + QFutureWatcher<bool> watcher; + ProgressDialog progress(this); + log_->reset(); + + connect(&watcher, SIGNAL(finished()), &progress, SLOT(reject())); + connect(&progress, SIGNAL(cancel()), log_, SLOT(cancel())); + connect(log_, SIGNAL(startProgress(const QString &, unsigned long long)), &progress, SLOT(startProgress(const QString &, unsigned long long))); + connect(log_, SIGNAL(stepProgress(unsigned long long)), &progress, SLOT(stepProgress(unsigned long long))); + + disconnect(log_, SIGNAL(notify(MessageType, IObject *, const QString &)), this, SLOT(notify(MessageType, IObject *, const QString &))); + connect(log_, SIGNAL(notify(MessageType, IObject *, const QString &)), this, SLOT(notify(MessageType, IObject *, const QString &)), Qt::BlockingQueuedConnection); + + watcher.setFuture(QtConcurrent::run(this, &MainWindow::internalCompile)); + progress.exec(); + watcher.waitForFinished(); + + disconnect(log_, SIGNAL(notify(MessageType, IObject *, const QString &)), this, SLOT(notify(MessageType, IObject *, const QString &))); + connect(log_, SIGNAL(notify(MessageType, IObject *, const QString &)), this, SLOT(notify(MessageType, IObject *, const QString &))); + + if (!watcher.result()) + return; + } + + if (save_act_->isEnabled() && settings_file().auto_save_project()) + save(); + + if (execute_act_->isEnabled()) { + execute_protected_act_->setFullText(QString::fromUtf8(core_->absolute_output_file_name().c_str())); + execute_protected_act_->setVisible(true); + execute_menu_->setDefaultAction(execute_protected_act_); + + if (MessageDialog::question(this, QString("%1.\n%2 \"%3\"?").arg(QString::fromUtf8(language[lsCompiled].c_str())).arg(QString::fromUtf8(language[lsExecute].c_str())).arg(execute_protected_act_->getFullText()), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + executeProtected(); + } else { + MessageDialog::information(this, QString::fromUtf8(language[lsCompiled].c_str()), QMessageBox::Ok); + } +} + +void MainWindow::execute() +{ + if (execute_protected_act_->isVisible()) + executeProtected(); + else + executeOriginal(); +} + +void MainWindow::executeOriginal() +{ + executeFile(execute_original_act_->getFullText()); +} + +void MainWindow::executeProtected() +{ + executeFile(execute_protected_act_->getFullText()); +} + +void MainWindow::executeFile(const QString &fileName) +{ + QString commandLine = parameters_edit_->text().trimmed(); +#ifdef VMP_GNU + QStringList arguments; + if (!commandLine.isEmpty()) + arguments << commandLine; + QProcess::startDetached(fileName, arguments, QFileInfo(fileName).absolutePath()); +#else + QString execCommand; + if (core_->input_file()) + execCommand = QString::fromUtf8(core_->input_file()->exec_command().c_str()); + if (execCommand.isEmpty()) + ShellExecuteW(0, L"open", (LPCWSTR)fileName.utf16(), (LPCWSTR)commandLine.utf16(), (LPCWSTR)QFileInfo(fileName).absolutePath().utf16(), SW_SHOWNORMAL); + else + ShellExecuteW(0, L"open", (LPCWSTR)execCommand.utf16(), (LPCWSTR)(fileName + " " + commandLine).utf16(), (LPCWSTR)QFileInfo(fileName).absolutePath().utf16(), SW_SHOWNORMAL); +#endif +} + +#ifndef LITE +static int luaErrGetLineNumber(const QString &text) +{ + int line = -1; + bool afterFirstSemicolon = false; + for(int pos = 0; pos < text.length(); pos++) + { + QChar ch = text.at(pos); + if(afterFirstSemicolon) + { + if(ch.isDigit()) + { + if(line < 0) + line = 0; + line = 10 * line + ch.digitValue(); + } else + { + break; + } + } else if(ch.toLatin1() == ':') + { + afterFirstSemicolon = true; + } + } + return line; +} +#endif + +void MainWindow::logItemDoubleClicked(const QModelIndex &index) +{ + ProjectNode *current = static_cast<ProjectNode *>(index.internalPointer()); + if (!current || !current->data()) + return; + + IObject *sender = static_cast<IObject *>(current->data()); + if (sender == core_->script()) { + icon_project_->setChecked(true); +#ifndef LITE + project_tree_->setCurrentIndex(project_model_->scriptIndex()); + int line = luaErrGetLineNumber(current->text()); + if(line >= 1) + script_editor_->send(SCI_GOTOLINE, line - 1); +#endif + } else if (sender == core_->watermark_manager()) { + icon_project_->setChecked(true); + project_tree_->setCurrentIndex(project_model_->optionsIndex()); +#ifndef LITE + core_property_editor_->setFocus(); + core_property_editor_->setCurrentIndex(core_property_manager_->watermarkNameIndex()); +#endif + } else if (dynamic_cast<IFunction *>(sender)) { + icon_project_->setChecked(true); + project_tree_->setCurrentIndex(project_model_->objectToIndex(sender)); + } +#ifdef ULTIMATE + else if (sender == core_->licensing_manager()) { + icon_project_->setChecked(true); + project_tree_->setCurrentIndex(project_model_->licensesIndex()); + } else if (dynamic_cast<InternalFile *>(sender)) { + icon_project_->setChecked(true); + project_tree_->setCurrentIndex(project_model_->objectToIndex(sender)); + internal_file_property_editor_->setCurrentIndex(internal_file_property_manager_->fileNameIndex()); + } +#endif + else + return; + + auto cw = project_page_->currentWidget(); + if (cw) + cw->setFocus(); +} + +void MainWindow::functionItemDoubleClicked(const QModelIndex &index) +{ + Property *prop = function_property_manager_->indexToProperty(index); + if (!prop) + return; + + if (CommandProperty *commandProp = qobject_cast<CommandProperty *>(prop)) { + ICommand *command = commandProp->value(); + if (qobject_cast<CommandProperty *>(commandProp->parent())) { + // link + function_property_editor_->setCurrentIndex(function_property_manager_->commandToIndex(command)); + return; + } + + uint64_t branchAddress = command->link() ? command->link()->to_address() : 0; + if (branchAddress) { + IArchitecture *file = command->owner()->owner()->owner(); + if (core_->input_file()->IndexOf(file) != NOT_ID) { + command = command->owner()->GetCommandByAddress(branchAddress); + if (command) { + function_property_editor_->setCurrentIndex(function_property_manager_->commandToIndex(command)); + return; + } + goToAddress(file, branchAddress); + } + } + } +} + +void MainWindow::disasmItemDoubleClicked(const QModelIndex &index) +{ +#ifndef LITE + ICommand *command = disasm_model_->indexToCommand(index); + if (!command) + return; + + uint64_t branchAddress = command->link() ? command->link()->to_address() : 0; + if (branchAddress) + goToAddress(disasm_model_->file(), branchAddress); +#endif +} + +void MainWindow::goToDump(IArchitecture *file, uint64_t address, bool mode) +{ +#ifndef LITE + info_tree_->setCurrentIndex(info_model_->dumpIndex(file)); + if (mode) { + QModelIndex index = dump_model_->addressToIndex(address); + if (index.isValid()) + dump_view_->setCurrentIndex(index); + } else { + QModelIndex index = disasm_model_->addressToIndex(address); + if (index.isValid()) { + disasm_view_->scrollTo(index, QAbstractItemView::PositionAtTop); + // sometimes PositionAtTop works like PositionAtCenter + disasm_view_->scrollTo(index, QAbstractItemView::PositionAtTop); + disasm_view_->setCurrentIndex(index); + } + } +#endif +} + +void MainWindow::goToAddress(IArchitecture *file, uint64_t address) +{ +#ifdef LITE + MapFunctionBundle *mapFunction = file->owner()->map_function_list()->GetFunctionByAddress(file, address); + if (mapFunction) { + project_tree_->setCurrentIndex(project_model_->objectToIndex(mapFunction)); + if (function_property_manager_->value()) { + ICommand *command = function_property_manager_->value()->GetCommandByAddress(file, address); + if (command) { + function_property_editor_->setCurrentIndex(function_property_manager_->commandToIndex(command)); + return; + } + } + } +#else + if (icon_details_->isChecked()) { + goToDump(file, address, dump_view_->hasFocus()); + return; + } + + ICommand *command = file->function_list()->GetCommandByAddress(address, false); + IFunction *project_function = command ? command->owner() : NULL; + MapFunctionBundle *mapFunction = file->owner()->map_function_list()->GetFunctionByAddress(file, address); + + if (project_function && (icon_project_->isChecked() || !mapFunction)) { + icon_project_->setChecked(true); + project_tree_->setCurrentIndex(project_model_->objectToIndex(project_function)); + function_property_editor_->setCurrentIndex(function_property_manager_->commandToIndex(command)); + return; + } else if (mapFunction) { + icon_functions_->setChecked(true); + functions_tree_->setCurrentIndex(functions_model_->objectToIndex(mapFunction)); + if (function_property_manager_->value()) { + command = function_property_manager_->value()->GetCommandByAddress(file, address); + if (command) { + function_property_editor_->setFocus(); + function_property_editor_->setCurrentIndex(function_property_manager_->commandToIndex(command)); + return; + } + } + } + + icon_details_->setChecked(true); + goToDump(file, address); +#endif +} + +void MainWindow::goTo() +{ +#ifndef LITE + FunctionDialog dialog(core_->input_file(), disasm_model_->file(), smGotoAddress, this); + + if (dialog.exec() == QDialog::Accepted) { + QList<AddressInfo> addresses = dialog.addresses(); + if (addresses.isEmpty()) + return; + + AddressInfo info = addresses[0]; + goToAddress(info.arch, info.address); + } +#endif +} + +bool MainWindow::isContextSearchApplicable() +{ + return project_page_->currentWidget() == script_editor_ || +#ifndef LITE + project_page_->currentWidget() == dump_page_ || +#endif + dynamic_cast<QTreeView *>(project_page_->currentWidget()); +} + +void MainWindow::search() +{ + if (isContextSearchApplicable()) { + if (!context_find_->isVisible()) { + context_find_->showAndClear(project_filter_->text()); + } else { + context_find_->show(); + } + return; + } + project_filter_->selectAll(); + project_filter_->setFocus(); +} + +void MainWindow::showProtected() +{ + showCurrentObject(); +} + +void MainWindow::contextFindNext() +{ + contextFind(context_find_->text(), true, false); +} + +void MainWindow::contextFindPrevious() +{ + contextFind(context_find_->text(), false, false); +} + +void MainWindow::contextFind(const QString &ttf, bool forward, bool incremental) +{ + bool found = true; + if(!ttf.isEmpty()) + { + if (project_page_->currentWidget() == script_editor_) + { + found = findInScript(ttf, forward, incremental); + } else if (QAbstractItemView *tv = +#ifndef LITE + (project_page_->currentWidget() == dump_page_) ? (disasm_view_->geometry().height() ? (QAbstractItemView *)disasm_view_ : (QAbstractItemView *)dump_view_) : +#endif + dynamic_cast<QAbstractItemView *>(project_page_->currentWidget())) + { + found = findInView(tv, ttf, forward, incremental); + } + } + if (!context_find_->isVisible()) + context_find_->show(); + context_find_->setPalette(found); +} + +bool MainWindow::findInScript(const QString &ttf, bool forward, bool incremental) +{ + bool found = false; + + uptr_t pos = script_editor_->send(SCI_GETCURRENTPOS), + anc = script_editor_->send(SCI_GETANCHOR); + if(!incremental) + { + if (forward) // set caret to the end of selection + { + script_editor_->send(SCI_GOTOPOS, std::max(anc, pos)); + } else // set caret to the beginning of selection + { + script_editor_->send(SCI_GOTOPOS, std::min(anc, pos)); + } + } + + unsigned int iMessage = SCI_SEARCHPREV; + if (forward) + iMessage = SCI_SEARCHNEXT; + uptr_t wParam = 0; + if (context_find_->caseSensitive()) + wParam = SCFIND_MATCHCASE; + + while(!found) + { + script_editor_->send(SCI_SEARCHANCHOR); + found = (script_editor_->send(iMessage, wParam, (sptr_t)ttf.toUtf8().data()) != -1); + + if (found) + { + script_editor_->send(SCI_SCROLLCARET); + } else + { + if(incremental) // try from the beginning + { + script_editor_->send(SCI_GOTOPOS); + incremental = false; + } else + { + script_editor_->send(SCI_SETSEL, anc, pos); + break; + } + } + } + return found; +} + +bool MainWindow::findInView(QAbstractItemView *tv, const QString &ttf, bool forward, bool incremental) +{ + WaitCursor wc; + + QRegExp term(ttf, context_find_->caseSensitive() ? Qt::CaseSensitive : Qt::CaseInsensitive); + ItemModelSearcher searcher( + tv->model(), + tv->currentIndex(), + &term, + forward, + incremental); + + QModelIndex ci = searcher.result(); + bool found = ci.isValid(); + if(found && ci != tv->currentIndex()) { + tv->selectionModel()->setCurrentIndex(ci, QItemSelectionModel::ClearAndSelect); + } + return found; +} + +void MainWindow::contextFindClosed() +{ + QWidget *page = project_page_->currentWidget(); + if (page) + page->setFocus(); +} + +void MainWindow::updateTemplates() +{ + QList<QAction*> actions = templates_menu_->actions(); + ProjectTemplateManager *template_manager = core_->template_manager(); + int separator_pos = actions.size() - 3; + size_t c = 0; + for (int i = 0; i < separator_pos; i++) { + QAction *action = actions.at(i); + if (i < (int)template_manager->count()) { + ProjectTemplate *pt = template_manager->item(i); + action->setText(QString::fromUtf8(pt->display_name().c_str())); + c++; + } else { + templates_menu_->removeAction(action); + } + } + for (size_t i = c; i < template_manager->count(); i++) { + ProjectTemplate *pt = template_manager->item(i); + QAction *action = new QAction(QString::fromUtf8(pt->display_name().c_str()), this); + action->setCheckable(true); + connect(action, SIGNAL(triggered()), this, SLOT(templateSelect())); + templates_menu_->insertAction(actions.at(separator_pos), action); + } +} + +void MainWindow::templatesShow() +{ + QList<QAction*> actions = templates_menu_->actions(); + ProjectTemplate current(NULL, ""); + ProjectTemplateManager *template_manager = core_->template_manager(); + current.ReadFromCore(*core_); + bool isChecked = false; + for (int i = 0; i < (int)template_manager->count(); i++) { + ProjectTemplate *pt = template_manager->item(i); + if (!isChecked && *pt == current) { + isChecked = true; + actions.at(i)->setChecked(true); + } else { + actions.at(i)->setChecked(false); + } + } +} + +void MainWindow::templatesSave() +{ + TemplateSaveDialog dialog(core_->template_manager(), this); + if (dialog.exec() == QDialog::Accepted) + core_->template_manager()->Add(dialog.name().toUtf8().constData(), *core_); +} + +void MainWindow::templatesEdit() +{ + TemplatesWindow dialog(this); + dialog.exec(); +} + +void MainWindow::templateSelect() +{ + QAction *action = qobject_cast<QAction *>(sender()); + if (action) { + core_property_editor_->closePersistentEditor(core_property_editor_->currentIndex()); + core_->LoadFromTemplate(*core_->template_manager()->item(templates_menu_->actions().indexOf(action))); + } +} + +void MainWindow::updateEditActions() +{ + if (project_model_->isEmpty()) + return; + + if (QApplication::activeWindow() != this) + return; + + QWidget *widget = focusWidget(); + bool canCopy = false; +#ifdef ULTIMATE + if (widget == license_property_editor_ && license_property_manager_->indexToProperty(license_property_editor_->currentIndex()) == license_property_manager_->serialNumber()) + canCopy = true; +#endif + bool canCut = false; + bool canPaste = false; + bool canRedo = false; + bool canUndo = false; + ProjectNode *current = currentProjectNode(); + assert(current); + if (!current) + return; +#ifdef ULTIMATE + add_license_act2_->setVisible(current->type() == NODE_LICENSE || current->type() == NODE_LICENSES); + add_file_act2_->setVisible(current->type() == NODE_FILE || current->type() == NODE_FILE_FOLDER || current->type() == NODE_FILES || current->type() == NODE_ASSEMBLIES); + add_function_act2_->setVisible(!add_license_act2_->isEnabled() && !add_file_act2_->isEnabled()); +#endif +#ifndef LITE + add_function_act2_->setVisible(current->type() == NODE_FUNCTIONS || current->type() == NODE_FOLDER || current->type() == NODE_FUNCTION); +#endif + + bool canDel = current->type() == NODE_SCRIPT || current->type() == NODE_SCRIPT_BOOKMARK || current->type() == NODE_FUNCTION || current->type() == NODE_FOLDER || current->type() == NODE_LICENSE || current->type() == NODE_FILE_FOLDER || current->type() == NODE_FILE; + if (widget == script_editor_) { + canUndo = script_editor_->canUndo(); + canRedo = script_editor_->canRedo(); + canCopy = script_editor_->hasSelection(); + canCut = script_editor_->hasSelection(); + canDel = script_editor_->hasSelection(); + canPaste = script_editor_->canPaste(); + } else if (QAbstractItemView *view = qobject_cast<QAbstractItemView *>(widget)) { + canCopy = view->selectionModel()->selectedIndexes().size() > 0; + canDel = canCopy && currentTreeView() == project_tree_; +#ifdef ULTIMATE + } else if (widget == license_property_editor_ && license_property_manager_->indexToProperty(license_property_editor_->currentIndex()) == license_property_manager_->serialNumber()) { + canCopy = true; +#endif + } else if (QLineEdit *edit = qobject_cast<QLineEdit *>(widget)) { + canCopy = edit->hasSelectedText(); + if (!edit->isReadOnly()) { + canPaste = !QApplication::clipboard()->text().isEmpty(); + canCut = edit->hasSelectedText(); + canDel = edit->hasSelectedText(); + canRedo = edit->isRedoAvailable(); + canUndo = edit->isUndoAvailable(); + } + } else if (QPlainTextEdit *pt_edit = qobject_cast<QPlainTextEdit *>(widget)) { + canCopy = pt_edit->textCursor().hasSelection(); + if (!pt_edit->isReadOnly()) { + canPaste = !QApplication::clipboard()->text().isEmpty(); + canCut = pt_edit->textCursor().hasSelection(); + canDel = pt_edit->textCursor().hasSelection(); + canRedo = pt_edit->document()->isRedoAvailable(); + canUndo = pt_edit->document()->isUndoAvailable(); + } + } else if (QComboBox *comboBox = qobject_cast<QComboBox *>(widget)) { + if (comboBox->isEditable()) { + QLineEdit *edit = comboBox->lineEdit(); + canCopy = edit->hasSelectedText(); + if (!edit->isReadOnly()) { + canPaste = !QApplication::clipboard()->text().isEmpty(); + canCut = edit->hasSelectedText(); + canDel = edit->hasSelectedText(); + canRedo = edit->isRedoAvailable(); + canUndo = edit->isUndoAvailable(); + } + } + } + copy_act_->setEnabled(canCopy); + cut_act_->setEnabled(canCut); + paste_act_->setEnabled(canPaste); + redo_act_->setEnabled(canRedo); + undo_act_->setEnabled(canUndo); + delete_act_->setEnabled(canDel); + + if (fileChanged_) { + fileChanged_ = false; + if (MessageDialog::question(this, QString::fromUtf8(string_format(language[lsWatchedFileChange].c_str(), core_->input_file()->file_name().c_str()).c_str()), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { + recent_file_ = 0; + openRecentFile(); + } + } +} + +void MainWindow::treeSectionClicked(int index) +{ + ProjectNode *current = currentProjectNode(); + if (!current) + return; + + project_model_->sortNode(current, index); + directory_model_->setDirectory(current); +} + +void MainWindow::fileChanged(const QString & path) +{ + fileChanged_ = true; +}
\ No newline at end of file diff --git a/VMProtect/mainwindow.h b/VMProtect/mainwindow.h new file mode 100644 index 0000000..5e3c077 --- /dev/null +++ b/VMProtect/mainwindow.h @@ -0,0 +1,321 @@ +#ifndef MAINWINDOW_H +#define MAINWINDOW_H + +class GUILog; +class FunctionBundle; +class FunctionPropertyManager; +class CorePropertyManager; +class SectionPropertyManager; +class SegmentPropertyManager; +class ImportPropertyManager; +class ExportPropertyManager; +class ResourcePropertyManager; +class LoadCommandPropertyManager; +class AddressCalculator; +class ProjectNode; +class IArchitecture; +class Core; +class WatermarksModel; +class TemplatesModel; +class ProjectModel; +class SearchModel; +class DirectoryModel; +class LogModel; +class FunctionsModel; +class InfoModel; +class DumpModel; +class DisasmModel; +class TabWidget; +class TreePropertyEditor; +class SearchLineEdit; +class ScriptEdit; +class License; +class LicensePropertyManager; +class InternalFilePropertyManager; +class AssemblyPropertyManager; +class FindWidget; +class ElidedAction; +class ToolButtonElided; + +using namespace Scintilla; + +class MainWindow : public QMainWindow +{ + Q_OBJECT +public: + MainWindow(); + ~MainWindow(); + +protected: + virtual void closeEvent(QCloseEvent *event); + virtual void dragEnterEvent(QDragEnterEvent *event); + virtual void dropEvent(QDropEvent *event); +private slots: + void notify(MessageType type, IObject *sender, const QString &message); + void projectFilterChanged(); + void projectItemChanged(); + void treeItemDoubleClicked(const QModelIndex &index); + void open(); + void loadFile(const QString &filenameOrBundle); + bool save(); + void saveAs(); + void saveLicenses(); + bool closeFile(); + void projectTabMoved(); + void projectTabClicked(); + void scriptNotify(SCNotification *scn); + void undo(); + void redo(); + void copy(); + void cut(); + void paste(); + void addFunction(); + void addFolder(); + void addFunctionFolder(); + void rename(); + void excludeFromCompilation(); + void block(); + void del(); + void homePage(); + void help(); + void about(); + void projectModified(); + void projectNodeRemoved(ProjectNode *node); + void projectObjectRemoved(void *object); + void compile(); + void execute(); + void executeOriginal(); + void executeProtected(); + void projectContextMenu(const QPoint &p); + void scriptContextMenu(const QPoint &p); + void functionContextMenu(const QPoint &p); + void functionExtAddress(); + void functionEndAddress(); + void functionDel(); + void loadFileFromHistory(); + void loadFileFromBoot(); + void addLicense(); + void addFileFolder(); + void addFile(); + void createKeyPair(); + void exportKeyPair(); + void useOtherProject(); + void importLicense(); + void importProject(); + void examples(); + void watermarks(); + void settings(); + void showFile(); + void logItemDoubleClicked(const QModelIndex &index); + void functionItemDoubleClicked(const QModelIndex &index); + void disasmItemDoubleClicked(const QModelIndex &index); + void goTo(); + void search(); + void showProtected(); + void contextFindNext(); + void contextFindPrevious(); + void contextFind(const QString &ttf, bool forward, bool incremental); + void contextFindClosed(); + void scriptModeClicked(); + void templatesShow(); + void templatesSave(); + void templatesEdit(); + void templateSelect(); + void updateEditActions(); + void treeSectionClicked(int index); + void recentFileContextMenu(const QPoint &p); + void openRecentFile(); + void removeRecentFile(); + void fileChanged(const QString & path); +private: + bool isContextSearchApplicable(); + bool findInScript(const QString &ttf, bool forward, bool incremental); + bool findInView(QAbstractItemView *tv, const QString &ttf, bool forward, bool incremental); + void showCurrentObject(); + void addRecentFile(int index, const QString file_name); + void saveRecentFiles(); + bool internalLoadFile(const QString &filename); + bool internalCompile(); + QTreeView *currentTreeView() const; + ProjectNode *currentProjectNode(bool focusedTree = false) const; + void updateCaption(); + void executeFile(const QString &fileName); + void localize(); + void goToAddress(IArchitecture *file, uint64_t address); + void goToDump(IArchitecture *file, uint64_t address, bool mode = false); +#ifdef ULTIMATE + void createLicense(License *license); + void updateLicensingActions(); +#endif + void updateTemplates(); + + QString caption_; + GUILog *log_; + Core *core_; + FunctionBundle *temp_function_; + WatermarksModel *watermarks_model_; + TemplatesModel *templates_model_; + ProjectModel *project_model_; + SearchModel *search_model_; + DirectoryModel *directory_model_; + LogModel *log_model_; + FunctionPropertyManager *function_property_manager_; + CorePropertyManager *core_property_manager_; +#ifndef LITE + FunctionsModel *functions_model_; + InfoModel *info_model_; + DumpModel *dump_model_; + DisasmModel *disasm_model_; + SectionPropertyManager *section_property_manager_; + SegmentPropertyManager *segment_property_manager_; + ImportPropertyManager *import_property_manager_; + ExportPropertyManager *export_property_manager_; + ResourcePropertyManager *resource_property_manager_; + LoadCommandPropertyManager *loadcommand_property_manager_; + AddressCalculator *address_calculator_manager_; + QTreeView *info_tree_; +#endif +#ifdef ULTIMATE + LicensePropertyManager *license_property_manager_; + InternalFilePropertyManager *internal_file_property_manager_; + AssemblyPropertyManager *assembly_property_manager_; +#endif + QFileSystemWatcher fs_watcher_; + + QAction *open_act_; + QAction *save_act_; + QAction *save_as_act_; + QAction *close_act_; + QAction *exit_act_; + QAction *undo_act_; + QAction *redo_act_; + QAction *cut_act_; + QAction *copy_act_; + QAction *paste_act_; + QAction *cut_act2_; + QAction *copy_act2_; + QAction *paste_act2_; +#ifdef LITE + QAction *show_act_; +#else + QAction *add_function_act_; + QAction *add_function_act2_; + QAction *add_folder_act_; + QAction *goto_act_; + QAction *goto_act2_; + QAction *watermarks_act_; +#endif +#ifdef ULTIMATE + QAction *save_licenses_act_; + QAction *add_license_act_; + QAction *add_license_act2_; + QAction *add_file_act_; + QAction *add_file_act2_; + QAction *import_license_act_; + QAction *import_project_act_; + QAction *export_key_act_; +#endif + QAction *block_act_; + QAction *exclude_act_; + QAction *rename_act_; + QAction *delete_act_; + QAction *project_filter_act_; + QAction *compile_act_; + QAction *execute_act_; + ElidedAction *execute_original_act_; + ElidedAction *execute_protected_act_; + QWidgetAction *execute_parameters_act_; + QAction *function_ext_address_act_; + QAction *function_end_address_act_; + QAction *function_del_act_; + QAction *help_act_; + QAction *home_page_act_; + QAction *about_act_; + QAction *history_separator_; + QAction *project_separator_; + QAction *settings_act_; + QAction *search_act_; + + QMenu *file_menu_; + QMenu *edit_menu_; + QMenu *project_menu_; +#ifdef ULTIMATE + QMenu *import_menu_; +#endif + QMenu *help_menu_; + QMenu *script_menu_; + QMenu *tools_menu_; + + QStackedWidget *desktop_page_; + QFrame *boot_frame_; + QFrame *boot_panel_; + QFrame *project_frame_; + TabWidget *project_tab_; + QTreeView *project_tree_; + QTreeView *search_tree_; + QTreeView *directory_tree_; + QRadioButton *icon_project_; + QStatusBar *status_bar_; +#ifndef LITE + QMenu *add_menu_; + QRadioButton *icon_functions_; + QRadioButton *icon_details_; + QTreeView *functions_tree_; + QFrame *dump_page_; + QTableView *dump_view_; + QTableView *disasm_view_; + TreePropertyEditor *section_property_editor_; + TreePropertyEditor *segment_property_editor_; + TreePropertyEditor *import_property_editor_; + TreePropertyEditor *export_property_editor_; + TreePropertyEditor *resource_property_editor_; + TreePropertyEditor *loadcommand_property_editor_; + TreePropertyEditor *address_calculator_; +#endif + SearchLineEdit *project_filter_; + QStackedWidget *project_page_; + ScriptEdit *script_editor_; + QLabel *project_file_name_; + QLabel *script_line_; + QLabel *script_column_; + QLabel *script_mode_; + FindWidget *context_find_; + TreePropertyEditor *function_property_editor_; + TreePropertyEditor *core_property_editor_; +#ifdef ULTIMATE + TreePropertyEditor *license_property_editor_; + TreePropertyEditor *internal_file_property_editor_; + TreePropertyEditor *assembly_property_editor_; + QFrame *licensing_parameters_page_; + QLabel *licensing_parameters_help_; + QLabel *key_algo_label_; + QLabel *key_len_label_; + QComboBox *key_len_; + QPushButton *create_key_button_; + QPushButton *use_other_project_button_; +#endif + ToolButtonElided *spacer_; + QWidget *project_separator_widget_; + QTreeView *log_tree_; + QMenu *execute_menu_; + QLineEdit *parameters_edit_; + + QBoxLayout *recent_files_layout_; + QToolButton *open_button_; + QToolButton *examples_button_; + QToolButton *help_button_; + QLabel *recent_files_label_; + QLabel *quick_start_label_; + QLabel *welcome_label_; + QAction *templates_act_; + QAction *templates_save_act_; + QAction *templates_edit_act_; + QMenu *templates_menu_; + QAction *recent_file_open_act_; + QAction *recent_file_remove_act_; + int recent_file_; + QMenu *recent_file_menu_; + bool fileChanged_; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/message_dialog.cc b/VMProtect/message_dialog.cc new file mode 100644 index 0000000..46a206e --- /dev/null +++ b/VMProtect/message_dialog.cc @@ -0,0 +1,149 @@ +#include "../core/objects.h" +#include "../core/lang.h" + +#include "message_dialog.h" +#include "moc/moc_message_dialog.cc" + +/** + * MessageDialog + */ + +MessageDialog::MessageDialog(QMessageBox::Icon icon, const QString &text, + QMessageBox::StandardButtons /*buttons*/, QWidget *parent) + : QDialog(parent, Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint), clickedButton_(NULL), defaultButton_(NULL) +{ + QLabel *label = new QLabel(text, this); + label->setObjectName("messageBox"); + + QLabel *iconLabel = new QLabel(this); + iconLabel->setAlignment(Qt::AlignCenter); + iconLabel->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); + + int iconSize = style()->pixelMetric(QStyle::PM_MessageBoxIconSize, 0, this); + QIcon tmpIcon; + switch (icon) { + case QMessageBox::Information: + setWindowTitle(QString::fromUtf8(language[lsInformation].c_str())); + tmpIcon = style()->standardIcon(QStyle::SP_MessageBoxInformation, 0, this); + break; + case QMessageBox::Warning: + setWindowTitle(QString::fromUtf8(language[lsWarning].c_str())); + tmpIcon = style()->standardIcon(QStyle::SP_MessageBoxWarning, 0, this); + break; + case QMessageBox::Critical: + setWindowTitle(QString::fromUtf8(language[lsError].c_str())); + tmpIcon = style()->standardIcon(QStyle::SP_MessageBoxCritical, 0, this); + break; + case QMessageBox::Question: + setWindowTitle(QString::fromUtf8(language[lsConfirmation].c_str())); + tmpIcon = style()->standardIcon(QStyle::SP_MessageBoxQuestion, 0, this); + default: + break; + } + if (!tmpIcon.isNull()) + iconLabel->setPixmap(tmpIcon.pixmap(iconSize, iconSize)); + + buttonBox_ = new QDialogButtonBox(this); + buttonBox_->setCenterButtons(true); + + QGridLayout *grid = new QGridLayout; + grid->setContentsMargins(20, 20, 20, 20); + grid->setSpacing(20); + grid->addWidget(iconLabel, 0, 0); + grid->addWidget(label, 0, 1); + grid->addWidget(buttonBox_, 2, 0, 1, 2); + grid->setSizeConstraint(QLayout::SetFixedSize); + setLayout(grid); + + connect(buttonBox_, SIGNAL(clicked(QAbstractButton*)), this, SLOT(buttonClicked(QAbstractButton*))); + + setModal(true); +} + +void MessageDialog::buttonClicked(QAbstractButton *button) +{ + clickedButton_ = button; + int ret = buttonBox_->standardButton(button); + if (ret == QMessageBox::NoButton) + ret = -1; + done(ret); +} + +void MessageDialog::setDefaultButton(QPushButton *button) +{ + if (!buttonBox_->buttons().contains(button)) + return; + + defaultButton_ = button; + button->setDefault(true); + button->setFocus(); +} + +QMessageBox::StandardButton MessageDialog::information(QWidget *parent, + const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) +{ + return showMessageBox(parent, QMessageBox::Information, text, buttons, defaultButton); +} + +QMessageBox::StandardButton MessageDialog::question(QWidget *parent, + const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) +{ + return showMessageBox(parent, QMessageBox::Question, text, buttons, defaultButton); +} + +QMessageBox::StandardButton MessageDialog::warning(QWidget *parent, + const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) +{ + return showMessageBox(parent, QMessageBox::Warning, text, buttons, defaultButton); +} + +QMessageBox::StandardButton MessageDialog::critical(QWidget *parent, + const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) +{ + return showMessageBox(parent, QMessageBox::Critical, text, buttons, defaultButton); +} + +QMessageBox::StandardButton MessageDialog::showMessageBox(QWidget *parent, QMessageBox::Icon icon, + const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton) +{ + MessageDialog dialog(icon, text, QMessageBox::NoButton, parent); + QDialogButtonBox *buttonBox = dialog.findChild<QDialogButtonBox*>(); + + assert(buttonBox); + if (buttonBox == NULL) return QMessageBox::Cancel; + + uint mask = QMessageBox::FirstButton; + while (mask <= QMessageBox::LastButton) { + uint sb = buttons & mask; + mask <<= 1; + if (!sb) + continue; + + QPushButton *button = buttonBox->addButton((QDialogButtonBox::StandardButton)sb); + switch (sb) { + case QMessageBox::Ok: + button->setText(QString::fromUtf8(language[lsOK].c_str())); + break; + case QMessageBox::Cancel: + button->setText(QString::fromUtf8(language[lsCancel].c_str())); + break; + case QMessageBox::Yes: + button->setText(QString::fromUtf8(language[lsYes].c_str())); + break; + case QMessageBox::No: + button->setText(QString::fromUtf8(language[lsNo].c_str())); + break; + } + + // Choose the first accept role as the default + if (dialog.defaultButton()) + continue; + if ((defaultButton == QMessageBox::NoButton && buttonBox->buttonRole(button) == QDialogButtonBox::AcceptRole) + || (defaultButton != QMessageBox::NoButton && sb == uint(defaultButton))) + dialog.setDefaultButton(button); + } + + if (dialog.exec() == -1) + return QMessageBox::Cancel; + return QMessageBox::StandardButton(buttonBox->standardButton(dialog.clickedButton())); +}
\ No newline at end of file diff --git a/VMProtect/message_dialog.h b/VMProtect/message_dialog.h new file mode 100644 index 0000000..520fc00 --- /dev/null +++ b/VMProtect/message_dialog.h @@ -0,0 +1,31 @@ +#ifndef MESSAGE_DIALOG_H +#define MESSAGE_DIALOG_H + +class MessageDialog : public QDialog +{ + Q_OBJECT +public: + MessageDialog(QMessageBox::Icon icon, const QString &text, + QMessageBox::StandardButtons buttons = QMessageBox::NoButton, QWidget *parent = 0); + static QMessageBox::StandardButton information(QWidget *parent, + const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + static QMessageBox::StandardButton question(QWidget *parent, + const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + static QMessageBox::StandardButton warning(QWidget *parent, + const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + static QMessageBox::StandardButton critical(QWidget *parent, + const QString &text, QMessageBox::StandardButtons buttons = QMessageBox::Ok, QMessageBox::StandardButton defaultButton = QMessageBox::NoButton); + QAbstractButton *clickedButton() const { return clickedButton_; } + void setDefaultButton(QPushButton *button); + QAbstractButton *defaultButton() const { return defaultButton_; } +private slots: + void buttonClicked(QAbstractButton *button); +private: + static QMessageBox::StandardButton showMessageBox(QWidget *parent, QMessageBox::Icon icon, + const QString &text, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton defaultButton); + QDialogButtonBox *buttonBox_; + QAbstractButton *clickedButton_; + QAbstractButton *defaultButton_; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/models.cc b/VMProtect/models.cc new file mode 100644 index 0000000..5895d0c --- /dev/null +++ b/VMProtect/models.cc @@ -0,0 +1,3943 @@ +#include "../core/objects.h" +#include "../core/files.h" +#include "../core/core.h" +#include "../core/processors.h" +#include "../core/script.h" +#include "../core/lang.h" + +#include "models.h" +#include "moc/moc_models.cc" +#include "widgets.h" +#include "property_editor.h" +#include "message_dialog.h" + +static QIcon nodeIcon(NodeType type, bool is_disabled = false) +{ + QString iconName; + switch (type) { + case NODE_FUNCTIONS: + iconName = ":/images/star.png"; + break; + case NODE_LICENSES: + iconName = ":/images/key.png"; + break; + case NODE_SCRIPT: + iconName = ":/images/script.png"; + break; + case NODE_OPTIONS: + iconName = ":/images/gear.png"; + break; + case NODE_FILES: + case NODE_ASSEMBLIES: + iconName = ":/images/box.png"; + break; + case NODE_ARCHITECTURE: + iconName = ":/images/processor.png"; + break; + case NODE_LOAD_COMMANDS: + iconName = ":/images/lightning.png"; + break; + case NODE_SEGMENTS: + iconName = ":/images/code.png"; + break; + case NODE_EXPORTS: + iconName = ":/images/export.png"; + break; + case NODE_IMPORTS: + iconName = ":/images/import.png"; + break; + case NODE_RESOURCES: + iconName = ":/images/database.png"; + break; + case NODE_CALC: + iconName = ":/images/calc.png"; + break; + case NODE_DUMP: + iconName = ":/images/dump.png"; + break; + case NODE_LICENSE: + iconName = ":/images/item_key.png"; + break; + case NODE_FILE: + iconName = ":/images/item_file.png"; + break; + case NODE_PROPERTY: + iconName = ":/images/item_property.png"; + break; + case NODE_LOAD_COMMAND: + iconName = ":/images/item_load_command.png"; + break; + case NODE_SEGMENT: + case NODE_SECTION: + iconName = ":/images/item_code.png"; + break; + case NODE_IMPORT_FUNCTION: + iconName = ":/images/item_import.png"; + break; + case NODE_EXPORT: + iconName = ":/images/item_export.png"; + break; + case NODE_RESOURCE: + iconName = ":/images/item_resource.png"; + break; + case NODE_WATERMARK: + case NODE_FUNCTION: + iconName = ":/images/item.png"; + break; + case NODE_SCRIPT_BOOKMARK: + iconName = ":/images/item_code.png"; + break; + case NODE_FOLDER: + case NODE_RESOURCE_FOLDER: + case NODE_MAP_FOLDER: + case NODE_IMPORT_FOLDER: + case NODE_EXPORT_FOLDER: + case NODE_IMPORT: + case NODE_FILE_FOLDER: + if (is_disabled) { + QIcon res; + QPixmap firstImage(":/images/folder_close.png"); + QPixmap secondImage(":/images/bullet_delete.png"); + { + QPainter painter(&firstImage); + painter.drawPixmap(firstImage.width() - secondImage.width(), firstImage.height() - secondImage.height(), secondImage); + } + res.addPixmap(firstImage); + + firstImage = QPixmap(":/images/folder.png"); + { + QPainter painter(&firstImage); + painter.drawPixmap(firstImage.width() - secondImage.width(), firstImage.height() - secondImage.height(), secondImage); + } + res.addPixmap(firstImage, QIcon::Normal, QIcon::On); + + return res; + } else { + QIcon res = QIcon(":/images/folder_close.png"); + res.addPixmap(QPixmap(":/images/folder.png"), QIcon::Normal, QIcon::On); + return res; + } + break; + } + + if (is_disabled) { + QPixmap firstImage(iconName); + QPixmap secondImage(":/images/bullet_delete.png"); + QPainter painter(&firstImage); + painter.drawPixmap(firstImage.width() - secondImage.width(), firstImage.height() - secondImage.height(), secondImage); + + return QIcon(firstImage); + } else { + return QIcon(iconName); + } +} + +template<typename F> +static QIcon functionIcon(F *func) +{ + if (!func || !func->need_compile()) + return nodeIcon(NODE_FUNCTION, true); + + QString iconName; + switch (func->compilation_type()) { + case ctMutation: + iconName = ":/images/item_m.png"; + break; + case ctUltra: + iconName = ":/images/item_u.png"; + break; + default: + iconName = ":/images/item_v.png"; + break; + } + + QString bullet_name; + if (func->type() == otUnknown) + bullet_name = ":/images/bullet_warning.png"; + else if (func->compilation_type() != ctMutation && (func->compilation_options() & coLockToKey)) + bullet_name = ":/images/bullet_key.png"; + + if (!bullet_name.isEmpty()) { + QPixmap firstImage(iconName); + QPixmap secondImage(bullet_name); + QPainter painter(&firstImage); + painter.drawPixmap(firstImage.width() - secondImage.width(), firstImage.height() - secondImage.height(), secondImage); + + QIcon res; + res.addPixmap(firstImage); + return res; + } + return QIcon(iconName); +} + +/** + * ProjectNode + */ + +ProjectNode::ProjectNode(ProjectNode *parent, NodeType type, void *data) + : parent_(NULL), data_(data), type_(type), properties_(NULL) +{ + if (parent) + parent->addChild(this); +} + +void ProjectNode::clear() +{ + for (int i = 0; i < children_.size(); i++) { + ProjectNode *node = children_[i]; + node->parent_ = NULL; + delete node; + } + children_.clear(); + + if (properties_) { + delete properties_; + properties_ = NULL; + } +} + +ProjectNode::~ProjectNode() +{ + clear(); + if (parent_) + parent_->removeChild(this); +} + +QString functionProtection(const FunctionBundle *func) +{ + return func ? QString::fromUtf8(func->display_protection().c_str()) : QString::fromUtf8(language[lsNone].c_str()); +} + +bool ProjectNode::contains(const QRegExp &filter) const +{ + for (int i = 0; i < 2; i++) { + if (text(i).contains(filter)) + return true; + } + + return false; +} + +QString ProjectNode::text(int column) const +{ + if (column == 0) + return text_; + + switch (type_) { + case NODE_SCRIPT: + case NODE_SCRIPT_BOOKMARK: + { + Script *object = static_cast<Script *>(data_); + if (column == 1) { + return QString::fromUtf8(object->text().c_str()); + } + } + break; + case NODE_FUNCTION: + { + FunctionBundle *object = static_cast<FunctionBundle *>(data_); + if (column == 1) { + return QString::fromUtf8(object->display_address().c_str()); + } else if (column == 2) { + return QString::fromUtf8(object->display_protection().c_str()); + } + } + break; + case NODE_MAP_FUNCTION: + { + MapFunctionBundle *object = static_cast<MapFunctionBundle *>(data_); + if (column == 1) { + return QString::fromUtf8(object->display_address().c_str()); + } else if (column == 2) { + IFile *file = object->owner()->owner(); + return functionProtection(file->function_list()->GetFunctionByName(object->name())); + } + } + break; + case NODE_LOAD_COMMAND: + { + ILoadCommand *object = static_cast<ILoadCommand *>(data_); + if (column == 1) { + return QString::fromUtf8(DisplayValue(object->address_size(), object->address()).c_str()); + } else if (column == 2) { + return QString::fromUtf8(DisplayValue(osDWord, object->size()).c_str()); + } + } + break; + case NODE_SEGMENT: + case NODE_SECTION: + { + ISection *object = static_cast<ISection *>(data_); + if (column == 1) { + return QString::fromUtf8(DisplayValue(object->address_size(), object->address()).c_str()); + } else if (column == 2) { + return QString::fromUtf8(DisplayValue(osDWord, object->size()).c_str()); + } else if (column == 3) { + return QString::fromUtf8(DisplayValue(osDWord, object->physical_offset()).c_str()); + } else if (column == 4) { + return QString::fromUtf8(DisplayValue(osDWord, object->physical_size()).c_str()); + } else if (column == 5) { + return QString::fromUtf8(DisplayValue(osDWord, object->flags()).c_str()); + } + } + break; + case NODE_RESOURCE: + { + IResource *object = static_cast<IResource *>(data_); + if (column == 1) { + return QString::fromUtf8(DisplayValue(object->address_size(), object->address()).c_str()); + } else if (column == 2) { + return QString::fromUtf8(DisplayValue(osDWord, object->size()).c_str()); + } + } + break; + case NODE_IMPORT_FUNCTION: + { + IImportFunction *object = static_cast<IImportFunction *>(data_); + if (column == 1) { + return QString::fromUtf8(DisplayValue(object->address_size(), object->address()).c_str()); + } + } + break; + case NODE_EXPORT: + { + IExport *object = static_cast<IExport *>(data_); + if (column == 1) { + return QString::fromUtf8(DisplayValue(object->address_size(), object->address()).c_str()); + } + } + break; + case NODE_PROPERTY: + { + Property *object = static_cast<Property *>(data_); + if (column == 1) { + return object->valueText(); + } + } + break; +#ifdef ULTIMATE + case NODE_LICENSE: + { + License *object = static_cast<License *>(data_); + if (column == 1) { + return QString::fromUtf8(object->customer_email().c_str()); + } else if (column == 2) { + LicenseDate date = object->date(); + return QDate(date.Year, date.Month, date.Day).toString(Qt::SystemLocaleShortDate); + } + } + break; + case NODE_FILE: + { + InternalFile *object = static_cast<InternalFile *>(data_); + if (column == 1) { + return QString::fromUtf8(object->file_name().c_str()); + } + } + break; +#endif + } + return QString(); +} + +QString ProjectNode::path() const +{ + QString res; + for (ProjectNode *p = parent(); p && p->type() != NODE_ROOT; p = p->parent()) { + if (!res.isEmpty()) + res = " > " + res; + res = p->text() + res; + } + return res; +} + +void ProjectNode::addChild(ProjectNode *child) +{ + insertChild(childCount(), child); +} + +void ProjectNode::insertChild(int index, ProjectNode *child) +{ + if (child->parent()) + return; + + child->parent_ = this; + children_.insert(index, child); +} + +void ProjectNode::removeChild(ProjectNode *child) +{ + if (children_.removeOne(child)) + child->parent_ = NULL; +} + +void ProjectNode::setPropertyManager(PropertyManager *propertyManager) +{ + if (properties_) { + delete properties_; + properties_ = NULL; + } + + if (!propertyManager) + return; + + properties_ = new ProjectNode(NULL, type_, data_); + properties_->setText(text_); + properties_->setIcon(nodeIcon(type_)); + + QList<Property *> propertyList; + QMap<Property *, ProjectNode *> propertyMap; + propertyMap[propertyManager->root()] = properties_; + propertyList.append(propertyManager->root()->children()); + for (int i = 0; i < propertyList.size(); i++) { + Property *prop = propertyList[i]; + propertyList.append(prop->children()); + + ProjectNode *node = new ProjectNode(propertyMap[prop->parent()], NODE_PROPERTY, prop); + node->setText(prop->name()); + node->setIcon(nodeIcon(node->type())); + propertyMap[prop] = node; + } +} + +void ProjectNode::localize() +{ + switch (type_) { + case NODE_FUNCTIONS: + setText(QString::fromUtf8(language[lsFunctionsForProtection].c_str())); + break; + case NODE_LICENSES: + setText(QString::fromUtf8(language[lsLicenses].c_str())); + break; + case NODE_FILES: + setText(QString::fromUtf8(language[lsFiles].c_str())); + break; + case NODE_ASSEMBLIES: + setText(QString::fromUtf8(language[lsAssemblies].c_str())); + break; + case NODE_SCRIPT: + setText(QString::fromUtf8(language[lsScript].c_str())); + break; + case NODE_OPTIONS: + setText(QString::fromUtf8(language[lsOptions].c_str())); + break; + case NODE_PROPERTY: + setText(static_cast<Property*>(data_)->name()); + break; + case NODE_LOAD_COMMANDS: + setText(QString::fromUtf8(language[lsDirectories].c_str())); + break; + case NODE_SEGMENTS: + setText(QString::fromUtf8(language[lsSegments].c_str())); + break; + case NODE_IMPORTS: + setText(QString::fromUtf8(language[lsImports].c_str())); + break; + case NODE_EXPORTS: + setText(QString::fromUtf8(language[lsExports].c_str())); + break; + case NODE_RESOURCES: + setText(QString::fromUtf8(language[lsResources].c_str())); + break; + case NODE_CALC: + setText(QString::fromUtf8(language[lsCalculator].c_str())); + break; + case NODE_DUMP: + setText(QString::fromUtf8(language[lsDump].c_str())); + break; + case NODE_ARCHITECTURE: + for (int i = 0; i < childCount(); i++) { + child(i)->localize(); + } + } + + if (properties_) { + QList<ProjectNode *> list; + list.append(properties_); + for (int i = 0; i < list.size(); i++) { + ProjectNode *node = list[i]; + node->localize(); + + list.append(node->children()); + } + } +} + +/** + * BaseModel + */ + +BaseModel::BaseModel(QObject *parent) + : QAbstractItemModel(parent), root_(NULL), core_(NULL) +{ + root_ = new ProjectNode(NULL, NODE_ROOT); +} + +BaseModel::~BaseModel() +{ + delete root_; +} + +ProjectNode *BaseModel::indexToNode(const QModelIndex &index) const +{ + if (index.isValid()) + return static_cast<ProjectNode *>(index.internalPointer()); + return root_; +} + +QModelIndex BaseModel::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + ProjectNode *childNode = indexToNode(index); + ProjectNode *parentNode = childNode->parent(); + if (parentNode == root_) + return QModelIndex(); + + return createIndex(parentNode->parent()->children().indexOf(parentNode), 0, parentNode); +} + +int BaseModel::columnCount(const QModelIndex & /* parent */) const +{ + return 1; +} + +int BaseModel::rowCount(const QModelIndex &parent) const +{ + ProjectNode *parentNode = indexToNode(parent); + return parentNode->childCount(); +} + +QVariant BaseModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + ProjectNode *node = indexToNode(index); + switch (role) { + case Qt::DisplayRole: + return node->text(); + case Qt::DecorationRole: + return node->icon(); + case Qt::FontRole: + { + switch (node->type()) { + case NODE_MAP_FUNCTION: + case NODE_WATERMARK: + case NODE_MESSAGE: + case NODE_WARNING: + case NODE_ERROR: + case NODE_TEMPLATE: + break; + default: + if (node->parent()->type() == NODE_ROOT) { + QFont font; + font.setBold(true); + return font; + } + } + } + break; + case Qt::BackgroundColorRole: + if (node->type() == NODE_WARNING) + return QColor(0xff, 0xf8, 0xe3); + else if (node->type() == NODE_ERROR) + return QColor(0xff, 0xf6, 0xf4); + break; + case Qt::TextColorRole: + if (node->type() == NODE_ERROR) + return QColor(0xff, 0x3c, 0x08); + break; + case Qt::Vmp::StaticTextRole: + { + int size = 0; + switch (node->type()) + { + case NODE_FUNCTIONS: + size = (int)reinterpret_cast<FunctionBundleList*>(node->data())->count(); + break; + case NODE_MAP_FOLDER: + if (node->parent()->type() == NODE_ROOT) { + QList<ProjectNode *> nodeList = node->children(); + for (int i = 0; i < nodeList.size(); i++) { + ProjectNode *child = nodeList[i]; + if (child->type() == NODE_MAP_FOLDER) + nodeList.append(child->children()); + else + size++; + } + break; + } + case NODE_FOLDER: + case NODE_IMPORT_FOLDER: + case NODE_EXPORT_FOLDER: + case NODE_FILE_FOLDER: + { + QListIterator<ProjectNode *> i(node->children()); + while (i.hasNext()) { + NodeType childType = i.next()->type(); + if (childType != NODE_FOLDER && childType != NODE_MAP_FOLDER && childType != NODE_FILE_FOLDER) + size++; + } + } + break; + case NODE_RESOURCE_FOLDER: + case NODE_IMPORT: + case NODE_IMPORTS: + case NODE_EXPORTS: + case NODE_SEGMENTS: + case NODE_RESOURCES: + case NODE_LICENSES: + case NODE_LOAD_COMMANDS: + case NODE_SEGMENT: + size = node->childCount(); + break; +#ifdef ULTIMATE + case NODE_FILES: + case NODE_ASSEMBLIES: + size = (int)reinterpret_cast<FileManager*>(node->data())->count(); + break; +#endif + case NODE_WATERMARK: + size = (int)reinterpret_cast<Watermark*>(node->data())->use_count(); + break; + } + if (size > 0) + return QString("(%1)").arg(size); + } + break; + case Qt::Vmp::StaticColorRole: + return QColor(0x9b, 0xa2, 0xaa); + } + return QVariant(); +} + +QModelIndex BaseModel::nodeToIndex(ProjectNode *node) const +{ + if (!node || node == root_) + return QModelIndex(); + + return createIndex(node->parent()->children().indexOf(node), 0, node); +} + +QModelIndex BaseModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) + return QModelIndex(); + + ProjectNode *parentNode = indexToNode(parent); + ProjectNode *childNode = parentNode->children().value(row); + if (!childNode) + return QModelIndex(); + + return createIndex(row, column, childNode); +} + +void BaseModel::setCore(Core *core) +{ + clear(); + core_ = core; +} + +void BaseModel::clear() +{ + root_->clear(); + objectToNode_.clear(); +} + +void BaseModel::setObjectNode(void *object, ProjectNode *node) +{ + objectToNode_[object] = node; +} + +QModelIndex BaseModel::objectToIndex(void *object) const +{ + return nodeToIndex(objectToNode(object)); +} + +ProjectNode *BaseModel::objectToNode(void *object) const +{ + return objectToNode_[object]; +} + +bool BaseModel::removeNode(void *object) +{ + ProjectNode *node = objectToNode(object); + if (!node) + return false; + + removeObject(object); + + ProjectNode *parent = node->parent(); + int i = parent->children().indexOf(node); + beginRemoveRows(nodeToIndex(parent), i, i); + emit nodeRemoved(node); + delete node; + endRemoveRows(); + return true; +} + +void BaseModel::updateNode(ProjectNode *node) +{ + QModelIndex index = nodeToIndex(node); + dataChanged(index, index); + emit nodeUpdated(node); +} + +void BaseModel::removeObject(void *object) +{ + objectToNode_.remove(object); + emit objectRemoved(object); +} + +void BaseModel::createFunctionsTree(ProjectNode *root) +{ + size_t i, count; + int k, j; + QList<QString> classList; + QList<QString> delimList; + QList<ProjectNode *> folderList; + QMap<ProjectNode *, QString> delimMap; + QMap<QString, ProjectNode *> classMap; + NodeType folder_type; + QString delim; + ushort u; + ProjectNode *folder, *node, *child; + MapFunctionBundleList *map_function_list = NULL; + IImport *import = NULL; + IExportList *export_list = NULL; + + switch (root->type()) { +#ifdef LITE + case NODE_FUNCTIONS: +#else + case NODE_ROOT: +#endif + if (!core()->input_file()) + return; + map_function_list = core()->input_file()->map_function_list(); + count = map_function_list->count(); + folder_type = NODE_MAP_FOLDER; + break; + case NODE_IMPORT: + import = static_cast<IImport*>(root->data()); + count = import->count(); + folder_type = NODE_IMPORT_FOLDER; + break; + case NODE_EXPORTS: + export_list = static_cast<IExportList*>(root->data()); + count = export_list->count(); + folder_type = NODE_EXPORT_FOLDER; + break; + default: + return; + } + + for (i = 0; i < count; i++) { + MapFunctionBundle *func = NULL; + IImportFunction *import_func = NULL; + IExport *export_func = NULL; + QString funcName; + + switch (root->type()) { +#ifdef LITE + case NODE_FUNCTIONS: +#else + case NODE_ROOT: +#endif + func = map_function_list->item(i); + if (!func->is_code()) + continue; + funcName = QString::fromUtf8(func->display_name(false).c_str()); + break; + case NODE_IMPORT: + import_func = import->item(i); + funcName = QString::fromUtf8(import_func->display_name(false).c_str()); + break; + case NODE_EXPORTS: + export_func = export_list->item(i); + funcName = QString::fromUtf8(export_func->display_name(false).c_str()); + break; + } + + size_t c = 0; + int p = 0; + classList.clear(); + delimList.clear(); + delim.clear(); + for (k = 0; k < funcName.size(); k++) { + u = funcName[k].unicode(); + switch (u) { + case '<': + c++; + break; + case '>': + c--; + break; + case ':': + if (c == 0 && k > 0 && funcName[k - 1].unicode() == ':') { + if (funcName[p] == '`') + p++; + classList.push_back(funcName.mid(p, k - p - 1)); + delimList.push_back(delim); + delim = "::"; + p = k + 1; + } + break; + case '.': + if (c == 0 && k > 0 && funcName[k - 1].unicode() != ':') { + classList.push_back(funcName.mid(p, k - p)); + delimList.push_back(delim); + delim = QChar(u); + p = k + 1; + } + break; + case '/': + if (c == 0 && k > 0) { + classList.push_back(funcName.mid(p, k - p)); + delimList.push_back(delim); + delim = QChar(u); + p = k + 1; + } + break; + case ' ': + if (c == 0) + p = k + 1; + break; + case '(': + case '"': + k = funcName.size(); + break; + } + } + + folder = root; + QString fullClassName; + for (k = 0; k < classList.size(); k++) { + QString className = classList[k]; + delim = delimList[k]; + fullClassName = fullClassName + delim + className; + + ProjectNode *classFolder; + auto it = classMap.upperBound(fullClassName); + if (it != classMap.begin() && (it - 1).key() == fullClassName) + classFolder = (it - 1).value(); + else { + classFolder = new ProjectNode(NULL, folder_type); + if (it == classMap.end()) { + for (j = 0; j < folder->childCount(); j++) { + if (folder->child(j)->type() != folder_type) + break; + } + } + else + j = folder->children().indexOf(*it); + folder->insertChild(j, classFolder); + classFolder->setText(className); + classFolder->setIcon(nodeIcon(classFolder->type())); + + delimMap[classFolder] = delim; + classMap[fullClassName] = classFolder; + } + folder = classFolder; + } + + switch (root->type()) { +#ifdef LITE + case NODE_FUNCTIONS: +#else + case NODE_ROOT: +#endif + { + node = new ProjectNode(folder, NODE_MAP_FUNCTION, func); + node->setText(QString::fromUtf8(func->display_name().c_str())); + node->setIcon(functionIcon(core()->input_file()->function_list()->GetFunctionByName(func->name()))); + setObjectNode(func, node); + } + break; + case NODE_IMPORT: + { + node = new ProjectNode(folder, NODE_IMPORT_FUNCTION, import_func); + node->setText(QString::fromUtf8(import_func->display_name().c_str())); + node->setIcon(nodeIcon(node->type())); + setObjectNode(import_func, node); + } + break; + case NODE_EXPORTS: + { + node = new ProjectNode(folder, NODE_EXPORT, export_func); + node->setText(QString::fromUtf8(export_func->display_name().c_str())); + node->setIcon(nodeIcon(node->type())); + } + break; + } + } + + // optimize + folderList.push_back(root); + for (k = 0; k < folderList.size(); k++) { + folder = folderList[k]; + if (folder->childCount() == 1 && folder->child(0)->type() == folder_type) { + child = folder->child(0); + while (child->childCount()) { + node = child->child(0); + child->removeChild(node); + folder->addChild(node); + } + folder->setText(folder->text() + delimMap[child] + child->text()); + + delete child; + j = folderList.indexOf(child); + if (j != -1) + folderList[j] = folder; + } + } +} + +void BaseModel::localize() +{ + if (isEmpty()) + return; + + QList<ProjectNode*> nodes = root()->children(); + if (nodes.isEmpty()) + nodes.append(root()); + + for (int i = 0; i < nodes.count(); i++) { + ProjectNode *node = nodes[i]; + node->localize(); + updateNode(node); + } +} + +/** + * ProjectModel + */ + +ProjectModel::ProjectModel(QObject *parent) + : BaseModel(parent), nodeFunctions_(NULL), +#ifdef ULTIMATE + nodeLicenses_(NULL), nodeFiles_(NULL), +#endif +#ifndef LITE + nodeScript_(NULL), +#endif + nodeOptions_(NULL) +{ + +} + +ProjectModel::~ProjectModel() +{ + +} + +Qt::ItemFlags ProjectModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags res = QAbstractItemModel::flags(index); + if (res & Qt::ItemIsSelectable) { + ProjectNode *node = indexToNode(index); + if (node) { + if (node->type() == NODE_FOLDER || node->type() == NODE_FUNCTION || node->type() == NODE_FILE_FOLDER || node->type() == NODE_FILE) + res |= Qt::ItemIsDragEnabled; + if (node->type() == NODE_FUNCTIONS || node->type() == NODE_FOLDER || node->type() == NODE_FILES || node->type() == NODE_FILE_FOLDER || node->type() == NODE_ASSEMBLIES) + res |= Qt::ItemIsDropEnabled; + if ((node->type() == NODE_FOLDER && !static_cast<Folder *>(node->data())->read_only()) || node->type() == NODE_LICENSE || node->type() == NODE_FILE_FOLDER || node->type() == NODE_FILE) + res |= Qt::ItemIsEditable; + } + } + return res; +} + +QStringList ProjectModel::mimeTypes() const +{ + return QStringList() << QLatin1String("application/x-projectmodeldatalist"); +} + +QMimeData *ProjectModel::mimeData(const QModelIndexList &indexes) const +{ + if (indexes.count() <= 0) + return 0; + QStringList types = mimeTypes(); + if (types.isEmpty()) + return 0; + QMimeData *data = new QMimeData(); + QString format = types.at(0); + QByteArray encoded; + QDataStream stream(&encoded, QIODevice::WriteOnly); + for (QModelIndexList::ConstIterator it = indexes.begin(); it != indexes.end(); ++it) { + ProjectNode *node = indexToNode(*it); + if (!node) + continue; + + stream << node->type(); + switch (node->type()) { + case NODE_FUNCTION: + { + FunctionBundle *func = reinterpret_cast<FunctionBundle *>(node->data()); + stream << QString::fromUtf8(func->id().c_str()); + } + break; + case NODE_FOLDER: + { + Folder *folder = reinterpret_cast<Folder *>(node->data()); + stream << QString::fromUtf8(folder->id().c_str()); + } + break; +#ifdef ULTIMATE + case NODE_FILE_FOLDER: + { + FileFolder *folder = reinterpret_cast<FileFolder *>(node->data()); + stream << QString::fromUtf8(folder->id().c_str()); + } + break; + case NODE_FILE: + { + InternalFile *file = reinterpret_cast<InternalFile *>(node->data()); + stream << (int)file->id(); + } + break; +#endif + } + } + data->setData(format, encoded); + return data; +} + +bool ProjectModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int /*row*/, int /*column*/, const QModelIndex &parent) +{ + if (!data || !(action == Qt::CopyAction || action == Qt::MoveAction)) + return false; + QStringList types = mimeTypes(); + if (types.isEmpty()) + return false; + QString format = types.at(0); + if (!data->hasFormat(format)) + return false; + ProjectNode *dst = indexToNode(parent); + if (!dst) + return false; + + if (dst->type()== NODE_FILES || dst->type() == NODE_ASSEMBLIES || dst->type()== NODE_FILE_FOLDER || dst->type()== NODE_FILE) { +#ifdef ULTIMATE + FileFolder *dst_folder; + switch (dst->type()) { + case NODE_FILE: + dst_folder = reinterpret_cast<InternalFile *>(dst->data())->folder(); + break; + case NODE_FILE_FOLDER: + dst_folder = reinterpret_cast<FileFolder *>(dst->data()); + break; + case NODE_FILES: + case NODE_ASSEMBLIES: + dst_folder = NULL; + break; + default: + return false; + } + QByteArray encoded = data->data(format); + QDataStream stream(&encoded, QIODevice::ReadOnly); + while (!stream.atEnd()) { + int t; + stream >> t; + switch (t) { + case NODE_FILE: + { + int id; + stream >> id; + InternalFile *file = core()->file_manager()->item((size_t)id); + file->set_folder(dst_folder); + } + break; + case NODE_FILE_FOLDER: + { + QString str_id; + stream >> str_id; + FileFolder *folder = core()->file_manager()->folder_list()->GetFolderById(str_id.toUtf8().constData()); + if (folder) + folder->set_owner(dst_folder ? dst_folder : core()->file_manager()->folder_list()); + } + break; + } + } +#endif + } else { + Folder *dst_folder; + switch (dst->type()) { + case NODE_FUNCTION: + dst_folder = reinterpret_cast<IFunction *>(dst->data())->folder(); + break; + case NODE_FOLDER: + dst_folder = reinterpret_cast<Folder *>(dst->data()); + break; + case NODE_FUNCTIONS: + dst_folder = NULL; + break; + default: + return false; + } + QByteArray encoded = data->data(format); + QDataStream stream(&encoded, QIODevice::ReadOnly); + while (!stream.atEnd()) { + int t; + stream >> t; + switch (t) { + case NODE_FUNCTION: + { + QString str_id; + stream >> str_id; + FunctionBundle *func = core()->input_file()->function_list()->GetFunctionById(str_id.toUtf8().constData()); + if (func) + func->set_folder(dst_folder); + } + break; + case NODE_FOLDER: + { + QString str_id; + stream >> str_id; + Folder *folder = core()->input_file()->folder_list()->GetFolderById(str_id.toUtf8().constData()); + if (folder) + folder->set_owner(dst_folder ? dst_folder : core()->input_file()->folder_list()); + } + break; + } + } + } + return true; +} + +QVariant ProjectModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const +{ + if (role == Qt::DisplayRole) { + if (section == 0) + return QString::fromUtf8(language[lsProject].c_str()); + } + return QVariant(); +} + +void ProjectModel::addFolder(Folder *folder) +{ + ProjectNode *node = internalAddFolder(folder); + if (node) { + updateNode(node); + emit modified(); + } +} + +void ProjectModel::updateFolder(Folder *folder) +{ + ProjectNode *node = internalUpdateFolder(folder); + if (node) { + updateNode(node); + emit modified(); + } +} + +void ProjectModel::removeFolder(Folder *folder) +{ + if (removeNode(folder)) + emit modified(); +} + +ProjectNode *ProjectModel::internalAddFolder(Folder *folder) +{ +#ifdef LITE + return NULL; +#else + ProjectNode *nodeFolder = objectToNode(folder->owner()); + if (!nodeFolder) + nodeFolder = nodeFunctions_; + ProjectNode *node = new ProjectNode(NULL, NODE_FOLDER, (void *)folder); + node->setText(QString::fromUtf8(folder->name().c_str())); + node->setIcon(nodeIcon(node->type())); + QList<ProjectNode *> folderList = nodeFolder->children(); + int index = folderList.size(); + for (int i = 0; i < folderList.size(); i++) { + if (folderList[i]->type() != NODE_FOLDER) { + index = i; + break; + } + } + beginInsertRows(nodeToIndex(nodeFolder), index, index); + nodeFolder->insertChild(index, node); + endInsertRows(); + + setObjectNode(folder, node); + return node; +#endif +} + +ProjectNode *ProjectModel::internalUpdateFolder(Folder *folder) +{ +#ifdef LITE + return NULL; +#else + ProjectNode *node = objectToNode(folder); + if (!node) + return NULL; + + node->setText(QString::fromUtf8(folder->name().c_str())); + + ProjectNode *folder_node = folder->owner() ? objectToNode(folder->owner()) : nodeFunctions_; + ProjectNode *parent_node = node->parent(); + if (folder_node && parent_node && parent_node != folder_node) { + int index_from = parent_node->children().indexOf(node); + int index_to = folder_node->childCount(); + for (int i = 0; i < folder_node->childCount(); i++) { + if (folder_node->child(i)->type() != NODE_FOLDER) { + index_to = i; + break; + } + } + beginMoveRows(nodeToIndex(parent_node), index_from, index_from, nodeToIndex(folder_node), index_to); + parent_node->removeChild(node); + folder_node->insertChild(index_to, node); + endMoveRows(); + } + + return node; +#endif +} + +void ProjectModel::addFunction(IFunction *func) +{ + ProjectNode *node = internalAddFunction(func); + if (node) { + updateNode(node); + emit modified(); + } +} + +void ProjectModel::updateFunction(IFunction *func) +{ + ProjectNode *node = internalUpdateFunction(func); + if (node) { + updateNode(node); + emit modified(); + } +} + +void ProjectModel::removeFunction(IFunction *func) +{ +#ifdef LITE + FunctionBundle *bundle = core()->input_file()->function_list()->GetFunctionByFunc(func); + if (!bundle) + return; + + removeObject(func); + + FunctionArch *func_arch = bundle->GetArchByFunction(func); + if (func_arch) + delete func_arch; + if (bundle->count() == 0) + delete bundle; + ProjectNode *node = internalUpdateFunction(func); + if (node) + updateNode(node); +#else + ProjectNode *node = objectToNode(func); + if (!node) + return; + removeObject(func); + + FunctionBundle *bundle = reinterpret_cast<FunctionBundle *>(node->data()); + FunctionArch *func_arch = bundle->GetArchByFunction(func); + if (func_arch) + delete func_arch; + if (bundle->count() == 0) { + removeNode(bundle); + delete bundle; + } +#endif + emit modified(); +} + +ProjectNode *ProjectModel::internalAddFunction(IFunction *func) +{ +#ifndef LITE + FunctionBundle *bundle = +#endif + core()->input_file()->function_list()->Add(func->owner()->owner(), func); +#ifndef LITE + ProjectNode *nodeFolder = objectToNode(func->folder()); + if (!nodeFolder) + nodeFolder = nodeFunctions_; + + ProjectNode *node = objectToNode(bundle); + if (!node) { + beginInsertRows(nodeToIndex(nodeFolder), nodeFolder->childCount(), nodeFolder->childCount()); + node = new ProjectNode(nodeFolder, NODE_FUNCTION, bundle); + endInsertRows(); + setObjectNode(bundle, node); + } + setObjectNode(func, node); + +#endif + return internalUpdateFunction(func); +} + +ProjectNode *ProjectModel::internalUpdateFunction(IFunction *func) +{ +#ifdef LITE + IArchitecture *arch = func->owner()->owner(); + MapFunctionBundle *map_func = core()->input_file()->map_function_list()->GetFunctionByAddress(arch, func->address()); + if (!map_func) + return NULL; + + ProjectNode *node = objectToNode(map_func); + if (!node) + return NULL; + + node->setIcon(functionIcon(core()->input_file()->function_list()->GetFunctionByAddress(arch, func->address()))); +#else + ProjectNode *node = objectToNode(func); + if (!node) + return NULL; + + FunctionBundle *bundle = reinterpret_cast<FunctionBundle *>(node->data()); + std::string func_name = bundle->display_name(); + node->setText(func_name.empty() ? QString::fromUtf8(bundle->display_address().c_str()) : QString::fromUtf8(func_name.c_str())); + node->setIcon(functionIcon(bundle)); + + ProjectNode *folder_node = bundle->folder() ? objectToNode(bundle->folder()) : nodeFunctions_; + ProjectNode *parent_node = node->parent(); + if (folder_node && parent_node && parent_node != folder_node) { + int i = parent_node->children().indexOf(node); + beginMoveRows(nodeToIndex(parent_node), i, i, nodeToIndex(folder_node), folder_node->childCount()); + parent_node->removeChild(node); + folder_node->addChild(node); + endMoveRows(); + } +#endif + + return node; +} + +void ProjectModel::updateScript() +{ +#ifndef LITE + ProjectNode *node = nodeScript_; + if (!node) + return; + + node->setIcon(nodeIcon(node->type(), !core()->script()->need_compile())); +#endif +} + +#ifdef ULTIMATE +void ProjectModel::addLicense(License *license) +{ + ProjectNode *node = internalAddLicense(license); + if (node) { + updateNode(node); + emit modified(); + } +} + +void ProjectModel::updateLicense(License *license) +{ + ProjectNode *node = internalUpdateLicense(license); + if (node) { + updateNode(node); + emit modified(); + } +} + +void ProjectModel::removeLicense(License *license) +{ + if (removeNode(license)) + emit modified(); +} + +void ProjectModel::addFileFolder(FileFolder *folder) +{ + ProjectNode *node = internalAddFileFolder(folder); + if (node) { + updateNode(node); + emit modified(); + } +} + +void ProjectModel::updateFileFolder(FileFolder *folder) +{ + ProjectNode *node = internalUpdateFileFolder(folder); + if (node) { + updateNode(node); + emit modified(); + } +} + +void ProjectModel::removeFileFolder(FileFolder *folder) +{ + if (removeNode(folder)) + emit modified(); +} + +void ProjectModel::addFile(InternalFile *file) +{ + ProjectNode *node = internalAddFile(file); + if (node) { + updateNode(node); + emit modified(); + } +} + +void ProjectModel::updateFile(InternalFile *file) +{ + ProjectNode *node = internalUpdateFile(file); + if (node) { + updateNode(node); + emit modified(); + } +} + +void ProjectModel::removeFile(InternalFile *file) +{ + if (removeNode(file)) + emit modified(); +} + +ProjectNode *ProjectModel::internalAddLicense(License *license) +{ + beginInsertRows(nodeToIndex(nodeLicenses_), nodeLicenses_->childCount(), nodeLicenses_->childCount()); + ProjectNode *node = new ProjectNode(nodeLicenses_, NODE_LICENSE, license); + endInsertRows(); + + setObjectNode(license, node); + internalUpdateLicense(license); + return node; +} + +ProjectNode *ProjectModel::internalUpdateLicense(License *license) +{ + ProjectNode *node = objectToNode(license); + if (!node) + return NULL; + + node->setText(QString::fromUtf8(license->customer_name().c_str())); + node->setIcon(nodeIcon(node->type(), license->blocked())); + return node; +} + +ProjectNode *ProjectModel::internalAddFileFolder(FileFolder *folder) +{ + ProjectNode *nodeFolder = objectToNode(folder->owner()); + if (!nodeFolder) + nodeFolder = nodeFiles_; + ProjectNode *node = new ProjectNode(NULL, NODE_FILE_FOLDER, (void *)folder); + node->setText(QString::fromUtf8(folder->name().c_str())); + node->setIcon(nodeIcon(node->type())); + QList<ProjectNode *> folderList = nodeFolder->children(); + int index = folderList.size(); + for (int i = 0; i < folderList.size(); i++) { + if (folderList[i]->type() != NODE_FILE_FOLDER) { + index = i; + break; + } + } + beginInsertRows(nodeToIndex(nodeFolder), index, index); + nodeFolder->insertChild(index, node); + endInsertRows(); + + setObjectNode(folder, node); + return node; +} + +ProjectNode *ProjectModel::internalUpdateFileFolder(FileFolder *folder) +{ + ProjectNode *node = objectToNode(folder); + if (!node) + return NULL; + + node->setText(QString::fromUtf8(folder->name().c_str())); + + ProjectNode *folder_node = folder->owner() ? objectToNode(folder->owner()) : nodeFiles_; + ProjectNode *parent_node = node->parent(); + if (folder_node && parent_node && parent_node != folder_node) { + int index_from = parent_node->children().indexOf(node); + int index_to = folder_node->childCount(); + for (int i = 0; i < folder_node->childCount(); i++) { + if (folder_node->child(i)->type() != NODE_FILE_FOLDER) { + index_to = i; + break; + } + } + beginMoveRows(nodeToIndex(parent_node), index_from, index_from, nodeToIndex(folder_node), index_to); + parent_node->removeChild(node); + folder_node->insertChild(index_to, node); + endMoveRows(); + } + + return node; +} + +ProjectNode *ProjectModel::internalAddFile(InternalFile *file) +{ + if (!nodeFiles_) + return NULL; + + ProjectNode *nodeFolder = objectToNode(file->folder()); + if (!nodeFolder) + nodeFolder = nodeFiles_; + + beginInsertRows(nodeToIndex(nodeFiles_), nodeFiles_->childCount(), nodeFiles_->childCount()); + ProjectNode *node = new ProjectNode(nodeFolder, NODE_FILE, file); + endInsertRows(); + + setObjectNode(file, node); + internalUpdateFile(file); + return node; +} + +ProjectNode *ProjectModel::internalUpdateFile(InternalFile *file) +{ + ProjectNode *node = objectToNode(file); + if (!node) + return NULL; + + node->setText(QString::fromUtf8(file->name().c_str())); + node->setIcon(nodeIcon(node->type())); + ProjectNode *folder_node = file->folder() ? objectToNode(file->folder()) : nodeFiles_; + ProjectNode *parent_node = node->parent(); + if (folder_node && parent_node && parent_node != folder_node) { + int i = parent_node->children().indexOf(node); + beginMoveRows(nodeToIndex(parent_node), i, i, nodeToIndex(folder_node), folder_node->childCount()); + parent_node->removeChild(node); + folder_node->addChild(node); + endMoveRows(); + } + + return node; +} + +void ProjectModel::updateFiles() +{ + ProjectNode *node = nodeFiles_; + if (!node) + return; + + node->setIcon(nodeIcon(node->type(), !core()->file_manager()->need_compile())); + updateNode(node); +} +#endif +#ifndef LITE +QRegularExpression FuncRegex("function\\s+[_a-zA-Z]+[_a-zA-Z0-9]*\\s*\\([^\\)]*\\)"); +void ProjectModel::updateScriptBookmarks() +{ + ProjectNode *parent = nodeScript_; + if (!parent) + return; + + QString script = QString::fromUtf8(core()->script()->text().c_str()); + QRegularExpression multi_space("\\s+"); + int nChild = 0; + auto it = FuncRegex.globalMatch(script); + while(it.hasNext()) { + QString newText = it.next().captured().replace(multi_space, " "); + + if (nChild >= parent->childCount()) { + beginInsertRows(nodeToIndex(nodeScript_), nodeScript_->childCount(), nodeScript_->childCount()); + ProjectNode *node = new ProjectNode(nodeScript_, NODE_SCRIPT_BOOKMARK, core()->script()); + node->setText(newText); + node->setIcon(nodeIcon(node->type())); + endInsertRows(); + } else { + ProjectNode *node = parent->child(nChild); + if(node->text(0).compare(newText)) { + node->setText(newText); + updateNode(node); + } + } + nChild++; + } + if(nChild != parent->childCount()) { + beginRemoveRows(nodeToIndex(parent), nChild, parent->childCount() - 1); + while (nChild != parent->childCount()) { + ProjectNode *node = parent->child(nChild); + emit nodeRemoved(node); + delete node; + } + endRemoveRows(); + } +} +uptr_t ProjectModel::bookmarkNodeToPos(ProjectNode *node) const +{ + uptr_t ret = 0; + int bookIdx = nodeToIndex(node).row(); + QString script = QString::fromUtf8(core()->script()->text().c_str()); + auto it = FuncRegex.globalMatch(script); + int nChild = 0; + while (it.hasNext()) { + auto m = it.next(); + if (nChild == bookIdx) + return m.capturedStart(); + nChild++; + } + return ret; +} +#endif + +void ProjectModel::setCore(Core *core) +{ + BaseModel::setCore(core); + + if (!core) { + beginResetModel(); + nodeFunctions_ = NULL; +#ifdef ULTIMATE + nodeLicenses_ = NULL; + nodeFiles_ = NULL; +#endif +#ifndef LITE + nodeScript_ = NULL; +#endif + nodeOptions_ = NULL; + endResetModel(); + return; + } + + size_t i, j; + + IFile *file = core->input_file(); + if (file) { + nodeFunctions_ = new ProjectNode(root(), NODE_FUNCTIONS, file->function_list()); + nodeFunctions_->setText(QString::fromUtf8(language[lsFunctionsForProtection].c_str())); + nodeFunctions_->setIcon(nodeIcon(nodeFunctions_->type())); + +#ifdef LITE + setObjectNode(file->map_function_list(), nodeFunctions_); + createFunctionsTree(nodeFunctions_); +#else + setObjectNode(file->folder_list(), nodeFunctions_); + std::vector<Folder*> folderList = file->folder_list()->GetFolderList(); + for (i = 0; i < folderList.size(); i++) { + internalAddFolder(folderList[i]); + } +#endif + + for (i = 0; i < file->count(); i++) { + IArchitecture *arch = file->item(i); + if (!arch->visible()) + continue; + + for (j = 0; j < arch->function_list()->count(); j++) { + internalAddFunction(arch->function_list()->item(j)); + } + } + } + +#ifdef ULTIMATE + LicensingManager *licensing_manager = core->licensing_manager(); + nodeLicenses_ = new ProjectNode(root(), NODE_LICENSES, licensing_manager); + nodeLicenses_->setText(QString::fromUtf8(language[lsLicenses].c_str())); + nodeLicenses_->setIcon(nodeIcon(nodeLicenses_->type())); + for (i = 0; i < licensing_manager->count(); i++) { + internalAddLicense(licensing_manager->item(i)); + } + + if (file && (file->disable_options() & cpVirtualFiles) == 0) { + FileManager *file_manager = core->file_manager(); + if (file->format_name() == "PE" && file->count() > 1) { + nodeFiles_ = new ProjectNode(root(), NODE_ASSEMBLIES, file_manager); + nodeFiles_->setText(QString::fromUtf8(language[lsAssemblies].c_str())); + } + else { + nodeFiles_ = new ProjectNode(root(), NODE_FILES, file_manager); + nodeFiles_->setText(QString::fromUtf8(language[lsFiles].c_str())); + } + nodeFiles_->setIcon(nodeIcon(nodeFiles_->type(), !file_manager->need_compile())); + setObjectNode(file_manager->folder_list(), nodeFiles_); + + std::vector<FileFolder*> folderList = file_manager->folder_list()->GetFolderList(); + for (i = 0; i < folderList.size(); i++) { + internalAddFileFolder(folderList[i]); + } + for (i = 0; i < file_manager->count(); i++) { + internalAddFile(file_manager->item(i)); + } + } +#endif + + if (file) { +#ifndef LITE + nodeScript_ = new ProjectNode(root(), NODE_SCRIPT, core->script()); + nodeScript_->setText(QString::fromUtf8(language[lsScript].c_str())); + nodeScript_->setIcon(nodeIcon(nodeScript_->type(), !core->script()->need_compile())); + updateScriptBookmarks(); +#endif + + nodeOptions_ = new ProjectNode(root(), NODE_OPTIONS); + nodeOptions_->setText(QString::fromUtf8(language[lsOptions].c_str())); + nodeOptions_->setIcon(nodeIcon(nodeOptions_->type())); + } +} + +struct FunctionBundleListCompareHelper { + Folder *folder; + int field; + FunctionBundleListCompareHelper(Folder *_folder, int _field) : folder(_folder), field(_field) {} + bool operator () (const FunctionBundle *func1, const FunctionBundle *func2) const + { + if (func1->folder() == func2->folder() && func1->folder() == folder) { + switch (field) { + case 0: + return QString::compare(QString::fromUtf8(func1->display_name().c_str()), QString::fromUtf8(func2->display_name().c_str()), Qt::CaseInsensitive) < 0; + case 1: + return func1->display_address() < func2->display_address(); + case 2: + { + CompilationType ct1 = func1->need_compile() ? func1->compilation_type() : ctNone; + CompilationType ct2 = func2->need_compile() ? func2->compilation_type() : ctNone; + return (ct1 == ct2) ? (func1->compilation_options() < func2->compilation_options()) : (ct1 < ct2); + } + } + } + return func1->folder() < func2->folder(); + } +}; + +#ifdef ULTIMATE +struct LicensingManagerCompareHelper { + int field; + LicensingManagerCompareHelper(int _field) : field(_field) {} + bool operator () (const License *license1, const License *license2) const + { + switch (field) { + case 0: + return QString::compare(QString::fromUtf8(license1->customer_name().c_str()), QString::fromUtf8(license2->customer_name().c_str()), Qt::CaseInsensitive) < 0; + case 1: + return QString::compare(QString::fromUtf8(license1->customer_email().c_str()), QString::fromUtf8(license2->customer_email().c_str()), Qt::CaseInsensitive) < 0; + case 2: + return license1->date().value() < license2->date().value(); + } + return false; + } +}; + +struct FileManagerCompareHelper { + FileFolder *folder; + int field; + FileManagerCompareHelper(FileFolder *_folder, int _field) : folder(_folder), field(_field) {} + bool operator () (const InternalFile *file1, const InternalFile *file2) const + { + if (file1->folder() == file2->folder() && file1->folder() == folder) { + switch (field) { + case 0: + return QString::compare(QString::fromUtf8(file1->name().c_str()), QString::fromUtf8(file2->name().c_str()), Qt::CaseInsensitive) < 0; + case 1: + return QString::compare(QString::fromUtf8(file1->file_name().c_str()), QString::fromUtf8(file2->file_name().c_str()), Qt::CaseInsensitive) < 0; + } + } + return file1->folder() < file2->folder(); + } +}; + +struct FileFolderCompareHelper { + bool operator () (const FileFolder *folder1, const FileFolder *folder2) const + { + return QString::compare(QString::fromUtf8(folder1->name().c_str()), QString::fromUtf8(folder2->name().c_str()), Qt::CaseInsensitive) < 0; + } +}; +#endif + +struct FolderCompareHelper { + bool operator () (const Folder *folder1, const Folder *folder2) const + { + return QString::compare(QString::fromUtf8(folder1->name().c_str()), QString::fromUtf8(folder2->name().c_str()), Qt::CaseInsensitive) < 0; + } +}; + +void ProjectModel::sortNode(ProjectNode *node, int field) +{ + bool isModified = false; + QModelIndex parent = nodeToIndex(node); + QList<ProjectNode*> nodeList = node->children(); + + switch (node->type()) { + case NODE_FUNCTIONS: + case NODE_FOLDER: + { + IFile *file = core()->input_file(); + Folder *folder = (node->type() == NODE_FUNCTIONS) ? core()->input_file()->folder_list() : reinterpret_cast<Folder *>(node->data()); + + if (field == 0) { + std::sort(folder->_begin(),folder->_end(), FolderCompareHelper()); + + QList<int> posList; + for (int i = 0; i < nodeList.size(); i++) { + ProjectNode *child = nodeList[i]; + if (child->type() != NODE_FOLDER) + break; + + int j = (int)folder->IndexOf(reinterpret_cast<Folder *>(child->data())); + if (j == -1) + continue; + + int p = posList.size(); + for (int c = 0; c < posList.size(); c++) { + if (posList[c] > j) { + p = c; + break; + } + } + + if (p < i) { + beginMoveRows(parent, i, i, parent, p); + node->removeChild(child); + node->insertChild(p, child); + endMoveRows(); + isModified = true; + } + posList.insert(p, j); + } + } + + if (node->type() == NODE_FUNCTIONS) + folder = NULL; + + std::sort(file->function_list()->_begin(), file->function_list()->_end(), FunctionBundleListCompareHelper(folder, field)); + + QList<FunctionBundle *> funcList; + for (size_t i = 0; i < file->function_list()->count(); i++) { + FunctionBundle *func = file->function_list()->item(i); + if (func->folder() == folder) + funcList.append(func); + } + + int k = 0; + QList<int> posList; + for (int i = 0; i < nodeList.size(); i++) { + ProjectNode *child = nodeList[i]; + if (child->type() == NODE_FOLDER) { + k++; + continue; + } + + int j = funcList.indexOf(reinterpret_cast<FunctionBundle *>(child->data())); + if (j == -1) + continue; + + int p = posList.size(); + for (int c = 0; c < posList.size(); c++) { + if (posList[c] > j) { + p = c; + break; + } + } + + if (k + p < i) { + beginMoveRows(parent, i, i, parent, k + p); + node->removeChild(child); + node->insertChild(k + p, child); + endMoveRows(); + isModified = true; + } + posList.insert(p, j); + } + } + break; +#ifdef ULTIMATE + case NODE_LICENSES: + { + std::sort(core()->licensing_manager()->_begin(), core()->licensing_manager()->_end(), LicensingManagerCompareHelper(field)); + + QList<int> posList; + for (int i = 0; i < node->childCount(); i++) { + ProjectNode *child = node->child(i); + + int j = (int)core()->licensing_manager()->IndexOf(reinterpret_cast<License *>(child->data())); + if (j == -1) + continue; + + int p = posList.size(); + for (int c = 0; c < posList.size(); c++) { + if (posList[c] > j) { + p = c; + break; + } + } + + if (p < i) { + beginMoveRows(parent, i, i, parent, p); + node->removeChild(child); + node->insertChild(p, child); + endMoveRows(); + isModified = true; + } + posList.insert(p, j); + } + } + break; + case NODE_FILES: + case NODE_FILE_FOLDER: + case NODE_ASSEMBLIES: + { + FileFolder *folder = (node->type() == NODE_FILES || node->type() == NODE_ASSEMBLIES) ? core()->file_manager()->folder_list() : reinterpret_cast<FileFolder *>(node->data()); + + if (field == 0) { + std::sort(folder->_begin(),folder->_end(), FileFolderCompareHelper()); + + QList<int> posList; + for (int i = 0; i < node->childCount(); i++) { + ProjectNode *child = node->child(i); + if (child->type() != NODE_FILE_FOLDER) + break; + + int j = (int)folder->IndexOf(reinterpret_cast<FileFolder *>(child->data())); + if (j == -1) + continue; + + int p = posList.size(); + for (int c = 0; c < posList.size(); c++) { + if (posList[c] > j) { + p = c; + break; + } + } + + if (p < i) { + beginMoveRows(parent, i, i, parent, p); + node->removeChild(child); + node->insertChild(p, child); + endMoveRows(); + isModified = true; + } + posList.insert(p, j); + } + } + + if (node->type() == NODE_FILES || node->type() == NODE_ASSEMBLIES) + folder = NULL; + + std::sort(core()->file_manager()->_begin(), core()->file_manager()->_end(), FileManagerCompareHelper(folder, field)); + + QList<InternalFile *> fileList; + for (size_t i = 0; i < core()->file_manager()->count(); i++) { + InternalFile *file = core()->file_manager()->item(i); + if (file->folder() == folder) + fileList.append(file); + } + + int k = 0; + QList<int> posList; + for (int i = 0; i < node->childCount(); i++) { + ProjectNode *child = node->child(i); + if (child->type() == NODE_FILE_FOLDER) { + k++; + continue; + } + + int j = fileList.indexOf(reinterpret_cast<InternalFile *>(child->data())); + if (j == -1) + continue; + + int p = posList.size(); + for (int c = 0; c < posList.size(); c++) { + if (posList[c] > j) { + p = c; + break; + } + } + + if (k + p < i) { + beginMoveRows(parent, i, i, parent, k + p); + node->removeChild(child); + node->insertChild(k + p, child); + endMoveRows(); + isModified = true; + } + posList.insert(p, j); + } + } + break; + +#endif + } + + if (isModified) + emit modified(); +} + +/** + * FunctionsModel + */ + +FunctionsModel::FunctionsModel(QObject *parent) + : BaseModel(parent) +{ + +} + +void FunctionsModel::setCore(Core *core) +{ + beginResetModel(); + BaseModel::setCore(core); + + if (core) + createFunctionsTree(root()); + + endResetModel(); +} + +void FunctionsModel::updateFunction(IFunction *func) +{ + IArchitecture *arch = func->owner()->owner(); + MapFunctionBundle *map_func = core()->input_file()->map_function_list()->GetFunctionByAddress(arch, func->address()); + if (!map_func) + return; + + ProjectNode *node = objectToNode(map_func); + if (!node) + return; + + node->setIcon(functionIcon(core()->input_file()->function_list()->GetFunctionByAddress(arch, func->address()))); + updateNode(node); +} + +void FunctionsModel::removeFunction(IFunction *func) +{ + updateFunction(func); +} + +QVariant FunctionsModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const +{ + if (role == Qt::DisplayRole) { + if (section == 0) + return QString::fromUtf8(language[lsFunctions].c_str()); + } + return QVariant(); +} + +/** + * InfoModel + */ + +InfoModel::InfoModel(QObject *parent) + : BaseModel(parent) +{ + +} + +void InfoModel::setCore(Core *core) +{ + BaseModel::setCore(core); + + if (!core || !core->input_file()) { + beginResetModel(); + endResetModel(); + return; + } + + size_t i, j, k; + QList<ProjectNode*> nodes; + for (i = 0; i < core->input_file()->count(); i++) { + IArchitecture *arch = core->input_file()->item(i); + if (!arch->visible()) + continue; + + ProjectNode *node = new ProjectNode(root(), NODE_ARCHITECTURE, arch); + node->setText(arch->name().c_str()); + node->setIcon(nodeIcon(node->type())); + nodes.append(node); + } + + IArchitecture *default_arch = NULL; + if (nodes.size() == 1) { + default_arch = reinterpret_cast<IArchitecture*>(nodes[0]->data()); + delete nodes[0]; + nodes[0] = root(); + } + + for (int f = 0; f < nodes.size(); f++) { + ProjectNode *nodeFile = nodes[f]; + IArchitecture *file = (nodeFile->type() == NODE_ROOT) ? default_arch : reinterpret_cast<IArchitecture*>(nodeFile->data()); + assert(file); + if (file == NULL) continue; + + if (file->command_list()->count()) { + ProjectNode *nodeCommands = new ProjectNode(nodeFile, NODE_LOAD_COMMANDS); + nodeCommands->setText(QString::fromUtf8(language[lsDirectories].c_str())); + nodeCommands->setIcon(nodeIcon(nodeCommands->type())); + for (i = 0; i < file->command_list()->count(); i++) { + ILoadCommand *command = file->command_list()->item(i); + if (!command->visible()) + continue; + + ProjectNode *node = new ProjectNode(nodeCommands, NODE_LOAD_COMMAND, command); + node->setText(QString::fromUtf8(command->name().c_str())); + node->setIcon(nodeIcon(node->type())); + setObjectNode(command, node); + } + } + + ProjectNode *nodeSegments = new ProjectNode(nodeFile, NODE_SEGMENTS); + nodeSegments->setText(QString::fromUtf8(language[lsSegments].c_str())); + nodeSegments->setIcon(nodeIcon(nodeSegments->type())); + for (i = 0; i < file->segment_list()->count(); i++) { + ISection *segment = file->segment_list()->item(i); + + ProjectNode *node = new ProjectNode(nodeSegments, NODE_SEGMENT, segment); + node->setText(QString::fromUtf8(segment->name().c_str())); + bool has_children = false; + for (j = 0; j < file->section_list()->count(); j++) { + if (file->section_list()->item(j)->parent() == segment) { + has_children = true; + break; + } + } + + node->setIcon(nodeIcon(has_children ? NODE_FOLDER : node->type(), segment->excluded_from_packing() || segment->excluded_from_memory_protection())); + setObjectNode(segment, node); + } + + for (i = 0; i < file->section_list()->count(); i++) { + ISection *section = file->section_list()->item(i); + j = file->segment_list()->IndexOf(section->parent()); + if (j == NOT_ID) + continue; + + ProjectNode *node = new ProjectNode(nodeSegments->child((int)j), NODE_SECTION, section); + node->setText(QString::fromUtf8(section->name().c_str())); + node->setIcon(nodeIcon(node->type())); + } + + if (file->import_list()->count()) { + ProjectNode *nodeImports = new ProjectNode(nodeFile, NODE_IMPORTS, file->import_list()); + nodeImports->setText(QString::fromUtf8(language[lsImports].c_str())); + nodeImports->setIcon(nodeIcon(nodeImports->type())); + for (i = 0; i < file->import_list()->count(); i++) { + IImport *import = file->import_list()->item(i); + + ProjectNode *nodeImport = new ProjectNode(nodeImports, NODE_IMPORT, import); + nodeImport->setText(QString::fromUtf8(import->name().c_str())); + nodeImport->setIcon(nodeIcon(nodeImport->type(), import->excluded_from_import_protection())); + setObjectNode(import, nodeImport); + + createFunctionsTree(nodeImport); + + if (import->name().empty()) { + QList<ProjectNode *> nodeList = nodeImport->children(); + for (int k = 0; k < nodeList.count(); k++) { + ProjectNode *child = nodeList[k]; + nodeImport->removeChild(child); + nodeImports->addChild(child); + } + delete nodeImport; + } + } + } + + if (file->export_list()->count()) { + ProjectNode *nodeExports = new ProjectNode(nodeFile, NODE_EXPORTS, file->export_list()); + nodeExports->setText(QString::fromUtf8(language[lsExports].c_str())); + nodeExports->setIcon(nodeIcon(nodeExports->type())); + + createFunctionsTree(nodeExports); + } + + if (file->resource_list() && file->resource_list()->count()) { + ProjectNode *nodeResources = new ProjectNode(nodeFile, NODE_RESOURCES, file->resource_list()); + nodeResources->setText(QString::fromUtf8(language[lsResources].c_str())); + nodeResources->setIcon(nodeIcon(nodeResources->type())); + std::vector<IResource *> resourceList; + for (i = 0; i < file->resource_list()->count(); i++) { + resourceList.push_back(file->resource_list()->item(i)); + } + for (k = 0; k < resourceList.size(); k++) { + IResource *resource = resourceList[k]; + for (j = 0; j < resource->count(); j++) { + resourceList.push_back(resource->item(j)); + } + } + for (k = 0; k < resourceList.size(); k++) { + IResource *resource = resourceList[k]; + + ProjectNode *nodeParent = objectToNode(resource->owner()); + if (!nodeParent) + nodeParent = nodeResources; + ProjectNode *node = new ProjectNode(nodeParent, resource->is_directory() ? NODE_RESOURCE_FOLDER : NODE_RESOURCE, resource); + node->setText(QString::fromUtf8(resource->name().c_str())); + node->setIcon(nodeIcon(node->type(), node->type() == NODE_RESOURCE && resource->excluded_from_packing())); + setObjectNode(resource, node); + } + } + + ProjectNode *nodeCalc = new ProjectNode(nodeFile, NODE_CALC, file); + nodeCalc->setText(QString::fromUtf8(language[lsCalculator].c_str())); + nodeCalc->setIcon(nodeIcon(nodeCalc->type())); + + ProjectNode *nodeDump = new ProjectNode(nodeFile, NODE_DUMP, file); + nodeDump->setText(QString::fromUtf8(language[lsDump].c_str())); + nodeDump->setIcon(nodeIcon(nodeDump->type())); + setObjectNode(file, nodeDump); + } +} + +void InfoModel::updateResource(IResource *resource) +{ + ProjectNode *node = objectToNode(resource); + if (!node) + return; + + node->setIcon(nodeIcon(node->type(), resource->excluded_from_packing())); + updateNode(node); + emit modified(); +} + +void InfoModel::updateSegment(ISection *segment) +{ + ProjectNode *node = objectToNode(segment); + if (!node) + return; + + node->setIcon(nodeIcon(node->childCount() ? NODE_FOLDER : node->type(), segment->excluded_from_packing() || segment->excluded_from_memory_protection())); + updateNode(node); + emit modified(); +} + +void InfoModel::updateImport(IImport *import) +{ + ProjectNode *node = objectToNode(import); + if (!node) + return; + + node->setIcon(nodeIcon(node->type(), import->excluded_from_import_protection())); + updateNode(node); + emit modified(); +} + +QVariant InfoModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const +{ + if (role == Qt::DisplayRole) { + if (section == 0) + return QString::fromUtf8(language[lsDetails].c_str()); + } + return QVariant(); +} + +/** + * SearchModel + */ + +SearchModel::SearchModel(QObject *parent) + : QAbstractItemModel(parent) +{ + +} + +void SearchModel::clear() +{ + if (items_.count()) + removeRows(0, items_.count()); +} + +void SearchModel::search(ProjectNode *directory, const QString &text, bool protectedFunctionsOnly) +{ + beginResetModel(); + QList<ProjectNode *> list; + QRegExp filter(text, Qt::CaseInsensitive, QRegExp::Wildcard); + + items_.clear(); + list.append(directory); + for (int i = 0; i < list.count(); i++) { + ProjectNode *node = list[i]; + for (int j = 0; j < node->childCount(); j++) { + list.insert(i + 1 + j, node->child(j)); + } + + if (node->properties()) + list.insert(i + 1, node->properties()); + + if (node->parent() && node->contains(filter)) { + if (protectedFunctionsOnly) { + switch (node->type()) { + case NODE_MAP_FUNCTION: + { + MapFunctionBundle *map = reinterpret_cast<MapFunctionBundle*>(node->data()); + FunctionBundle *func = map->owner()->owner()->function_list()->GetFunctionByName(map->name()); + if (!func || !func->need_compile()) + continue; + } + break; + default: + continue; + } + } + items_.append(node); + } + } + + endResetModel(); +} + +QModelIndex SearchModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) + return QModelIndex(); + + ProjectNode *node = items_.value(row); + if (!node) + return QModelIndex(); + + return createIndex(row, column, node); +} + +QModelIndex SearchModel::parent(const QModelIndex & /*index*/) const +{ + return QModelIndex(); +} + +int SearchModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + return items_.size(); +} + +int SearchModel::columnCount(const QModelIndex & /*parent*/) const +{ + return 1; +} + +ProjectNode *SearchModel::indexToNode(const QModelIndex &index) const +{ + if (index.isValid()) + return static_cast<ProjectNode *>(index.internalPointer()); + return NULL; +} + +QVariant SearchModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + ProjectNode *node = indexToNode(index); + assert(node); + if (node != NULL) { + switch (role) { + case Qt::DisplayRole: + return node->text(index.column()); + case Qt::DecorationRole: + if (index.column() == 0) + return node->icon(); + break; + case Qt::ToolTipRole: + { + QString text = node->path(); + if (!text.isEmpty()) + text += " > " + node->text(index.column()); + return text; + } + break; + } + } + return QVariant(); +} + +QVariant SearchModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int role) const +{ + if (role == Qt::DisplayRole) + return QString::fromUtf8(language[lsSearchResult].c_str()); + return QVariant(); +} + +QModelIndex SearchModel::nodeToIndex(ProjectNode *node) const +{ + int i = items_.indexOf(node); + if (i == -1) + return QModelIndex(); + + return createIndex(i, 0, node); +} + +void SearchModel::updateNode(ProjectNode *node) +{ + int i = items_.indexOf(node); + if (i == -1) + return; + + QModelIndex index = createIndex(i, 0, node); + dataChanged(index, index); +} + +bool SearchModel::removeRows(int position, int rows, const QModelIndex &parent) +{ + bool res; + + beginRemoveRows(parent, position, position + rows - 1); + if (position < 0 || position + rows > items_.size()) { + res = false; + } else { + for (int row = position; row < rows; ++row) + items_.removeAt(position); + res = true; + } + endRemoveRows(); + + return res; +} + +void SearchModel::removeNode(ProjectNode *node) +{ + int i = items_.indexOf(node); + if (i == -1) + return; + + removeRows(i, 1); +} + +/** + * DirectoryModel + */ + +DirectoryModel::DirectoryModel(QObject *parent) + : QAbstractItemModel(parent), directory_(NULL) +{ + +} + +Qt::ItemFlags DirectoryModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags res = QAbstractItemModel::flags(index); + if (res & Qt::ItemIsSelectable) { + ProjectNode *node = indexToNode(index); + if (node) { + if (node->type() == NODE_FILE_FOLDER || node->type() == NODE_FOLDER || node->type() == NODE_FILE || node->type() == NODE_LICENSE) + res |= Qt::ItemIsEditable; + } + } + return res; +} + +void DirectoryModel::setDirectory(ProjectNode *directory) +{ + beginResetModel(); + directory_ = directory; + if (directory_) { + items_ = directory->children(); + } else { + items_.clear(); + } + + endResetModel(); +} + +QModelIndex DirectoryModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) + return QModelIndex(); + + ProjectNode *node = items_.value(row); + if (!node) + return QModelIndex(); + + return createIndex(row, column, node); +} + +QModelIndex DirectoryModel::parent(const QModelIndex & /*index*/) const +{ + return QModelIndex(); +} + +int DirectoryModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + return items_.size(); +} + +QStringList headerLabels(NodeType type) +{ + QStringList res; + switch (type) { + case NODE_FUNCTIONS: + case NODE_FOLDER: + case NODE_MAP_FOLDER: + res << QString::fromUtf8(language[lsName].c_str()) << QString::fromUtf8(language[lsAddress].c_str()) << QString::fromUtf8(language[lsProtection].c_str()); + break; + case NODE_RESOURCES: + case NODE_RESOURCE_FOLDER: + case NODE_LOAD_COMMANDS: + res << QString::fromUtf8(language[lsName].c_str()) << QString::fromUtf8(language[lsAddress].c_str()) << QString::fromUtf8(language[lsSize].c_str()); + break; + case NODE_SEGMENTS: + case NODE_SEGMENT: + res << QString::fromUtf8(language[lsName].c_str()) << QString::fromUtf8(language[lsAddress].c_str()) << QString::fromUtf8(language[lsSize].c_str()) << QString::fromUtf8(language[lsRawAddress].c_str()) << QString::fromUtf8(language[lsRawSize].c_str()) << QString::fromUtf8(language[lsFlags].c_str()); + break; + case NODE_IMPORT: + case NODE_IMPORT_FOLDER: + case NODE_EXPORTS: + case NODE_EXPORT_FOLDER: + res << QString::fromUtf8(language[lsName].c_str()) << QString::fromUtf8(language[lsAddress].c_str()); + break; + case NODE_LICENSES: + res << QString::fromUtf8(language[lsCustomerName].c_str()) << QString::fromUtf8(language[lsEmail].c_str()) << QString::fromUtf8(language[lsDate].c_str()); + break; + case NODE_FILES: + case NODE_FILE_FOLDER: + case NODE_ASSEMBLIES: + res << QString::fromUtf8(language[lsName].c_str()) << QString::fromUtf8(language[lsFileName].c_str()); + break; + default: + res << QString::fromUtf8(language[lsName].c_str()); + break; + } + return res; +}; + +int DirectoryModel::columnCount(const QModelIndex & /*parent*/) const +{ + if (!directory_) + return 0; + + return headerLabels(directory_->type()).size(); +} + +ProjectNode *DirectoryModel::indexToNode(const QModelIndex &index) const +{ + if (index.isValid()) + return static_cast<ProjectNode *>(index.internalPointer()); + return NULL; +} + +QVariant DirectoryModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + ProjectNode *node = indexToNode(index); + if (node != NULL) { + if (role == Qt::DisplayRole) { + return node->text(index.column()); + } else if (role == Qt::DecorationRole) { + if (index.column() == 0) + return node->icon(); + } + } + return QVariant(); +} + +QVariant DirectoryModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const +{ + if (!directory_) + return QVariant(); + + if (role == Qt::DisplayRole) { + return headerLabels(directory_->type()).value(section); + } + return QVariant(); +} + +QModelIndex DirectoryModel::nodeToIndex(ProjectNode *node) const +{ + int i = items_.indexOf(node); + if (i == -1) + return QModelIndex(); + + return createIndex(i, 0, node); +} + +void DirectoryModel::updateNode(ProjectNode *node) +{ + int i = items_.indexOf(node); + if (i == -1) + return; + + QModelIndex index = createIndex(i, 0, node); + dataChanged(index, index); +} + +bool DirectoryModel::removeRows(int position, int rows, const QModelIndex &parent) +{ + bool res; + + beginRemoveRows(parent, position, position + rows - 1); + if (position < 0 || position + rows > items_.size()) { + res = false; + } else { + for (int row = 0; row < rows; ++row) + items_.removeAt(position); + res = true; + } + endRemoveRows(); + + return res; +} + +void DirectoryModel::removeNode(ProjectNode *node) +{ + ProjectNode *parent = directory_; + while (parent) { + if (parent == node) { + setDirectory(NULL); + return; + } + parent = parent->parent(); + } + + int i = items_.indexOf(node); + if (i == -1) + return; + + removeRows(i, 1); +} + +/** + * MapFunctionBundleListModel + */ + +MapFunctionBundleListModel::MapFunctionBundleListModel(IFile &file, bool codeOnly, QObject *parent) + : QAbstractItemModel(parent) +{ + MapFunctionBundleList *map_function_list = file.map_function_list(); + for (size_t i = 0; i < map_function_list->count(); i++) { + MapFunctionBundle *func = map_function_list->item(i); + switch (func->type()) { + case otCode: + case otExport: + case otMarker: + case otAPIMarker: + case otString: + break; + case otUnknown: + continue; + default: + if (codeOnly) + continue; + break; + } + + mapFunctionList_.append(func); + } + + items_ = mapFunctionList_; +} + +int MapFunctionBundleListModel::rowCount(const QModelIndex &parent) const +{ + if (!parent.isValid()) + return items_.size(); + + return 0; +} + +int MapFunctionBundleListModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return 2; +} + +QModelIndex MapFunctionBundleListModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) + return QModelIndex(); + + MapFunctionBundle *bundle = items_.value(row); + if (!bundle) + return QModelIndex(); + + return createIndex(row, column, bundle); +} + +QModelIndex MapFunctionBundleListModel::parent(const QModelIndex & /*index*/) const +{ + return QModelIndex(); +} + +QVariant MapFunctionBundleListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + MapFunctionBundle *func = items_.at(index.row()); + + if (role == Qt::DisplayRole) { + if (index.column() == 0) { + return QString::fromUtf8(func->display_name().c_str()); + } else if (index.column() == 1) { + return QString::fromLatin1(func->display_address().c_str()); + } + } else if (role == Qt::DecorationRole) { + if (index.column() == 0) { + switch (func->type()) { + case otImport: + return nodeIcon(NODE_IMPORT_FUNCTION); + default: + return functionIcon(func->owner()->owner()->function_list()->GetFunctionByName(func->name())); + } + } + } + return QVariant(); +} + +QVariant MapFunctionBundleListModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + switch (section) { + case 0: + return QString::fromUtf8(language[lsName].c_str()); + case 1: + return QString::fromUtf8(language[lsAddress].c_str()); + } + return QVariant(); +} + +void MapFunctionBundleListModel::search(const QString &text) +{ + beginResetModel(); + if (text.isEmpty()) { + items_ = mapFunctionList_; + } else { + items_.clear(); + QRegExp filter(text, Qt::CaseInsensitive, QRegExp::Wildcard); + + for (int i = 0; i < mapFunctionList_.size(); i++) { + MapFunctionBundle *func = mapFunctionList_[i]; + QString name = QString::fromUtf8(func->name().c_str()); + if (name.contains(filter)) + items_.append(func); + } + } + + endResetModel(); +} + +struct MapFunctionBundleListCompareHelper { + int column; + MapFunctionBundleListCompareHelper(int _column) : column(_column) {} + bool operator () (const MapFunctionBundle *func1, const MapFunctionBundle *func2) const + { + switch (column) { + case 0: + return QString::fromUtf8(func1->display_name().c_str()).compare(QString::fromUtf8(func2->display_name().c_str()), Qt::CaseInsensitive) < 0; + case 1: + return func1->display_address() < func2->display_address(); + } + return false; + } +}; + +void MapFunctionBundleListModel::sort(int column, Qt::SortOrder order) +{ + beginResetModel(); + qSort(mapFunctionList_.begin(), mapFunctionList_.end(), MapFunctionBundleListCompareHelper(column)); + if (items_.size() == mapFunctionList_.size()) + items_ = mapFunctionList_; + else + qSort(items_.begin(), items_.end(), MapFunctionBundleListCompareHelper(column)); + endResetModel(); +} + +/** + * MapFunctionListModel + */ + +MapFunctionListModel::MapFunctionListModel(IArchitecture &file, bool codeOnly, QObject *parent) + : QAbstractItemModel(parent) +{ + MapFunctionList *map_function_list = file.map_function_list(); + for (size_t i = 0; i < map_function_list->count(); i++) { + MapFunction *func = map_function_list->item(i); + switch (func->type()) { + case otCode: + case otExport: + case otMarker: + case otAPIMarker: + case otString: + break; + case otUnknown: + continue; + default: + if (codeOnly) + continue; + break; + } + + mapFunctionList_.append(func); + } + + items_ = mapFunctionList_; +} + +int MapFunctionListModel::rowCount(const QModelIndex &parent) const +{ + if (!parent.isValid()) + return items_.size(); + + return 0; +} + +int MapFunctionListModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return 2; +} + +QModelIndex MapFunctionListModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) + return QModelIndex(); + + MapFunction *func = items_.value(row); + if (!func) + return QModelIndex(); + + return createIndex(row, column, func); +} + +QModelIndex MapFunctionListModel::parent(const QModelIndex & /*index*/) const +{ + return QModelIndex(); +} + +QVariant MapFunctionListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + MapFunction *func = items_.at(index.row()); + + if (role == Qt::DisplayRole) { + if (index.column() == 0) { + return QString::fromUtf8(func->display_name().c_str()); + } else if (index.column() == 1) { + return QString::fromLatin1(func->display_address("").c_str()); + } + } else if (role == Qt::DecorationRole) { + if (index.column() == 0) { + switch (func->type()) { + case otImport: + return nodeIcon(NODE_IMPORT_FUNCTION); + default: + return functionIcon(func->owner()->owner()->function_list()->GetFunctionByAddress(func->address())); + } + } + } + return QVariant(); +} + +QVariant MapFunctionListModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + switch (section) { + case 0: + return QString::fromUtf8(language[lsName].c_str()); + case 1: + return QString::fromUtf8(language[lsAddress].c_str()); + } + return QVariant(); +} + +void MapFunctionListModel::search(const QString &text) +{ + beginResetModel(); + if (text.isEmpty()) { + items_ = mapFunctionList_; + } else { + items_.clear(); + QRegExp filter(text, Qt::CaseInsensitive, QRegExp::Wildcard); + + for (int i = 0; i < mapFunctionList_.size(); i++) { + MapFunction *func = mapFunctionList_[i]; + QString name = QString::fromUtf8(func->name().c_str()); + if (name.contains(filter)) + items_.append(func); + } + } + + endResetModel(); +} + +struct MapFunctionListCompareHelper { + int column; + MapFunctionListCompareHelper(int _column) : column(_column) {} + bool operator () (const MapFunction *func1, const MapFunction *func2) const + { + switch (column) { + case 0: + return QString::fromUtf8(func1->display_name().c_str()).compare(QString::fromUtf8(func2->display_name().c_str()), Qt::CaseInsensitive) < 0; + case 1: + return func1->display_address("") < func2->display_address(""); + } + return false; + } +}; + +void MapFunctionListModel::sort(int column, Qt::SortOrder order) +{ + beginResetModel(); + qSort(mapFunctionList_.begin(), mapFunctionList_.end(), MapFunctionListCompareHelper(column)); + if (items_.size() == mapFunctionList_.size()) + items_ = mapFunctionList_; + else + qSort(items_.begin(), items_.end(), MapFunctionListCompareHelper(column)); + endResetModel(); +} + +/** + * WatermarksModel + */ + +WatermarksModel::WatermarksModel(QObject *parent) + : BaseModel(parent) +{ + +} + +QVariant WatermarksModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const +{ + if (role == Qt::DisplayRole) { + if (section == 0) + return QString::fromUtf8(language[lsName].c_str()); + } + return QVariant(); +} + +Qt::ItemFlags WatermarksModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags res = QAbstractItemModel::flags(index); + if (res & Qt::ItemIsSelectable) { + ProjectNode *node = indexToNode(index); + if (node) { + if (node->type() == NODE_WATERMARK) + res |= Qt::ItemIsEditable; + } + } + return res; +} + +ProjectNode *WatermarksModel::internalAddWatermark(Watermark *watermark) +{ + beginInsertRows(nodeToIndex(NULL), root()->childCount(), root()->childCount()); + ProjectNode *node = new ProjectNode(root(), NODE_WATERMARK, (void *)watermark); + endInsertRows(); + + setObjectNode(watermark, node); + internalUpdateWatermark(watermark); + return node; +} + +ProjectNode *WatermarksModel::internalUpdateWatermark(Watermark *watermark) +{ + ProjectNode *node = objectToNode(watermark); + if (!node) + return NULL; + + node->setText(QString::fromUtf8(watermark->name().c_str())); + node->setIcon(nodeIcon(node->type(), !watermark->enabled())); + return node; +} + +void WatermarksModel::setCore(Core *core) +{ + beginResetModel(); + BaseModel::setCore(core); + + if (core) { + WatermarkManager *manager = core->watermark_manager(); + for (size_t i = 0; i < manager->count(); i++) { + internalAddWatermark(manager->item(i)); + } + } + endResetModel(); +} + +void WatermarksModel::addWatermark(Watermark *watermark) +{ + updateNode(internalAddWatermark(watermark)); +} + +void WatermarksModel::updateWatermark(Watermark *watermark) +{ + updateNode(internalUpdateWatermark(watermark)); +} + +void WatermarksModel::removeWatermark(Watermark *watermark) +{ + removeNode(watermark); +} + +QModelIndex WatermarksModel::indexByName(const QString &watermarkName) const +{ + for (int i = 0; i < root()->childCount(); i++) { + ProjectNode *node = root()->child(i); + if (node->text() == watermarkName) + return nodeToIndex(node); + } + + return QModelIndex(); +} + +WatermarkManager * WatermarksModel::manager() const +{ + return core() ? core()->watermark_manager() : NULL; +} + +/** + * WatermarkScanModel + */ + +WatermarkScanModel::WatermarkScanModel(QObject *parent) + : QAbstractItemModel(parent) +{ + +} + +QModelIndex WatermarkScanModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) + return QModelIndex(); + + Watermark *watermark = items_.keys().value(row); + if (!watermark) + return QModelIndex(); + + return createIndex(row, column, watermark); +} + +QModelIndex WatermarkScanModel::parent(const QModelIndex & /*index*/) const +{ + return QModelIndex(); +} + +int WatermarkScanModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + return items_.size(); +} + +int WatermarkScanModel::columnCount(const QModelIndex & /*parent*/) const +{ + return 2; +} + +Watermark *WatermarkScanModel::indexToWatermark(const QModelIndex &index) const +{ + if (index.isValid()) + return static_cast<Watermark *>(index.internalPointer()); + return NULL; +} + +QVariant WatermarkScanModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + Watermark *watermark = indexToWatermark(index); + assert(watermark); + if (watermark != NULL ) { + if (role == Qt::DisplayRole) { + if (index.column() == 0) { + return QString::fromUtf8(watermark->name().c_str()); + } else if (index.column() == 1) { + return QString::number(items_[watermark]); + } + } else if (role == Qt::DecorationRole) { + if (index.column() == 0) + return watermark->enabled() ? QIcon(":/images/item_watermark.png") : QIcon(":/images/item_watermark_black.png"); + } + } + return QVariant(); +} + +QVariant WatermarkScanModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const +{ + if (role == Qt::DisplayRole) { + if (section == 0) { + return QString::fromUtf8(language[lsName].c_str()); + } else if (section == 1) { + return QString::fromUtf8(language[lsCount].c_str()); + } + } + return QVariant(); +} + +void WatermarkScanModel::setWatermarkData(std::map<Watermark *, size_t> data) +{ + beginResetModel(); + items_.clear(); + for (std::map<Watermark *, size_t>::const_iterator it = data.begin(); it != data.end(); it++) { + items_[it->first] = it->second; + } + + endResetModel(); +} + +void WatermarkScanModel::removeWatermark(Watermark *watermark) +{ + int position = items_.keys().indexOf(watermark); + if (position == -1) + return; + + beginRemoveRows(QModelIndex(), position, position); + items_.remove(watermark); + endRemoveRows(); +} + +void WatermarkScanModel::clear() +{ + if (items_.count()) + removeRows(0, items_.count()); +} + +/** + * TemplatesModel + */ + +TemplatesModel::TemplatesModel(QObject *parent) + : BaseModel(parent) +{ + +} + +QVariant TemplatesModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const +{ + if (role == Qt::DisplayRole) { + if (section == 0) + return QString::fromUtf8(language[lsName].c_str()); + } + return QVariant(); +} + +Qt::ItemFlags TemplatesModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags res = QAbstractItemModel::flags(index); + if (res & Qt::ItemIsSelectable) { + if (index.row() != 0) + res |= Qt::ItemIsEditable; + } + return res; +} + +QVariant TemplatesModel::data(const QModelIndex &index, int role) const +{ + if (role == Qt::DisplayRole && index.row() == 0) + return "(" + QString::fromUtf8(language[lsDefault].c_str()) + ")"; + return BaseModel::data(index, role); +} + +void TemplatesModel::setCore(Core *core) +{ + beginResetModel(); + BaseModel::setCore(core); + + if (core) { + ProjectTemplateManager *manager = core->template_manager(); + for (size_t i = 0; i < manager->count(); i++) { + ProjectTemplate *pt = manager->item(i); + internalAddTemplate(pt); + } + } + endResetModel(); +} + +void TemplatesModel::updateTemplate(ProjectTemplate *pt) +{ + updateNode(internalUpdateTemplate(pt)); +} + +void TemplatesModel::removeTemplate(ProjectTemplate *pt) +{ + removeNode(pt); +} + +ProjectNode * TemplatesModel::internalUpdateTemplate(ProjectTemplate *pt) +{ + ProjectNode *node = objectToNode(pt); + if (!node) + return NULL; + + node->setText(QString::fromUtf8(pt->name().c_str())); + node->setIcon(nodeIcon(node->type())); + return node; +} + +ProjectNode * TemplatesModel::internalAddTemplate(ProjectTemplate *pt) +{ + beginInsertRows(nodeToIndex(NULL), root()->childCount(), root()->childCount()); + ProjectNode *node = new ProjectNode(root(), NODE_TEMPLATE, (void *)pt); + endInsertRows(); + + setObjectNode(pt, node); + internalUpdateTemplate(pt); + return node; +} + +void TemplatesModel::addTemplate(ProjectTemplate * pt) +{ + updateNode(internalAddTemplate(pt)); +} + +/** + * LogModel + */ + +LogModel::LogModel(QObject *parent) + : BaseModel(parent) +{ + +} + +void LogModel::addMessage(MessageType type, IObject *sender, const QString &text) +{ + NodeType node_type; + QString icon_name; + if (type == mtWarning) { + node_type = NODE_WARNING; + icon_name = ":/images/warning.png"; + } else if (type == mtError) { + node_type = NODE_ERROR; + icon_name = ":/images/error.png"; + } else + node_type = NODE_MESSAGE; + + ProjectNode *node; + beginInsertRows(QModelIndex(), root()->childCount(), root()->childCount()); + node = new ProjectNode(root(), node_type, sender); + endInsertRows(); + + if (sender) + setObjectNode(sender, node); + + node->setText(text); + if (!icon_name.isEmpty()) + node->setIcon(QIcon(icon_name)); +} + +QVariant LogModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int role) const +{ + if (role == Qt::DisplayRole) { + return QString::fromUtf8(language[lsCompilationLog].c_str()); + } + return QVariant(); +} + +void LogModel::clear() +{ + beginRemoveRows(QModelIndex(), 0, root()->childCount()); + BaseModel::clear(); + endRemoveRows(); +} + +void LogModel::removeObject(void *object) +{ + removeNode(object); +} + +/** + * ProjectTreeDelegate + */ + +ProjectTreeDelegate::ProjectTreeDelegate(QObject *parent) + : TreeViewItemDelegate(parent) +{ + +} + +QWidget *ProjectTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const +{ + QLineEdit *editor = new LineEdit(parent); + editor->setObjectName("editor"); + editor->setFrame(false); + + return editor; +} + +void ProjectTreeDelegate::setModelData(QWidget *editor, QAbstractItemModel * /*model*/, const QModelIndex &index) const +{ + ProjectNode *node = static_cast<ProjectNode *>(index.internalPointer()); + if (!node) + return; + + auto le = qobject_cast<QLineEdit *>(editor); + assert(le); + if (!le) + return; + + QString text = le->text(); + + switch (node->type()) { + case NODE_FOLDER: + static_cast<Folder *>(node->data())->set_name(text.toUtf8().constData()); + break; +#ifdef ULTIMATE + case NODE_LICENSE: + static_cast<License *>(node->data())->set_customer_name(text.toUtf8().constData()); + break; + case NODE_FILE_FOLDER: + static_cast<FileFolder *>(node->data())->set_name(text.toUtf8().constData()); + break; + case NODE_FILE: + static_cast<InternalFile *>(node->data())->set_name(text.toUtf8().constData()); + break; +#endif + case NODE_WATERMARK: + static_cast<Watermark *>(node->data())->set_name(text.toUtf8().constData()); + break; + } +} + +/** + * WatermarksTreeDelegate + */ + +WatermarksTreeDelegate::WatermarksTreeDelegate(QObject *parent) + : TreeViewItemDelegate(parent) +{ + +} + +QWidget *WatermarksTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const +{ + QLineEdit *editor = new LineEdit(parent); + editor->setObjectName("editor"); + editor->setFrame(false); + + return editor; +} + +void WatermarksTreeDelegate::setModelData(QWidget *editor, QAbstractItemModel * /*model*/, const QModelIndex &index) const +{ + ProjectNode *node = static_cast<ProjectNode *>(index.internalPointer()); + if (!node) + return; + + QString text = qobject_cast<QLineEdit *>(editor)->text(); + + switch (node->type()) { + case NODE_WATERMARK: + static_cast<Watermark *>(node->data())->set_name(text.toUtf8().constData()); + break; + } +} + +/** + * TemplatesTreeDelegate + */ + +TemplatesTreeDelegate::TemplatesTreeDelegate(QObject *parent) + : TreeViewItemDelegate(parent) +{ + +} + +QWidget *TemplatesTreeDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & /*index*/) const +{ + QLineEdit *editor = new LineEdit(parent); + editor->setObjectName("editor"); + editor->setFrame(false); + + return editor; +} + +void TemplatesTreeDelegate::setModelData(QWidget *editor, QAbstractItemModel * /*model*/, const QModelIndex &index) const +{ + ProjectNode *node = static_cast<ProjectNode *>(index.internalPointer()); + if (!node) + return; + + QString text = qobject_cast<QLineEdit *>(editor)->text(); + if (text.isEmpty()) + { + //FIXME i18n + MessageDialog::warning(editor->parentWidget(), "Please provide meaningful name", QMessageBox::Ok); + return; + } + switch (node->type()) { + case NODE_TEMPLATE: + static_cast<ProjectTemplate *>(node->data())->set_name(text.toUtf8().constData()); + break; + } +} + +/** + * DumpModel + */ + +DumpModel::DumpModel(QObject *parent) + : QAbstractItemModel(parent), file_(NULL), rowCountCache_(0), cacheAddress_(0) +{ + +} + +QModelIndex DumpModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) + return QModelIndex(); + + return createIndex(row, column); +} + +QModelIndex DumpModel::parent(const QModelIndex & /*index*/) const +{ + return QModelIndex(); +} + +int DumpModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + if(rowCountCache_ == 0) { + QMapIterator<uint64_t, int> i(addrsToRows_); + while (i.hasNext()) { + i.next(); + rowCountCache_ += i.value(); + } + } + return rowCountCache_; +} + +int DumpModel::columnCount(const QModelIndex & /*parent*/) const +{ + return 3; +} + +void DumpModel::setFile(IArchitecture *file) +{ + if (file_ == file) + return; + + beginResetModel(); + file_ = file; + rowCountCache_ = 0; + addrsToRows_.clear(); + cacheAddress_ = 0; + cache_.clear(); + + if (file_) { + size_t i; + ISection *segment; + std::vector<ISection *> segmentList; + std::string formatName = file->owner()->format_name(); + + if (formatName == "PE") { + segment = file->segment_list()->GetSectionByAddress(file->image_base()); + if (segment) + segmentList.push_back(segment); + } + + for (i = 0; i < file->segment_list()->count(); i++) { + segment = file->segment_list()->item(i); + if (segment->memory_type() == mtNone || segment->size() == 0) + continue; + + if (formatName == "ELF" && segment->name() != "PT_LOAD") + continue; + + segmentList.push_back(segment); + } + + uint64_t curAddr; + int curRows = 0; + for (i = 0; i < segmentList.size(); i++) { + segment = segment = segmentList[i]; + uint64_t address = segment->address(); + uint32_t rows = (uint32_t)(segment->size() + 15) / 16; + + if(curRows == 0) { + curAddr = address; + curRows = rows; + continue; + } + uint64_t curEndAddr = curAddr + 16 * curRows; + if(curEndAddr < address) { //gap + addrsToRows_.insert(curAddr, curRows); + curAddr = address; + curRows = rows; + continue; + } + uint64_t nextEndAddr = address + 16 * rows; + if(nextEndAddr > curEndAddr) curRows = (nextEndAddr - curAddr) / 16; + } + if (curRows) addrsToRows_.insert(curAddr, curRows); + } + endResetModel(); +} + +QByteArray DumpModel::read(uint64_t address, int size) const +{ + if (!cacheAddress_ || address < cacheAddress_ || address + size > cacheAddress_ + cache_.size()) { + if (file_->AddressSeek(address)) { + ISection *segment = file_->selected_segment(); + cacheAddress_ = address; + int cacheSize = (int)qMin(segment->physical_size(), (uint32_t)segment->size()) - (address - segment->address()); + if (cacheSize > 0x100000 && cacheSize > size) // 1Mbyte read ahead limit + cacheSize = 0x100000; + if (cacheSize) { + cache_.resize(cacheSize); + file_->Read(cache_.data(), cacheSize); + } else { + cache_.clear(); + } + } else { + return QByteArray(); + } + } + + uint64_t offset = address - cacheAddress_; + return cache_.mid(offset, qMin(cache_.size() - (int)offset, size)); +} + +QVariant DumpModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (role == Qt::DisplayRole) { + uint64_t address = indexToAddress(index); + switch (index.column()) { + case 0: + { + QString res; + ISection *segment = file_->segment_list()->GetSectionByAddress(address); + if (segment) + res = QString::fromLatin1(segment->name().c_str()).append(':'); + res.append(QString::fromUtf8(DisplayValue(file_->cpu_address_size(), address).c_str())); + return res; + } + + case 1: + { + QByteArray data = read(address, 0x10); + unsigned char res[16*3] = "?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ?? ??"; + static char hex[] = "0123456789ABCDEF"; + for (int i = 0; i < 16; i++) { + int value = -1; + if (i < data.size()) { + value = (unsigned char)data[i]; + } else { + data = read(address + i, 1); + if(data.size()) { + value = (unsigned char)data[0]; + } + } + if (value >= 0) { + res[3 * i] = hex[value >> 4]; + res[3 * i + 1] = hex[value & 0x0f]; + } + } + return QString((char *)res); + } + + case 2: + { + QByteArray data = read(address, 0x10); + char res[17], *ptr = res; + for (int i = 0; i < 16; i++) { + if (i < data.size()) { + unsigned char value = data[i]; + if (value < 32 || value > 127) value = 0xB7; + *ptr++ = value; + } else { + data = read(address + i, 1); + if (data.size()) { + unsigned char value = data[0]; + if (value < 32 || value > 127) value = 0xB7; + *ptr++ = value; + } + else { + *ptr++ = '?'; + } + } + } + *ptr = 0; + return QString::fromLatin1((char *)res); + } + } + } else if (role == Qt::FontRole) { + QFont font(MONOSPACE_FONT_FAMILY); + return font; + } + + return QVariant(); +} + +QVariant DumpModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const +{ + if (role == Qt::DisplayRole) { + switch (section) { + case 0: + return QString::fromUtf8(language[lsAddress].c_str()); + case 1: + return QString::fromUtf8(language[lsDump].c_str()); + case 2: + return QString::fromUtf8(language[lsValue].c_str()); + } + } + return QVariant(); +} + +QModelIndex DumpModel::addressToIndex(uint64_t address) +{ + QMapIterator<uint64_t, int> i(addrsToRows_); + int rows = 0; + while (i.hasNext()) { + i.next(); + if(address >= i.key() && i.value() > (int)((address - i.key()) / 16)) + return createIndex(rows + (int)((address - i.key()) / 16), 0); + rows += i.value(); + } + return QModelIndex(); +} + +uint64_t DumpModel::indexToAddress(const QModelIndex &index) const +{ + QMapIterator<uint64_t, int> i(addrsToRows_); + int rows = 0; + while (i.hasNext()) { + i.next(); + if (rows + i.value() > index.row()) + return i.key() + (index.row() - rows) * 16; + rows += i.value(); + } + assert(0); + return 0; +} + +/** + * DisasmModel + */ + +DisasmModel::DisasmModel(QObject *parent) + : QAbstractItemModel(parent), file_(NULL), rowCountCache_(0), func_(NULL) +{ + +} + +QModelIndex DisasmModel::index(int row, int column, const QModelIndex &parent) const +{ + if (parent.isValid() && parent.column() != 0) + return QModelIndex(); + + return createIndex(row, column); +} + +QModelIndex DisasmModel::parent(const QModelIndex & /*index*/) const +{ + return QModelIndex(); +} + +int DisasmModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + if (rowCountCache_ == 0) { + QMapIterator<uint64_t, int> i(addrsToRows_); + while (i.hasNext()) { + i.next(); + rowCountCache_ += i.value(); + } + } + return rowCountCache_; +} + +int DisasmModel::columnCount(const QModelIndex & /*parent*/) const +{ + return 3; +} + +QModelIndex DisasmModel::addressToIndex(uint64_t address) +{ + int row = addressOffset(address); + if (row >= 0) + { + QModelIndex index = createIndex(row, 0); + if (func_->count()) { + QModelIndex end = createIndex(index.row() + (int)func_->count(), 2); + func_->clear(); + dataChanged(index, end); + } + return index; + } + return QModelIndex(); +} + +int DisasmModel::addressOffset(uint64_t address) const +{ + QMapIterator<uint64_t, int> i(addrsToRows_); + int ret = 0; + while (i.hasNext()) { + i.next(); + if (address >= i.key() && i.value() > (int)(address - i.key())) + { + return ret + (int)(address - i.key()); + } + ret += i.value(); + } + return -1; +} + +uint64_t DisasmModel::offsetToAddress(int offset) const +{ + QMapIterator<uint64_t, int> i(addrsToRows_); + while (i.hasNext()) { + i.next(); + if (i.value() > offset) + { + return i.key() + offset; + } + offset -= i.value(); + } + return 0; +} + +ICommand *DisasmModel::indexToCommand(const QModelIndex &index) const +{ + if (func_->count()) { + uint64_t address = func_->item(0)->address(); + int row = addressOffset(address); + if (row >= 0 && row <= index.row()) { + size_t commandIndex = index.row() - row; + if (commandIndex < func_->count()) + return func_->item(commandIndex); + } + } + return NULL; +} + +void DisasmModel::setFile(IArchitecture *file) +{ + if (file_ == file) + return; + + beginResetModel(); + file_ = file; + rowCountCache_ = 0; + addrsToRows_.clear(); + delete func_; + func_ = NULL; + + if (file_) { + size_t i; + ISection *segment; + std::vector<ISection *> segmentList; + std::string formatName = file->owner()->format_name(); + + if (formatName == "PE" && file->AddressSeek(file->image_base())) + segmentList.push_back(file->selected_segment()); + + for (i = 0; i < file->segment_list()->count(); i++) { + segment = file->segment_list()->item(i); + if (segment->memory_type() == mtNone || segment->size() == 0) + continue; + + if (formatName == "ELF" && segment->name() != "PT_LOAD") + continue; + + segmentList.push_back(segment); + } + + uint64_t curAddr; + int curRows = 0; + for (i = 0; i < segmentList.size(); i++) { + segment = segment = segmentList[i]; + uint64_t address = segment->address(); + uint32_t rows = (uint32_t)segment->size(); + + if (curRows == 0) { + curAddr = address; + curRows = rows; + continue; + } + uint64_t curEndAddr = curAddr + curRows; + if (curEndAddr < address) { //gap + addrsToRows_.insert(curAddr, curRows); + curAddr = address; + curRows = rows; + continue; + } + uint64_t nextEndAddr = address + rows; + if (nextEndAddr > curEndAddr) curRows = nextEndAddr - curAddr; + } + if (curRows) addrsToRows_.insert(curAddr, curRows); + func_ = file->function_list()->CreateFunction(file->cpu_address_size()); + } + endResetModel(); +} + +QVariant DisasmModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + switch (role) { + case Qt::DisplayRole: + case Qt::Vmp::StaticTextRole: + case Qt::Vmp::StaticColorRole: + { + if (func_->count() > 100000) + func_->clear(); + + uint64_t address = offsetToAddress(index.row()); + ICommand *command = NULL; + if (func_->count()) { + int startIndex = addressOffset(func_->item(0)->address()); + if (startIndex >= 0 && startIndex <= index.row()) { + size_t commandIndex = index.row() - startIndex; + if (commandIndex < func_->count()) + command = func_->item(commandIndex); + else if (commandIndex == func_->count()) + address = func_->item(func_->count() - 1)->next_address(); + else + func_->clear(); + } else { + func_->clear(); + } + } + + if (!command) + command = func_->ParseCommand(*file_, address, true); + + if (role == Qt::DisplayRole) { + switch (index.column()) { + case 0: + { + QString res; + ISection *segment = file_->segment_list()->GetSectionByAddress(address - address % file_->segment_alignment()); + if (segment) + res = QString::fromLatin1(segment->name().c_str()).append(':'); + return res.append(QString::fromLatin1(command->display_address().c_str())); + } + case 1: + return QString::fromLatin1(command->dump_str().c_str()); + case 2: + return QString::fromUtf8(command->text().c_str()); + } + } else if (role == Qt::Vmp::StaticTextRole) { + if (index.column() == 2 && !command->comment().value.empty()) + return QString::fromUtf8(command->comment().display_value().c_str()); + } else if (role == Qt::Vmp::StaticColorRole) { + if (index.column() == 2 && !command->comment().value.empty()) { + switch (command->comment().type) { + case ttFunction: case ttJmp: + return QColor(Qt::blue); + case ttImport: + return QColor(Qt::darkRed); + case ttExport: + return QColor(Qt::red); + case ttString: + return QColor(Qt::darkGreen); + case ttVariable: + return QColor(Qt::magenta); + case ttComment: + return QColor(Qt::gray); + default: + return QColor(); + } + } + } + } + break; + case Qt::FontRole: { + return QFont(MONOSPACE_FONT_FAMILY); + } + } + + return QVariant(); +} + +QVariant DisasmModel::headerData(int section, Qt::Orientation /*orientation*/, int role) const +{ + if (role == Qt::DisplayRole) { + switch (section) { + case 0: + return QString::fromUtf8(language[lsAddress].c_str()); + case 1: + return QString::fromUtf8(language[lsDump].c_str()); + case 2: + return QString::fromUtf8(language[lsCode].c_str()); + } + } + return QVariant(); +} + +/** + * ProjectNode + */ + +bool ItemModelSearcher::extractMatchingIndexes(const QModelIndex &parent) +{ + //TODO: âîçìîæíû äàëüíåéøèå îïòèìèçàöèè + if (current_match_ == NULL) + current_match_ = &match_before_; + + int rows = where_->rowCount(parent); + for(int i = 0; i < rows; ++i) + { + QModelIndex idx0; + for(int col = 0; col < where_->columnCount(parent); col++) + { + QModelIndex idx = where_->index(i, col, parent); + if(idx.isValid()) + { + if(col == 0) + idx0 = idx; + if(from_ == idx) + { + assert(current_match_ == &match_before_); + if (match_before_.isValid() && !forward_) + return true; + if (!forward_ && !incremental_ && !match_before_.isValid()) + return false; + current_match_ = &match_after_; + } else + { + bool matched = (idx.data(Qt::DisplayRole).toString() + idx.data(Qt::Vmp::StaticTextRole).toString()).contains(*term_); + if (matched) + { + *current_match_ = idx; + if (incremental_ && current_match_ == &match_before_ && from_.isValid() && !match_after_.isValid()) + match_after_ = idx; //store wrapped result + if (from_.isValid() && current_match_ == &match_after_ && forward_) + return true; + if (!from_.isValid() && forward_) + return true; + } + } + } + } + if (extractMatchingIndexes(idx0)) + return true; + } + return false; +} + +QModelIndex ItemModelSearcher::find() +{ + assert(incremental_ == false || forward_ == true); //other modes unsupported + if(incremental_ == false || forward_ == true) + { + bool from_matched = from_.isValid() && (from_.data(Qt::DisplayRole).toString() + from_.data(Qt::Vmp::StaticTextRole).toString()).contains(*term_); + if(from_matched && incremental_) + return from_; + + if (extractMatchingIndexes(QModelIndex())) + { + assert(current_match_ && current_match_->isValid()); + return *current_match_; + } + // 1. from_ invalid backward + if (!from_.isValid() && !forward_ && match_before_.isValid()) + { + return match_before_; + } + + // 2. from_ valid incremental_ wrapped + if (from_.isValid() && incremental_ && match_after_.isValid()) + { + return match_after_; + } + } + return QModelIndex(); +} diff --git a/VMProtect/models.h b/VMProtect/models.h new file mode 100644 index 0000000..6e9ac0b --- /dev/null +++ b/VMProtect/models.h @@ -0,0 +1,488 @@ +#ifndef MODELS_H +#define MODELS_H + +#include "widgets.h" + +class Folder; +class IFunction; +class License; +class FileFolder; +class InternalFile; +class PropertyManager; + +enum NodeType { + NODE_ROOT, + NODE_ARCHITECTURE, + NODE_OPTIONS, + NODE_SCRIPT, + NODE_SCRIPT_BOOKMARK, + NODE_LOAD_COMMANDS, + NODE_LOAD_COMMAND, + NODE_SEGMENTS, + NODE_SEGMENT, + NODE_SECTION, + NODE_IMPORTS, + NODE_IMPORT, + NODE_IMPORT_FOLDER, + NODE_IMPORT_FUNCTION, + NODE_EXPORTS, + NODE_EXPORT_FOLDER, + NODE_EXPORT, + NODE_MAP_FOLDER, + NODE_MAP_FUNCTION, + NODE_FUNCTIONS, + NODE_FOLDER, + NODE_FUNCTION, + NODE_RESOURCES, + NODE_RESOURCE_FOLDER, + NODE_RESOURCE, + NODE_LICENSES, + NODE_LICENSE, + NODE_FILES, + NODE_FILE, + NODE_FILE_FOLDER, + NODE_COMMAND, + NODE_WATERMARK, + NODE_PROPERTY, + NODE_DUMP, + NODE_CALC, + NODE_MESSAGE, + NODE_WARNING, + NODE_ERROR, + NODE_TEMPLATE, + NODE_ASSEMBLIES, +}; + +class ProjectNode +{ +public: + ProjectNode(ProjectNode *parent, NodeType type, void *data = NULL); + ~ProjectNode(); + void clear(); + NodeType type() const { return type_; } + QString text(int column = 0) const; + bool contains(const QRegExp &filter) const; + QString path() const; + void *data() const { return data_; } + QIcon icon() const { return icon_; } + ProjectNode *child(int index) const { return children_[index]; }; + int childCount() const { return children_.size(); } + void setData(void *data) { data_ = data; } + void setText(const QString &text) { text_ = text; } + void setIcon(const QIcon &icon) { icon_ = icon; } + QList<ProjectNode *> children() const { return children_; }; + ProjectNode *parent() const { return parent_; }; + void addChild(ProjectNode *child); + void insertChild(int index, ProjectNode *child); + void removeChild(ProjectNode *child); + void setPropertyManager(PropertyManager *propertyManager); + ProjectNode *properties() const { return properties_; }; + void localize(); +private: + ProjectNode *parent_; + void *data_; + NodeType type_; + QString text_; + QIcon icon_; + QList<ProjectNode *> children_; + ProjectNode *properties_; + + // no copy ctr or assignment op + ProjectNode(const ProjectNode &); + ProjectNode &operator =(const ProjectNode &); +}; + +class IProjectNodesModel +{ +public: + virtual ProjectNode *indexToNode(const QModelIndex &index) const = 0; +}; + +class Core; +class BaseModel : public QAbstractItemModel, public IProjectNodesModel +{ + Q_OBJECT +public: + BaseModel(QObject *parent = 0); + ~BaseModel(); + virtual void setCore(Core *core); + bool isEmpty() const { return root_->childCount() == 0; } + virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const; + virtual QModelIndex parent(const QModelIndex &index) const; + virtual int rowCount(const QModelIndex &parent) const; + virtual int columnCount(const QModelIndex &parent) const; + virtual QVariant data(const QModelIndex &index, int role) const; + ProjectNode *indexToNode(const QModelIndex &index) const; + QModelIndex nodeToIndex(ProjectNode *node) const; + QModelIndex objectToIndex(void *object) const; + ProjectNode *objectToNode(void *object) const; + void setObjectNode(void *object, ProjectNode *node); + ProjectNode *root() const { return root_; } + Core *core() const { return core_; } + void localize(); +signals: + void nodeUpdated(ProjectNode *node); + void nodeRemoved(ProjectNode *node); + void objectRemoved(void *object); +protected: + void clear(); + bool removeNode(void *object); + void updateNode(ProjectNode *node); + void removeObject(void *object); + void createFunctionsTree(ProjectNode *root); +private: + ProjectNode *root_; + Core *core_; + QMap<void *, ProjectNode *> objectToNode_; +}; + +class ProjectModel : public BaseModel +{ + Q_OBJECT +public: + ProjectModel(QObject *parent = 0); + ~ProjectModel(); + virtual void setCore(Core *core); + //virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual Qt::DropActions supportedDragActions() const { return Qt::MoveAction; } + virtual Qt::DropActions supportedDropActions() const { return Qt::MoveAction; } + virtual Qt::ItemFlags flags(const QModelIndex & index) const; + virtual QStringList mimeTypes() const; + virtual QMimeData *mimeData(const QModelIndexList &indexes) const; + virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); + void addFolder(Folder *folder); + void updateFolder(Folder *folder); + void removeFolder(Folder *folder); + void addFunction(IFunction *func); + void updateFunction(IFunction *func); + void removeFunction(IFunction *func); + void updateScript(); + QModelIndex optionsIndex() const { return nodeToIndex(nodeOptions_); } +#ifndef LITE + QModelIndex scriptIndex() const { return nodeToIndex(nodeScript_); } + uptr_t bookmarkNodeToPos(ProjectNode *node) const; + void updateScriptBookmarks(); +#endif +#ifdef ULTIMATE + QModelIndex licensesIndex() const { return nodeToIndex(nodeLicenses_); } + void addLicense(License *license); + void updateLicense(License *license); + void removeLicense(License *license); + void addFileFolder(FileFolder *folder); + void updateFileFolder(FileFolder *folder); + void removeFileFolder(FileFolder *folder); + void addFile(InternalFile *file); + void updateFile(InternalFile *file); + void removeFile(InternalFile *file); + void updateFiles(); +#endif + void sortNode(ProjectNode *node, int field); +signals: + void modified(); +private: + ProjectNode *internalAddFolder(Folder *folder); + ProjectNode *internalUpdateFolder(Folder *folder); + ProjectNode *internalAddFunction(IFunction *func); + ProjectNode *internalUpdateFunction(IFunction *func); +#ifdef ULTIMATE + ProjectNode *internalAddLicense(License *license); + ProjectNode *internalUpdateLicense(License *license); + ProjectNode *internalAddFileFolder(FileFolder *folder); + ProjectNode *internalUpdateFileFolder(FileFolder *folder); + ProjectNode *internalAddFile(InternalFile *file); + ProjectNode *internalUpdateFile(InternalFile *file); +#endif + ProjectNode *addObject(ProjectNode *parent, NodeType type, void *object); + ProjectNode *nodeFunctions_; +#ifdef ULTIMATE + ProjectNode *nodeLicenses_; + ProjectNode *nodeFiles_; +#endif +#ifndef LITE + ProjectNode *nodeScript_; +#endif + ProjectNode *nodeOptions_; +}; + +class FunctionsModel : public BaseModel +{ +public: + FunctionsModel(QObject *parent = 0); + virtual void setCore(Core *core); + void updateFunction(IFunction *func); + void removeFunction(IFunction *func); + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; +}; + +class IResource; +class IArchitecture; +class ISection; +class IImport; + +class InfoModel : public BaseModel +{ + Q_OBJECT +public: + InfoModel(QObject *parent = 0); + virtual void setCore(Core *core); + void updateResource(IResource *resource); + void updateSegment(ISection *segment); + void updateImport(IImport *import); + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + QModelIndex dumpIndex(IArchitecture *file) const { return objectToIndex(file); } +signals: + void modified(); +}; + +class SearchModel : public QAbstractItemModel +{ +public: + SearchModel(QObject *parent = 0); + void search(ProjectNode *directory, const QString &text, bool protectedFunctionsOnly = false); + virtual QModelIndex index(int row, int column, const QModelIndex &parent) const; + virtual QModelIndex parent(const QModelIndex &index) const; + virtual int rowCount(const QModelIndex &parent) const; + virtual int columnCount(const QModelIndex &parent) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual bool removeRows(int position, int rows, const QModelIndex &parent = QModelIndex()); + QModelIndex nodeToIndex(ProjectNode *node) const; + void updateNode(ProjectNode *node); + void removeNode(ProjectNode *node); + void clear(); + ProjectNode *indexToNode(const QModelIndex &index) const; +private: + QList<ProjectNode *> items_; +}; + +class DirectoryModel : public QAbstractItemModel, public IProjectNodesModel +{ +public: + DirectoryModel(QObject *parent = 0); + void setDirectory(ProjectNode *directory); + virtual QModelIndex index(int row, int column, const QModelIndex &parent) const; + virtual QModelIndex parent(const QModelIndex &index) const; + virtual int rowCount(const QModelIndex &parent) const; + virtual int columnCount(const QModelIndex &parent) const; + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual bool removeRows(int position, int rows, const QModelIndex &parent = QModelIndex()); + QModelIndex nodeToIndex(ProjectNode *node) const; + void updateNode(ProjectNode *node); + void removeNode(ProjectNode *node); +private: + ProjectNode *indexToNode(const QModelIndex &index) const; + QList<ProjectNode *> items_; + ProjectNode *directory_; +}; + +class IFile; +class MapFunctionBundle; +class MapFunctionBundleListModel : public QAbstractItemModel +{ + Q_OBJECT +public: + MapFunctionBundleListModel(IFile &file, bool codeOnly, QObject *parent = 0); + virtual int rowCount(const QModelIndex &parent) const; + virtual int columnCount(const QModelIndex &parent) const; + virtual QModelIndex index(int row, int column, const QModelIndex &parent) const; + virtual QModelIndex parent(const QModelIndex &index) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + void search(const QString &text); + virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); +private: + QList<MapFunctionBundle*> mapFunctionList_; + QList<MapFunctionBundle*> items_; +}; + +class MapFunction; +class MapFunctionListModel : public QAbstractItemModel +{ + Q_OBJECT +public: + MapFunctionListModel(IArchitecture &file, bool codeOnly, QObject *parent = 0); + virtual int rowCount(const QModelIndex &parent) const; + virtual int columnCount(const QModelIndex &parent) const; + virtual QModelIndex index(int row, int column, const QModelIndex &parent) const; + virtual QModelIndex parent(const QModelIndex &index) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + void search(const QString &text); + virtual void sort(int column, Qt::SortOrder order = Qt::AscendingOrder); +private: + QList<MapFunction*> mapFunctionList_; + QList<MapFunction*> items_; +}; + +class WatermarkManager; +class Watermark; + +class WatermarksModel : public BaseModel +{ + Q_OBJECT +public: + WatermarksModel(QObject *parent = 0); + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual Qt::ItemFlags flags(const QModelIndex & index) const; + WatermarkManager *manager() const; + void setCore(Core *core); + void addWatermark(Watermark *watermark); + void updateWatermark(Watermark *watermark); + void removeWatermark(Watermark *watermark); + QModelIndex indexByName(const QString &watermarkName) const; +private: + ProjectNode *internalAddWatermark(Watermark *watermark); + ProjectNode *internalUpdateWatermark(Watermark *watermark); +}; + +class WatermarkScanModel : public QAbstractItemModel +{ +public: + WatermarkScanModel(QObject *parent = 0); + virtual QModelIndex index(int row, int column, const QModelIndex &parent) const; + virtual QModelIndex parent(const QModelIndex &index) const; + virtual int rowCount(const QModelIndex &parent) const; + virtual int columnCount(const QModelIndex &parent) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + Watermark *indexToWatermark(const QModelIndex &index) const; + void setWatermarkData(std::map<Watermark *, size_t> data); + void removeWatermark(Watermark *watermark); + void clear(); +private: + QMap<Watermark *, size_t> items_; +}; + +class ProjectTemplate; +class TemplatesModel : public BaseModel +{ + Q_OBJECT +public: + TemplatesModel(QObject *parent = 0); + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual Qt::ItemFlags flags(const QModelIndex & index) const; + void setCore(Core *core); + void addTemplate(ProjectTemplate * pt); + void updateTemplate(ProjectTemplate *pt); + void removeTemplate(ProjectTemplate *pt); +private: + ProjectNode *internalAddTemplate(ProjectTemplate * pt); + ProjectNode *internalUpdateTemplate(ProjectTemplate * pt); +}; + +class LogModel : public BaseModel +{ +public: + LogModel(QObject *parent = 0); + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + void clear(); + void addMessage(MessageType type, IObject *sender, const QString &text); + void removeObject(void *object); +}; + +class ProjectTreeDelegate : public TreeViewItemDelegate +{ + Q_OBJECT +public: + ProjectTreeDelegate(QObject *parent = 0); + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const; + void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; +}; + +class WatermarksTreeDelegate : public TreeViewItemDelegate +{ + Q_OBJECT +public: + WatermarksTreeDelegate(QObject *parent = 0); + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const; + void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; +}; + +class TemplatesTreeDelegate : public TreeViewItemDelegate +{ + Q_OBJECT +public: + TemplatesTreeDelegate(QObject *parent = 0); + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const; + void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const; +}; + +class DumpModel : public QAbstractItemModel +{ +public: + DumpModel(QObject *parent = 0); + virtual QModelIndex index(int row, int column, const QModelIndex &parent) const; + virtual QModelIndex parent(const QModelIndex &index) const; + virtual int rowCount(const QModelIndex &parent) const; + virtual int columnCount(const QModelIndex &parent) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + void setFile(IArchitecture *file); + QModelIndex addressToIndex(uint64_t address); +private: + QByteArray read(uint64_t address, int size) const; + uint64_t indexToAddress(const QModelIndex &index) const; + + IArchitecture *file_; + QMap<uint64_t, int> addrsToRows_; + mutable int rowCountCache_; + mutable uint64_t cacheAddress_; + mutable QByteArray cache_; +}; + +class ICommand; +class DisasmModel : public QAbstractItemModel +{ +public: + DisasmModel(QObject *parent = 0); + virtual QModelIndex index(int row, int column, const QModelIndex &parent) const; + virtual QModelIndex parent(const QModelIndex &index) const; + virtual int rowCount(const QModelIndex &parent) const; + virtual int columnCount(const QModelIndex &parent) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + void setFile(IArchitecture *file); + QModelIndex addressToIndex(uint64_t address); + ICommand *indexToCommand(const QModelIndex &index) const; + IArchitecture *file() const { return file_; } +private: + int addressOffset(uint64_t address) const; + uint64_t offsetToAddress(int offset) const; + void funcClear() const; + + IArchitecture *file_; + mutable int rowCountCache_; + QMap<uint64_t, int> addrsToRows_; + IFunction *func_; +}; + +class ItemModelSearcher +{ +public: + ItemModelSearcher(QAbstractItemModel *where, QModelIndex from, const QRegExp *term, bool forward, bool incremental) : + where_(where), from_(from), term_(term), forward_(forward), incremental_(incremental), current_match_(NULL) + { + result_ = find(); + } + QModelIndex result() { return result_; } + +private: + QModelIndex find(); + QModelIndex result_; + + bool extractMatchingIndexes(const QModelIndex &parent); + + QAbstractItemModel *where_; + const QRegExp *term_; + const bool forward_, incremental_; + const QModelIndex from_; + + QModelIndex match_before_, match_after_; + QModelIndex *current_match_; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/precompiled.cc b/VMProtect/precompiled.cc new file mode 100644 index 0000000..c08ca1f --- /dev/null +++ b/VMProtect/precompiled.cc @@ -0,0 +1 @@ +#include "precompiled.h"
\ No newline at end of file diff --git a/VMProtect/precompiled.h b/VMProtect/precompiled.h new file mode 100644 index 0000000..7f1104b --- /dev/null +++ b/VMProtect/precompiled.h @@ -0,0 +1,67 @@ +#pragma once +#ifndef VMP_PCH +#define VMP_PCH + +#include <QtCore/QMap> // because of non-usual new operator +#include <QtCore/QHash> // because of non-usual new operator +#include <QtCore/QMetaType> // because of non-usual new operator +#include <QtCore/QVector> // because of non-usual new operator +#include "../core/precompiled.h" + +#include <QtWidgets/QtWidgets> +#include <QtWidgets/QDialog> +#include <QtWidgets/QMainWindow> +#include <QtWidgets/QApplication> +#include <QtCore/QObject> +#include <QtWidgets/QAbstractScrollArea> +#include <QtWidgets/QAction> +#include <QtGui/QClipboard> +#include <QtGui/QPaintEvent> +#include <QtGui/QDrag> +#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) +#include <QtWidgets/QInputContext> +#endif +#include <QtCore/QMimeData> +#include <QtWidgets/QMenu> +#include <QtWidgets/QScrollBar> +#include <QtCore/QTimer> +#include <QtCore/QTextCodec> +#include <QtGui/QPainter> +#include <QtGui/QTextFormat> +#include <QtCore/QVarLengthArray> +#include <QtGui/QPaintDevice> +#include <QtGui/QFont> +#include <QtGui/QColor> +#include <QtCore/QRect> +#include <QtGui/QPaintEngine> +#include <QtWidgets/QWidget> +#include <QtGui/QPixmap> +#include <QtWidgets/QAction> +#include <QtCore/QTime> +#include <QtWidgets/QMessageBox> +#include <QtWidgets/QListWidget> +#include <QtWidgets/QDesktopWidget> +#include <QtGui/QTextLayout> +#include <QtGui/QTextLine> +#include <QtCore/QLibrary> +#include <QtCore/QProcess> +#include <QtConcurrent/QtConcurrent> +#ifndef VMP_GNU +#include "QtWinExtras/qwinfunctions.h" +#endif +#include <QtWidgets/QTabWidget> +#include <QtWidgets/QTabBar> +#include <QtHelp/QHelpEngine> +#include <QtHelp/QHelpContentWidget> +#include <QtHelp/QHelpSearchQuery> +#include <QtHelp/QHelpSearchEngine> +#include <QtHelp/QHelpSearchResultWidget> + +#include "../third-party/scintilla/Platform.h" +#include "../third-party/scintilla/Scintilla.h" +#include "../third-party/scintilla/ScintillaEditBase.h" +#include "../third-party/scintilla/SciLexer.h" +#include "../third-party/scintilla/ScintillaQt.h" +#include "../third-party/scintilla/PlatQt.h" + +#endif //VMP_PCH
\ No newline at end of file diff --git a/VMProtect/progress_dialog.cc b/VMProtect/progress_dialog.cc new file mode 100644 index 0000000..a32fe8b --- /dev/null +++ b/VMProtect/progress_dialog.cc @@ -0,0 +1,133 @@ +#include "../core/objects.h" +#include "../core/files.h" +#include "../core/lang.h" + +#include "wait_cursor.h" +#include "progress_dialog.h" +#include "moc/moc_progress_dialog.cc" +#include "message_dialog.h" + +/** + * ProgressDialog + */ + +ProgressDialog::ProgressDialog(QWidget *parent) + : QDialog(parent, Qt::Dialog | Qt::FramelessWindowHint | Qt::CustomizeWindowHint) +{ + progressBar = new QProgressBar(this); + progressBar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred); + QFontMetrics fontMetrics = progressBar->fontMetrics(); + QString spaces; + while (fontMetrics.width(spaces) < 58) + spaces += QLatin1Char(' '); + progressBar->setFormat(progressBar->format() + spaces); + + label = new QLabel(this); + + QToolButton *button = new QToolButton(this); + button->setObjectName("cancel"); + button->setToolTip(QString::fromUtf8(language[lsCancel].c_str())); + + QHBoxLayout *layout = new QHBoxLayout; + layout->setContentsMargins(20, 0, 20, 0); + layout->setSpacing(0); + layout->addWidget(label, 1); + layout->addWidget(button, 0, Qt::AlignRight); + progressBar->setLayout(layout); + + layout = new QHBoxLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->addWidget(progressBar); + setLayout(layout); + + setModal(true); + + connect(button, SIGNAL(clicked()), this, SLOT(cancelClicked())); + + resize(320, 60); +} + +void ProgressDialog::cancelClicked() +{ + if(!wait_cursor_.get()) + wait_cursor_.reset(new WaitCursor()); + this->setDisabled(true); + emit cancel(); +} + +void ProgressDialog::startProgress(const QString &caption, unsigned long long max) +{ + label->setText(caption); + progressBar->setValue(0); + progressBar->setMaximum(max); +} + +void ProgressDialog::stepProgress(unsigned long long value) +{ + progressBar->setValue(progressBar->value() + value); +} + +void ProgressDialog::closeEvent(QCloseEvent *event) +{ + event->ignore(); +} + +void ProgressDialog::notify(MessageType type, IObject * /*sender*/, const QString &message) +{ + wait_cursor_.reset(); + switch (type) { + case mtError: + MessageDialog::critical(this, message, QMessageBox::Ok); + break; + case mtWarning: + MessageDialog::warning(this, message, QMessageBox::Ok); + break; + case mtInformation: + MessageDialog::information(this, message, QMessageBox::Ok); + break; + } +} + +/** + * GUILog + */ + +GUILog::GUILog(QObject *parent) + : QObject(parent), is_canceled_(false) +{ + qRegisterMetaType<MessageType>("MessageType"); +} + +void GUILog::Notify(MessageType type, IObject *sender, const std::string &message) +{ + emit notify(type, sender, QString::fromUtf8(message.c_str())); +} + +void GUILog::StartProgress(const std::string &caption, unsigned long long max) +{ + checkCanceled(); + emit startProgress(QString::fromUtf8(caption.c_str()), max); +} + +void GUILog::StepProgress(unsigned long long value, bool /*is_project*/) +{ + checkCanceled(); + emit stepProgress(value); +} + +void GUILog::EndProgress() +{ + checkCanceled(); + emit endProgress(); +} + +void GUILog::cancel() +{ + is_canceled_ = true; +} + +void GUILog::checkCanceled() +{ + if (is_canceled_) + throw canceled_error(language[lsOperationCanceledByUser]); +}
\ No newline at end of file diff --git a/VMProtect/progress_dialog.h b/VMProtect/progress_dialog.h new file mode 100644 index 0000000..64929a8 --- /dev/null +++ b/VMProtect/progress_dialog.h @@ -0,0 +1,53 @@ +#ifndef PROGRESS_DIALOG_H +#define PROGRESS_DIALOG_H + +class WaitCursor; + +class ProgressDialog : public QDialog +{ + Q_OBJECT +public: + ProgressDialog(QWidget *parent = NULL); +public slots: + void startProgress(const QString &caption, unsigned long long max); + void stepProgress(unsigned long long value); + void notify(MessageType type, IObject *sender, const QString &message); + void cancelClicked(); +signals: + void cancel(); +protected: + void closeEvent(QCloseEvent *event); +private: + std::auto_ptr<WaitCursor> wait_cursor_; + QProgressBar *progressBar; + QLabel *label; +}; + +Q_DECLARE_INTERFACE(ILog, "ILog") + +class GUILog : public QObject, ILog +{ + Q_OBJECT + Q_INTERFACES(ILog) +public: + GUILog(QObject *parent = 0); + virtual void Notify(MessageType type, IObject *sender, const std::string &message); + virtual void StartProgress(const std::string &caption, unsigned long long max); + virtual void StepProgress(unsigned long long value, bool is_project); + virtual void EndProgress(); + virtual void set_warnings_as_errors(bool /*value*/) { } + virtual void set_arch_name(const std::string & /*arch_name*/) { } + void reset() { is_canceled_ = false; } +public slots: + void cancel(); +signals: + void notify(MessageType type, IObject *sender, const QString &message); + void startProgress(const QString &, unsigned long long); + void stepProgress(unsigned long long); + void endProgress(); +private: + void checkCanceled(); + bool is_canceled_; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/property_editor.cc b/VMProtect/property_editor.cc new file mode 100644 index 0000000..01ec142 --- /dev/null +++ b/VMProtect/property_editor.cc @@ -0,0 +1,2765 @@ +#include "../runtime/common.h" +#include "../runtime/crypto.h" +#include "../core/objects.h" +#include "../core/osutils.h" +#include "../core/streams.h" +#include "../core/files.h" +#include "../core/lang.h" +#include "../core/core.h" +#include "../core/processors.h" +#include "widgets.h" +#include "models.h" +#include "property_editor.h" +#include "moc/moc_property_editor.cc" + +std::string formatBase64(const std::string &value) +{ + std::string res = value; + size_t len = res.size(); + for (size_t i = 0; i < len / 76; i++) { + res.insert(res.begin() + (i + 1) * 76 + i, '\n'); + } + return res; +} + +std::string formatVector(const std::vector<uint8_t> &value) +{ + std::string dst; + size_t dst_len = Base64EncodeGetRequiredLength(value.size()); + if (dst_len) { + dst.resize(dst_len); + Base64Encode(&value[0], value.size(), &dst[0], dst_len); + if (dst_len != dst.size()) + dst.resize(dst_len); + } + return formatBase64(dst); +} + +/** + * Property + */ + +Property::Property(Property *parent, const QString &name) + : parent_(NULL), name_(name), readOnly_(false) +{ + if (parent) + parent->addChild(this); +} + +Property::~Property() +{ + if (parent_) + parent_->removeChild(this); + clear(); + emit destroyed(this); +} + +void Property::clear() +{ + while (!children_.isEmpty()) { + QListIterator<Property *> it(children_); + Property *prop = it.next(); + delete prop; + } +} + +QWidget *Property::createEditor(QWidget * /*parent*/) +{ + return NULL; +} + +QString Property::valueText() const +{ + return QString(); +} + +void Property::setName(const QString &name) +{ + if (name_ == name) + return; + + name_ = name; + emit changed(this); +} + +void Property::setReadOnly(bool value) +{ + if (readOnly_ == value) + return; + + readOnly_ = value; + emit changed(this); +} + +void Property::addChild(Property *child) +{ + insertChild(childCount(), child); +} + +void Property::insertChild(int index, Property *child) +{ + if (child->parent()) + return; + + child->parent_ = this; + children_.insert(index, child); +} + +void Property::removeChild(Property *child) +{ + children_.removeOne(child); +} + +/** + * StringProperty + */ + +StringProperty::StringProperty(Property *parent, const QString &name, const QString &value) + : Property(parent, name), value_(value) +{ + +} + +QString StringProperty::valueText() const +{ + return value_; +} + +QWidget *StringProperty::createEditor(QWidget *parent) +{ + QLineEdit *editor = new LineEdit(parent); + editor->setFrame(false); + editor->setText(value_); + connect(editor, SIGNAL(textChanged(const QString &)), this, SLOT(editorChanged(const QString &))); + + return editor; +} + +void StringProperty::editorChanged(const QString &value) +{ + setValue(value); +} + +void StringProperty::setValue(const QString &value) +{ + if (value_ != value) { + value_ = value; + emit valueChanged(value); + emit changed(this); + } +} + +/** + * BoolProperty + */ + +BoolProperty::BoolProperty(Property *parent, const QString &name, bool value) + : Property(parent, name), value_(value) +{ + +} + +QString BoolProperty::valueText() const +{ + return value_ ? QString::fromUtf8(language[lsYes].c_str()) : QString::fromUtf8(language[lsNo].c_str()); +} + +QWidget *BoolProperty::createEditor(QWidget *parent) +{ + BoolEdit *editor = new BoolEdit(parent); + editor->setFrame(false); + editor->setChecked(value_); + + connect(editor, SIGNAL(toggled(bool)), this, SLOT(editorChanged(bool))); + + return editor; +} + +void BoolProperty::editorChanged(bool value) +{ + setValue(value); +} + +void BoolProperty::setValue(bool value) +{ + if (value_ != value) { + value_ = value; + emit valueChanged(value); + emit changed(this); + } +} + +/** + * DateProperty + */ + +DateProperty::DateProperty(Property *parent, const QString &name, const QDate &value) + : Property(parent, name), value_(value) +{ + +} + +QString DateProperty::valueText() const +{ + return value_.toString(Qt::SystemLocaleShortDate); +} + +QWidget *DateProperty::createEditor(QWidget *parent) +{ + QDateEdit *editor = new QDateEdit(parent); + editor->setFrame(false); + editor->setDate(value_); + connect(editor, SIGNAL(dateChanged(const QDate &)), this, SLOT(editorChanged(const QDate &))); + + return editor; +} + +void DateProperty::editorChanged(const QDate &value) +{ + setValue(value); +} + +void DateProperty::setValue(const QDate &value) +{ + if (value_ != value) { + value_ = value; + emit valueChanged(value); + emit changed(this); + } +} + +/** + * StringListProperty + */ + +StringListProperty::StringListProperty(Property *parent, const QString &name, const QString &value) + : StringProperty(parent, name, value) +{ + +} + +QWidget *StringListProperty::createEditor(QWidget *parent) +{ + StringListEdit *editor = new StringListEdit(parent); + editor->document()->setDocumentMargin(0); + editor->setFrameShape(QFrame::NoFrame); + editor->setPlainText(value()); + connect(editor, SIGNAL(textChanged(const QString &)), this, SLOT(editorChanged(const QString &))); + + return editor; +} + +/** + * HexProperty + */ + + /* +HexProperty::HexProperty(Property *parent, const QString &name, const QByteArray &value) + : Property(parent, name) +{ + edit_ = new QHexEdit(); + edit_->setFrameShape(QFrame::NoFrame); + edit_->setData(value); +} + +HexProperty::~HexProperty() +{ + delete edit_; +} + */ + +/** + * GroupProperty + */ + +GroupProperty::GroupProperty(Property *parent, const QString &name) + : Property(parent, name) +{ + +} + +/** + * CommandProperty + */ + +CommandProperty::CommandProperty(Property *parent, ICommand *value) + : Property(parent, QString::fromLatin1(value->display_address().c_str())), value_(value) +{ + text_ = QString::fromUtf8(value_->text().c_str()); +} + +QString CommandProperty::valueText() const +{ + return text_; +} + +bool CommandProperty::hasStaticText(int column) const +{ + if (!value_) + return false; + + if (column == 0) + return true; + + if (column == 1) + return (value_->comment().type > ttNone); + + return false; +} + +QString CommandProperty::staticText(int column) const +{ + if (!value_) + return QString(); + + if (column == 0) + return QString::fromLatin1(value_->dump_str().c_str()); + + if (column == 1) + return QString::fromUtf8(value_->comment().display_value().c_str()); + + return QString(); +} + +QColor CommandProperty::staticColor(int column) const +{ + if (!value_) + return QColor(); + + if (column == 0) + return Qt::gray; + + if (column == 1) { + switch (value_->comment().type) { + case ttFunction: case ttJmp: + return Qt::blue; + case ttImport: + return Qt::darkRed; + case ttExport: + return Qt::red; + case ttString: + return Qt::darkGreen; + case ttVariable: + return Qt::magenta; + case ttComment: + return Qt::gray; + } + } + return QColor(); +} + +/** + * EnumProperty + */ + +EnumProperty::EnumProperty(Property *parent, const QString &name, const QStringList &items, int value) + : Property(parent, name), items_(items), value_(value) +{ + +} + +void EnumProperty::setValue(int value) +{ + if (value_ != value) { + value_ = value; + emit valueChanged(value); + emit changed(this); + } +} + +void EnumProperty::editorChanged(int value) +{ + setValue(value); +} + +QString EnumProperty::valueText() const +{ + if (value_ >= 0 && value_ < items_.size()) + return items_[value_]; + return QString(); +} + +QWidget *EnumProperty::createEditor(QWidget *parent) +{ + EnumEdit *editor = new EnumEdit(parent, items_); + editor->setFrame(false); + editor->setCurrentIndex(value_); + + connect(editor, SIGNAL(currentIndexChanged(int)), this, SLOT(editorChanged(int))); + + return editor; +} + +/** + * CompilationTypeProperty + */ + +CompilationTypeProperty::CompilationTypeProperty(Property *parent, const QString &name, CompilationType value) + : Property(parent, name), value_(value), defaultValue_(ctNone) +{ + items_ << QString::fromUtf8(language[lsNone].c_str()); + items_ << QString::fromUtf8(language[lsVirtualization].c_str()); + items_ << QString::fromUtf8(language[lsMutation].c_str()); + items_ << QString("%1 (%2 + %3)").arg(QString::fromUtf8(language[lsUltra].c_str())).arg(QString::fromUtf8(language[lsMutation].c_str())).arg(QString::fromUtf8(language[lsVirtualization].c_str())); +} + +void CompilationTypeProperty::setValue(CompilationType value) +{ + if (value_ != value) { + value_ = value; + emit valueChanged(value); + emit changed(this); + } +} + +void CompilationTypeProperty::editorChanged(int value) +{ + CompilationType new_value = ctNone; + if (value > 0) { + if (defaultValue_ == ctNone) + new_value = static_cast<CompilationType>(value - 1); + else + new_value = (value == 1) ? defaultValue_ : ctNone; + } + + setValue(new_value); +} + +QString CompilationTypeProperty::valueText() const +{ + switch (value_) { + case ctNone: + return items_[0]; + case ctVirtualization: + return items_[1]; + case ctMutation: + return items_[2]; + case ctUltra: + return items_[3]; + } + + return QString(); +} + +QWidget *CompilationTypeProperty::createEditor(QWidget *parent) +{ + QStringList items; + items << items_[0]; + switch (defaultValue_) { + case ctNone: + items << items_[1]; + items << items_[2]; + items << items_[3]; + break; + case ctVirtualization: + items << items_[1]; + break; + case ctMutation: + items << items_[2]; + break; + case ctUltra: + items << items_[3]; + break; + } + + int index = 0; + if (defaultValue_ != ctNone) { + if (value_ == defaultValue_) + index = 1; + } else if (value_ != ctNone) { + index = value_ + 1; + } + + EnumEdit *editor = new EnumEdit(parent, items); + editor->setFrame(false); + editor->setCurrentIndex(index); + + connect(editor, SIGNAL(currentIndexChanged(int)), this, SLOT(editorChanged(int))); + + return editor; +} + +/** + * FileNameProperty + */ + +FileNameProperty::FileNameProperty(Property *parent, const QString &name, const QString &filter, const QString &value, bool saveMode) + : Property(parent, name), filter_(filter), value_(value), saveMode_(saveMode) +{ + +} + +QString FileNameProperty::valueText() const +{ + return value_; +} + +QWidget *FileNameProperty::createEditor(QWidget *parent) +{ + FileNameEdit *editor = new FileNameEdit(parent); + editor->setFrame(false); + editor->setFilter(filter_); + editor->setRelativePath(relativePath_); + editor->setText(value_); + editor->setSaveMode(saveMode_); + connect(editor, SIGNAL(textChanged(const QString &)), this, SLOT(editorChanged(const QString &))); + + return editor; +} + +void FileNameProperty::editorChanged(const QString &value) +{ + setValue(value); +} + +void FileNameProperty::setValue(const QString &value) +{ + if (value_ != value) { + value_ = value; + emit valueChanged(value); + emit changed(this); + } +} + +/** + * FileNameProperty + */ + +WatermarkProperty::WatermarkProperty(Property *parent, const QString &name, const QString &value) + : Property(parent, name), value_(value) +{ + +} + +QString WatermarkProperty::valueText() const +{ + return value_; +} + +QWidget *WatermarkProperty::createEditor(QWidget *parent) +{ + WatermarkEdit *editor = new WatermarkEdit(parent); + editor->setFrame(false); + editor->setText(value_); + connect(editor, SIGNAL(textChanged(const QString &)), this, SLOT(editorChanged(const QString &))); + + return editor; +} + +void WatermarkProperty::editorChanged(const QString &value) +{ + setValue(value); +} + +void WatermarkProperty::setValue(const QString &value) +{ + if (value_ != value) { + value_ = value; + emit valueChanged(value); + emit changed(this); + } +} + +/** + * PropertyManager + */ + +PropertyManager::PropertyManager(QObject *parent) + : QAbstractItemModel(parent) +{ + root_ = new GroupProperty(NULL, ""); +} + +PropertyManager::~PropertyManager() +{ + delete root_; +} + +QModelIndex PropertyManager::index(int row, int column, const QModelIndex &parent) const +{ + //if (parent.isValid() && parent.column() != 0) + // return QModelIndex(); + + Property *parentProp = indexToProperty(parent); + Property *childProp = parentProp->children().value(row); + if (!childProp) + return QModelIndex(); + + return createIndex(row, column, childProp); +} + +QModelIndex PropertyManager::parent(const QModelIndex &index) const +{ + if (!index.isValid()) + return QModelIndex(); + + Property *childProp = indexToProperty(index); + Property *parentProp = childProp->parent(); + if (parentProp == root_) + return QModelIndex(); + + return createIndex(parentProp->parent()->children().indexOf(parentProp), 0, parentProp); +} + +int PropertyManager::columnCount(const QModelIndex & /* parent */) const +{ + return 2; +} + +int PropertyManager::rowCount(const QModelIndex &parent) const +{ + Property *parentProp = indexToProperty(parent); + return parentProp->childCount(); +} + +QVariant PropertyManager::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + Property *prop = indexToProperty(index); + switch (role) { + case Qt::DisplayRole: + if (index.column() == 0) { + return prop->name(); + } else if (index.column() == 1) { + return prop->valueText(); + } + break; + case Qt::DecorationRole: + if (CommandProperty *c = qobject_cast<CommandProperty *>(prop)) { + if (index.column() == 0) { + ICommand *command = c->value(); + IFunction *func = command->owner(); + if (qobject_cast<CommandProperty *>(c->parent())) { + return QIcon(":/images/reference.png"); + } else if (func->ext_command_list()->GetCommandByAddress(command->address())) { + return QIcon(":/images/link.png"); + } else if (func->is_breaked_address(command->address())) { + return QIcon(":/images/disabled.png"); + } + QIcon res; + QPixmap pixmap(18, 1); + pixmap.fill(Qt::transparent); + res.addPixmap(pixmap); + return res; + } + } + break; + case Qt::TextColorRole: + if (prop->readOnly() && index.column() == 1) { + QPalette palette; + return palette.color(QPalette::Disabled, QPalette::Text); + } + break; + case Qt::FontRole: + if (!prop->readOnly() && index.column() == 1) { + QFont font; + font.setBold(true); + return font; + } + break; + case Qt::Vmp::StaticTextRole: + if (prop->hasStaticText(index.column())) + return prop->staticText(index.column()); + break; + case Qt::Vmp::StaticColorRole: + if (prop->hasStaticText(index.column())) + return prop->staticColor(index.column()); + break; + } + + return QVariant(); +} + +QVariant PropertyManager::headerData(int section, Qt::Orientation /*orientation*/, int role) const +{ + if (role == Qt::DisplayRole) { + if (section == 0) { + return QString::fromUtf8(language[lsName].c_str()); + } else { + return QString::fromUtf8(language[lsValue].c_str()); + } + } + return QVariant(); +} + +void PropertyManager::clear() +{ + root_->clear(); +} + +BoolProperty *PropertyManager::addBoolProperty(Property *parent, const QString &name, bool value) +{ + BoolProperty *prop = new BoolProperty(parent ? parent : root_, name, value); + addProperty(prop); + return prop; +} + +StringProperty *PropertyManager::addStringProperty(Property *parent, const QString &name, const QString &value) +{ + StringProperty *prop = new StringProperty(parent ? parent : root_, name, value); + addProperty(prop); + return prop; +} + +DateProperty *PropertyManager::addDateProperty(Property *parent, const QString &name, const QDate &value) +{ + DateProperty *prop = new DateProperty(parent ? parent : root_, name, value); + addProperty(prop); + return prop; +} + +StringListProperty *PropertyManager::addStringListProperty(Property *parent, const QString &name, const QString &value) +{ + StringListProperty *prop = new StringListProperty(parent ? parent : root_, name, value); + addProperty(prop); + return prop; +} + +GroupProperty *PropertyManager::addGroupProperty(Property *parent, const QString &name) +{ + GroupProperty *prop = new GroupProperty(parent ? parent : root_, name); + addProperty(prop); + return prop; +} + +EnumProperty *PropertyManager::addEnumProperty(Property *parent, const QString &name, const QStringList &items, int value) +{ + EnumProperty *prop = new EnumProperty(parent ? parent : root_, name, items, value); + addProperty(prop); + return prop; +} + +FileNameProperty *PropertyManager::addFileNameProperty(Property *parent, const QString &name, const QString &filter, const QString &value, bool saveMode) +{ + FileNameProperty *prop = new FileNameProperty(parent ? parent : root_, name, filter, value, saveMode); + addProperty(prop); + return prop; +} + +CommandProperty *PropertyManager::addCommandProperty(Property *parent, ICommand *value) +{ + CommandProperty *prop = new CommandProperty(parent ? parent : root_, value); + addProperty(prop); + return prop; +} + +WatermarkProperty *PropertyManager::addWatermarkProperty(Property *parent, const QString &name, const QString &value) +{ + WatermarkProperty *prop = new WatermarkProperty(parent ? parent : root_, name, value); + addProperty(prop); + return prop; +} + +CompilationTypeProperty *PropertyManager::addCompilationTypeProperty(Property *parent, const QString &name, CompilationType value) +{ + CompilationTypeProperty *prop = new CompilationTypeProperty(parent ? parent : root_, name, value); + addProperty(prop); + return prop; +} + +void PropertyManager::addProperty(Property *prop) +{ + if (!prop) + return; + + connect(prop, SIGNAL(destroyed(Property *)), this, SLOT(slotPropertyDestroyed(Property *))); + connect(prop, SIGNAL(changed(Property *)), this, SLOT(slotPropertyChanged(Property *))); +} + +Property *PropertyManager::indexToProperty(const QModelIndex &index) const +{ + if (index.isValid()) + return static_cast<Property *>(index.internalPointer()); + return root_; +} + +QModelIndex PropertyManager::propertyToIndex(Property *prop) const +{ + if (!prop) + return QModelIndex(); + + return createIndex(prop->parent()->children().indexOf(prop), 0, prop); +} + +void PropertyManager::slotPropertyChanged(Property *prop) +{ + QModelIndex index = propertyToIndex(prop); + emit dataChanged(index, index.sibling(index.row(), 1)); +} + +void PropertyManager::slotPropertyDestroyed(Property * /*prop*/) +{ + // +} + +Qt::ItemFlags PropertyManager::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return 0; + + Qt::ItemFlags res = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + Property *prop = indexToProperty(index); + if (prop && prop->hasValue() && !prop->readOnly()) + res |= Qt::ItemIsEditable; + return res; +} + +/** + * PropertyEditorDelegate + */ + +PropertyEditorDelegate::PropertyEditorDelegate(QObject *parent) + : TreeViewItemDelegate(parent) +{ + +} + +Property *PropertyEditorDelegate::indexToProperty(const QModelIndex &index) const +{ + return static_cast<Property *>(index.internalPointer()); +} + +QWidget *PropertyEditorDelegate::createEditor(QWidget *parent, + const QStyleOptionViewItem &, const QModelIndex &index) const +{ + if (index.column() != 1) + return NULL; + + Property *prop = indexToProperty(index); + if (!prop) + return NULL; + + QWidget *editor = prop->createEditor(parent); + if (editor) { + QWidget *corrBearing = dynamic_cast<QLineEdit *>(editor); + editor->setObjectName("editor"); + editor->setAutoFillBackground(true); + QVariant value = index.data(Qt::FontRole); + if (value.isValid() && value.canConvert<QFont>()) + editor->setFont(qvariant_cast<QFont>(value)); + if (QComboBox *c = qobject_cast<QComboBox *>(editor)) { + c->lineEdit()->selectAll(); + corrBearing = c; + } else if (QPlainTextEdit *c = qobject_cast<QPlainTextEdit *>(editor)) { + c->selectAll(); + } + if(corrBearing) + { + corrBearing->setProperty("corrBearing", +#ifdef __APPLE__ + false +#else + true +#endif + ); + corrBearing->style()->unpolish(corrBearing); + corrBearing->style()->polish(corrBearing); + corrBearing->update(); + } + } + return editor; +} + +void PropertyEditorDelegate::setEditorData(QWidget * /*widget*/, const QModelIndex &) const +{ + //do nothing +} + +/** + * TreePropertyEditor + */ + +TreePropertyEditor::TreePropertyEditor(QWidget *parent) + : TreeView(parent) +{ + setObjectName("grid"); + setIconSize(QSize(18, 18)); + setFrameShape(QFrame::NoFrame); + setItemDelegate(new PropertyEditorDelegate(this)); +} + +Property *TreePropertyEditor::indexToProperty(const QModelIndex &index) const +{ + return static_cast<Property *>(index.internalPointer()); +} + +void TreePropertyEditor::keyPressEvent(QKeyEvent *event) +{ + switch (event->key()) { + case Qt::Key_Return: + case Qt::Key_Enter: + case Qt::Key_Space: // Trigger Edit + { + QModelIndex index = currentIndex(); + if ((index.flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled)) { + event->accept(); + // If the current position is at column 0, move to 1. + if (index.column() == 0) { + index = index.sibling(index.row(), 1); + setCurrentIndex(index); + } + edit(index); + return; + } + } + break; + default: + break; + } + + TreeView::keyPressEvent(event); +} + +void TreePropertyEditor::mousePressEvent(QMouseEvent *event) +{ + QTreeView::mousePressEvent(event); + QModelIndex index = indexAt(event->pos()); + + if (index.isValid()) { + Property *prop = indexToProperty(index); + if ((event->button() == Qt::LeftButton) && (index.column() == 1) && ((index.flags() & (Qt::ItemIsEditable | Qt::ItemIsEnabled)) == (Qt::ItemIsEditable | Qt::ItemIsEnabled))) { + edit(index); + } else if (!rootIsDecorated() && prop->childCount()) { + QRect rect = visualRect(index); + if (event->pos().x() >= rect.left() && event->pos().x() <= rect.left() + 20) + setExpanded(index, !isExpanded(index)); + } + } +} + +void TreePropertyEditor::dataChanged(const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector<int> &roles /*= QVector<int>()*/) +{ + QRect rect = visualRect(topLeft); + QTreeView::dataChanged(topLeft, bottomRight, roles); + if (topLeft.row() == bottomRight.row() && topLeft.isValid()) { + if (rect != visualRect(bottomRight)) + updateEditorGeometries(); + } +} + +/** + * LicensePropertyManager + */ + +LicensePropertyManager::LicensePropertyManager(QObject *parent) + : PropertyManager(parent), value_(NULL), lock_(false) +{ + details_ = addGroupProperty(NULL, QString::fromUtf8(language[lsDetails].c_str())); + licenseName_ = addStringProperty(details_, QString::fromUtf8(language[lsCustomerName].c_str()), QString()); + licenseEmail_ = addStringProperty(details_, QString::fromUtf8(language[lsEmail].c_str()), QString()); + licenseDate_ = addDateProperty(details_, QString::fromUtf8(language[lsDate].c_str()), QDate()); + licenseOrder_ = addStringProperty(details_, QString::fromUtf8(language[lsOrderRef].c_str()), QString()); + licenseComments_ = addStringListProperty(details_, QString::fromUtf8(language[lsComments].c_str()), QString()); + licenseBlocked_ = addBoolProperty(details_, QString::fromUtf8(language[lsBlocked].c_str()), false); + licenseSerialNumber_ = addStringProperty(details_, QString::fromUtf8(language[lsSerialNumber].c_str()), QString()); + licenseSerialNumber_->setReadOnly(true); + + contents_ = addGroupProperty(NULL, QString::fromUtf8(language[lsSerialNumberContents].c_str())); + serialName_ = addStringProperty(contents_, QString::fromUtf8(language[lsCustomerName].c_str()), QString()); + serialName_->setReadOnly(true); + serialEmail_ = addStringProperty(contents_, QString::fromUtf8(language[lsEmail].c_str()), QString()); + serialEmail_->setReadOnly(true); + serialHWID_ = addStringProperty(contents_, QString::fromUtf8(language[lsHardwareID].c_str()), QString()); + serialHWID_->setReadOnly(true); + serialExpirationDate_ = addDateProperty(contents_, QString::fromUtf8(language[lsExpirationDate].c_str()), QDate()); + serialExpirationDate_->setReadOnly(true); + serialTimeLimit_ = addStringProperty(contents_, QString::fromUtf8(language[lsRunningTimeLimit].c_str()), QString()); + serialTimeLimit_->setReadOnly(true); + serialMaxBuildDate_ = addDateProperty(contents_, QString::fromUtf8(language[lsMaxBuildDate].c_str()), QDate()); + serialMaxBuildDate_->setReadOnly(true); + serialUserData_ = addStringProperty(contents_, QString::fromUtf8(language[lsUserData].c_str()), QString()); + serialUserData_->setReadOnly(true); + + connect(licenseName_, SIGNAL(valueChanged(const QString &)), this, SLOT(nameChanged(const QString &))); + connect(licenseEmail_, SIGNAL(valueChanged(const QString &)), this, SLOT(emailChanged(const QString &))); + connect(licenseDate_, SIGNAL(valueChanged(const QDate &)), this, SLOT(dateChanged(const QDate &))); + connect(licenseOrder_, SIGNAL(valueChanged(const QString &)), this, SLOT(orderChanged(const QString &))); + connect(licenseComments_, SIGNAL(valueChanged(const QString &)), this, SLOT(commentsChanged(const QString &))); + connect(licenseBlocked_, SIGNAL(valueChanged(bool)), this, SLOT(blockedChanged(bool))); + + localize(); +} + +void LicensePropertyManager::localize() +{ + details_->setName(QString::fromUtf8(language[lsDetails].c_str())); + licenseName_->setName(QString::fromUtf8(language[lsCustomerName].c_str())); + licenseEmail_->setName(QString::fromUtf8(language[lsEmail].c_str())); + licenseDate_->setName(QString::fromUtf8(language[lsDate].c_str())); + licenseComments_->setName(QString::fromUtf8(language[lsComments].c_str())); + licenseOrder_->setName(QString::fromUtf8(language[lsOrderRef].c_str())); + licenseBlocked_->setName(QString::fromUtf8(language[lsBlocked].c_str())); + licenseSerialNumber_->setName(QString::fromUtf8(language[lsSerialNumber].c_str())); + + contents_->setName(QString::fromUtf8(language[lsSerialNumberContents].c_str())); + serialName_->setName(QString::fromUtf8(language[lsCustomerName].c_str())); + serialEmail_->setName(QString::fromUtf8(language[lsEmail].c_str())); + serialHWID_->setName(QString::fromUtf8(language[lsHardwareID].c_str())); + serialExpirationDate_->setName(QString::fromUtf8(language[lsExpirationDate].c_str())); + serialTimeLimit_->setName(QString::fromUtf8(language[lsRunningTimeLimit].c_str())); + serialMaxBuildDate_->setName(QString::fromUtf8(language[lsMaxBuildDate].c_str())); + serialUserData_->setName(QString::fromUtf8(language[lsUserData].c_str())); +} + +QVariant LicensePropertyManager::data(const QModelIndex &index, int role) const +{ + Property *prop = indexToProperty(index); + if (role == Qt::FontRole) { + if (index.column() == 1 && (prop == licenseSerialNumber_ || prop == serialUserData_)) + return QFont(MONOSPACE_FONT_FAMILY); + } + + return PropertyManager::data(index, role); +} + +void LicensePropertyManager::nameChanged(const QString &value) +{ + if (!value_ || lock_) + return; + +#ifdef ULTIMATE + value_->set_customer_name(value.toUtf8().constData()); +#endif +} + +void LicensePropertyManager::emailChanged(const QString &value) +{ + if (!value_ || lock_) + return; + +#ifdef ULTIMATE + value_->set_customer_email(value.toUtf8().constData()); +#endif +} + +void LicensePropertyManager::orderChanged(const QString &value) +{ + if (!value_ || lock_) + return; + +#ifdef ULTIMATE + value_->set_order_ref(value.toUtf8().constData()); +#endif +} + +void LicensePropertyManager::dateChanged(const QDate &value) +{ + if (!value_ || lock_) + return; + +#ifdef ULTIMATE + value_->set_date(LicenseDate(value.year(), value.month(), value.day())); +#endif +} + +void LicensePropertyManager::commentsChanged(const QString &value) +{ + if (!value_ || lock_) + return; + +#ifdef ULTIMATE + value_->set_comments(value.toUtf8().constData()); +#endif +} + +void LicensePropertyManager::blockedChanged(bool value) +{ + if (!value_ || lock_) + return; + +#ifdef ULTIMATE + value_->set_blocked(value); +#endif +} + +void LicensePropertyManager::setValue(License *value) +{ + value_ = value; + update(); +} + +void LicensePropertyManager::update() +{ +#ifdef ULTIMATE + lock_ = true; + + licenseName_->setValue(value_ ? QString::fromUtf8(value_->customer_name().c_str()) : QString()); + licenseEmail_->setValue(value_ ? QString::fromUtf8(value_->customer_email().c_str()) : QString()); + licenseDate_->setValue(value_ ? QDate(value_->date().Year, value_->date().Month, value_->date().Day) : QDate()); + licenseOrder_->setValue(value_ ? QString::fromUtf8(value_->order_ref().c_str()) : QString()); + licenseComments_->setValue(value_ ? QString::fromUtf8(value_->comments().c_str()) : QString()); + licenseBlocked_->setValue(value_ ? value_->blocked() : false); + licenseSerialNumber_->setValue(value_ ? QString::fromLatin1(formatBase64(value_->serial_number()).c_str()) : QString()); + + LicenseInfo *license_info = value_ ? value_->info() : NULL; + serialName_->setValue(license_info && (license_info->Flags & HAS_USER_NAME) ? QString::fromUtf8(license_info->CustomerName.c_str()) : QString()); + serialEmail_->setValue(license_info && (license_info->Flags & HAS_EMAIL) ? QString::fromUtf8(license_info->CustomerEmail.c_str()) : QString()); + serialHWID_->setValue(license_info && (license_info->Flags & HAS_HARDWARE_ID) ? QString::fromLatin1(license_info->HWID.c_str()) : QString()); + serialTimeLimit_->setValue(license_info && (license_info->Flags & HAS_TIME_LIMIT) ? QString::number(license_info->RunningTimeLimit) : QString()); + serialExpirationDate_->setValue(license_info && (license_info->Flags & HAS_EXP_DATE) ? QDate(license_info->ExpireDate.Year, license_info->ExpireDate.Month, license_info->ExpireDate.Day) : QDate()); + serialMaxBuildDate_->setValue(license_info && (license_info->Flags & HAS_MAX_BUILD_DATE) ? QDate(license_info->MaxBuildDate.Year, license_info->MaxBuildDate.Month, license_info->MaxBuildDate.Day) : QDate()); + QString userData; + if (license_info && license_info->Flags & HAS_USER_DATA) { + int bytes = 16; + for (size_t line = 0; line <= license_info->UserData.size() / bytes; line++) { + QString hex; + QString text; + for (int i = 0; i < bytes; i++) { + size_t pos = line * bytes + i; + if (pos < license_info->UserData.size()) { + uint8_t value = static_cast<uint8_t>(license_info->UserData[pos]); + hex.append(QString("%1 ").arg(value, 2, 16, QChar('0'))); + QChar qc(value); + if (qc.unicode() >= 127 || !qc.isPrint()) + qc = 0xB7; + text += qc; + } else { + if (i == 0) + break; + hex.append(" "); + text.append(" "); + } + } + if (!hex.isEmpty()) { + if (!userData.isEmpty()) + userData.append('\n'); + userData.append(QString("%1 ").arg(line * bytes, 4, 16, QChar('0'))).append(hex).append(text); + } + } + } + serialUserData_->setValue(userData); + + if (serialHWID_->childCount()) { + beginRemoveRows(propertyToIndex(serialHWID_), 0, serialHWID_->childCount()); + serialHWID_->clear(); + endRemoveRows(); + } + if (license_info && (license_info->Flags & HAS_HARDWARE_ID) && !license_info->HWID.empty()) { + size_t len = license_info->HWID.size(); + uint8_t *hwid = new uint8_t[len]; + Base64Decode(license_info->HWID.c_str(), license_info->HWID.size(), hwid, len); + beginInsertRows(propertyToIndex(serialHWID_), 0, (int)(len / 4)); + for (size_t i = 0; i < len; i += 4) { + uint32_t value = *reinterpret_cast<uint32_t *>(&hwid[i]); + QString name; + switch (value & 3) { + case 0: + name = QString::fromUtf8(language[lsCPU].c_str()); + break; + case 1: + name = QString::fromUtf8(language[lsHost].c_str()); + break; + case 2: + name = QString::fromUtf8(language[lsEthernet].c_str()); + break; + case 3: + name = QString::fromUtf8(language[lsHDD].c_str()); + break; + } + StringProperty *prop = addStringProperty(serialHWID_, name, QString("%1").arg(value & ~3, 8, 16, QChar('0')).toUpper()); + prop->setReadOnly(true); + } + delete [] hwid; + endInsertRows(); + } + + lock_ = false; +#endif +} + +/** + * FilePropertyManager + */ + +InternalFilePropertyManager::InternalFilePropertyManager(QObject *parent) + : PropertyManager(parent), value_(NULL), lock_(false) +{ + details_ = addGroupProperty(NULL, QString::fromUtf8(language[lsDetails].c_str())); + name_ = addStringProperty(details_, QString::fromUtf8(language[lsName].c_str()), QString()); + fileName_ = addFileNameProperty(details_, QString::fromUtf8(language[lsFileName].c_str()), QString( +#ifdef VMP_GNU + "%1 (*)" +#else + "%1 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsAllFiles].c_str())), QString()); + + action_ = addEnumProperty(details_, QString::fromUtf8(language[lsAction].c_str()), QStringList() << QString::fromUtf8(language[lsNo].c_str()) + << QString::fromUtf8(language[lsLoadAtStart].c_str()) << QString::fromUtf8(language[lsRegisterCOMServer].c_str()) << QString::fromUtf8(language[lsInstallCOMServer].c_str()), 0); + + connect(name_, SIGNAL(valueChanged(const QString &)), this, SLOT(nameChanged(const QString &))); + connect(fileName_, SIGNAL(valueChanged(const QString &)), this, SLOT(fileNameChanged(const QString &))); + connect(action_, SIGNAL(valueChanged(int)), this, SLOT(actionChanged(int))); +} + +void InternalFilePropertyManager::localize() +{ + details_->setName(QString::fromUtf8(language[lsDetails].c_str())); + name_->setName(QString::fromUtf8(language[lsName].c_str())); + fileName_->setName(QString::fromUtf8(language[lsFileName].c_str())); + fileName_->setFilter(QString( +#ifdef VMP_GNU + "%1 (*)" +#else + "%1 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsAllFiles].c_str()))); + action_->setName(QString::fromUtf8(language[lsAction].c_str())); + action_->setText(0, QString::fromUtf8(language[lsNo].c_str())); + action_->setText(1, QString::fromUtf8(language[lsLoadAtStart].c_str())); + action_->setText(2, QString::fromUtf8(language[lsRegisterCOMServer].c_str())); + action_->setText(3, QString::fromUtf8(language[lsInstallCOMServer].c_str())); +} + +void InternalFilePropertyManager::nameChanged(const QString &value) +{ + if (!value_ || lock_) + return; + +#ifdef ULTIMATE + value_->set_name(value.toUtf8().constData()); +#endif +} + +void InternalFilePropertyManager::fileNameChanged(const QString &value) +{ + if (!value_ || lock_) + return; + +#ifdef ULTIMATE + value_->set_file_name(value.toUtf8().constData()); +#endif +} + +void InternalFilePropertyManager::actionChanged(int value) +{ + if (!value_ || lock_) + return; + +#ifdef ULTIMATE + value_->set_action(static_cast<InternalFileAction>(value)); +#endif +} + +void InternalFilePropertyManager::setValue(InternalFile *value) +{ + value_ = value; + +#ifdef ULTIMATE + fileName_->setRelativePath(value_ ? QString::fromUtf8(value_->owner()->owner()->project_path().c_str()) : QString()); + update(); +#endif +} + +void InternalFilePropertyManager::update() +{ +#ifdef ULTIMATE + lock_ = true; + + name_->setValue(value_ ? QString::fromUtf8(value_->name().c_str()) : QString()); + fileName_->setValue(value_ ? QString::fromUtf8(value_->file_name().c_str()) : QString()); + int i = 0; + if (value_) { + switch (value_->action()) { + case faLoad: + i = 1; + break; + case faRegister: + i = 2; + break; + case faInstall: + i = 3; + break; + } + } + action_->setValue(value_ ? i : 0); + + lock_ = false; +#endif +} + +/** +* AssemblyPropertyManager +*/ + +AssemblyPropertyManager::AssemblyPropertyManager(QObject *parent) + : PropertyManager(parent), value_(NULL), lock_(false) +{ + details_ = addGroupProperty(NULL, QString::fromUtf8(language[lsDetails].c_str())); + name_ = addStringProperty(details_, QString::fromUtf8(language[lsName].c_str()), QString()); + fileName_ = addFileNameProperty(details_, QString::fromUtf8(language[lsFileName].c_str()), + QString("%1 (*.dll);;%2 (*.*)").arg(QString::fromUtf8(language[lsAssemblies].c_str())).arg(QString::fromUtf8(language[lsAllFiles].c_str())), QString()); + + connect(name_, SIGNAL(valueChanged(const QString &)), this, SLOT(nameChanged(const QString &))); + connect(fileName_, SIGNAL(valueChanged(const QString &)), this, SLOT(fileNameChanged(const QString &))); +} + +void AssemblyPropertyManager::localize() +{ + details_->setName(QString::fromUtf8(language[lsDetails].c_str())); + name_->setName(QString::fromUtf8(language[lsName].c_str())); + fileName_->setName(QString::fromUtf8(language[lsFileName].c_str())); + fileName_->setFilter(QString("%1 (*.dll);;%2 (*.*)").arg(QString::fromUtf8(language[lsAssemblies].c_str())).arg(QString::fromUtf8(language[lsAllFiles].c_str()))); +} + +void AssemblyPropertyManager::nameChanged(const QString &value) +{ + if (!value_ || lock_) + return; + +#ifdef ULTIMATE + value_->set_name(value.toUtf8().constData()); +#endif +} + +void AssemblyPropertyManager::fileNameChanged(const QString &value) +{ + if (!value_ || lock_) + return; + +#ifdef ULTIMATE + value_->set_file_name(value.toUtf8().constData()); +#endif +} + +void AssemblyPropertyManager::setValue(InternalFile *value) +{ + value_ = value; + +#ifdef ULTIMATE + fileName_->setRelativePath(value_ ? QString::fromUtf8(value_->owner()->owner()->project_path().c_str()) : QString()); + update(); +#endif +} + +void AssemblyPropertyManager::update() +{ +#ifdef ULTIMATE + lock_ = true; + + name_->setValue(value_ ? QString::fromUtf8(value_->name().c_str()) : QString()); + fileName_->setValue(value_ ? QString::fromUtf8(value_->file_name().c_str()) : QString()); + + lock_ = false; +#endif +} + +/** + * FunctionPropertyManager + */ + +FunctionPropertyManager::FunctionPropertyManager(QObject *parent) + : PropertyManager(parent), value_(NULL), lock_(false) +{ + protection_ = addGroupProperty(NULL, QString::fromUtf8(language[lsProtection].c_str())); + compilationType_ = addCompilationTypeProperty(protection_, QString::fromUtf8(language[lsCompilationType].c_str()), ctNone); + lockToKey_ = addBoolProperty(protection_, QString::fromUtf8(language[lsLockToSerialNumber].c_str()), false); + + details_ = addGroupProperty(NULL, QString::fromUtf8(language[lsDetails].c_str())); + type_ = addStringProperty(details_, QString::fromUtf8(language[lsType].c_str()), QString()); + type_->setReadOnly(true); + name_ = addStringProperty(details_, QString::fromUtf8(language[lsName].c_str()), QString()); + name_->setReadOnly(true); + address_ = addStringProperty(details_, QString::fromUtf8(language[lsAddress].c_str()), QString()); + address_->setReadOnly(true); + + connect(compilationType_, SIGNAL(valueChanged(CompilationType)), this, SLOT(compilationTypeChanged(CompilationType))); + connect(lockToKey_, SIGNAL(valueChanged(bool)), this, SLOT(lockToKeyChanged(bool))); +} + +void FunctionPropertyManager::localize() +{ + protection_->setName(QString::fromUtf8(language[lsProtection].c_str())); + compilationType_->setName(QString::fromUtf8(language[lsCompilationType].c_str())); + compilationType_->setText(0, QString::fromUtf8(language[lsNone].c_str())); + compilationType_->setText(1, QString::fromUtf8(language[lsVirtualization].c_str())); + compilationType_->setText(2, QString::fromUtf8(language[lsMutation].c_str())); + compilationType_->setText(3, QString("%1 (%2 + %3)").arg(QString::fromUtf8(language[lsUltra].c_str())).arg(QString::fromUtf8(language[lsMutation].c_str())).arg(QString::fromUtf8(language[lsVirtualization].c_str()))); + compilationType_->setToolTip(QString::fromUtf8(language[lsCompilationTypeHelp].c_str())); + + lockToKey_->setName(QString::fromUtf8(language[lsLockToSerialNumber].c_str())); + lockToKey_->setToolTip(QString::fromUtf8(language[lsLockToSerialNumberHelp].c_str())); + + details_->setName(QString::fromUtf8(language[lsDetails].c_str())); + type_->setName(QString::fromUtf8(language[lsType].c_str())); + name_->setName(QString::fromUtf8(language[lsName].c_str())); + address_->setName(QString::fromUtf8(language[lsAddress].c_str())); + + if (value_) { + for (QMap<IArchitecture *, ArchInfo>::const_iterator arch = map_.begin(); arch != map_.end(); arch++) { + QString str = QString::fromUtf8(language[lsCode].c_str()); + if (value_->show_arch_name()) + str.append(" ").append(QString::fromLatin1(arch.key()->name().c_str())); + arch.value().code->setName(str); + } + update(); + } +} + +QVariant FunctionPropertyManager::data(const QModelIndex &index, int role) const +{ + Property *prop = indexToProperty(index); + if (role == Qt::FontRole) { + if (qobject_cast<CommandProperty*>(prop)) + return QFont(MONOSPACE_FONT_FAMILY); + } + + return PropertyManager::data(index, role); +} + +void FunctionPropertyManager::setValue(FunctionBundle *value) +{ + if (value_ == value) + return; + + value_ = value; + + for (QMap<IArchitecture *, ArchInfo>::iterator arch = map_.begin(); arch != map_.end(); arch++) { + Property *code = arch.value().code; + if (code->childCount()) { + beginRemoveRows(propertyToIndex(code), 0, code->childCount()); + code->clear(); + endRemoveRows(); + } + arch.value().map.clear(); + } + + if (value_) { + for (size_t i = 0; i < value_->count(); i++) { + internalAddFunction(value_->item(i)->func()); + } + } else { + for (QMap<IArchitecture *, ArchInfo>::const_iterator arch = map_.begin(); arch != map_.end(); arch++) { + Property *code = arch.value().code; + int index = code->parent()->children().indexOf(code); + beginRemoveRows(propertyToIndex(code->parent()), index, index + 1); + delete code; + endRemoveRows(); + } + map_.clear(); + } + + update(); +} + +void FunctionPropertyManager::addFunction(IFunction *func) +{ + if (internalAddFunction(func)) + update(); +} + +void FunctionPropertyManager::createCommands(IFunction *func, Property *code) +{ + size_t i; + QMap<uint64_t, QList<ICommand*> > references; + + for (i = 0; i < func->link_list()->count(); i++) { + CommandLink *link = func->link_list()->item(i); + if (link->to_address()) { + QMap<uint64_t, QList<ICommand*> >::iterator it = references.find(link->to_address()); + if (it == references.end()) + it = references.insert(link->to_address(), QList<ICommand*>() << link->from_command()); + else + it.value().push_back(link->from_command()); + } + } + + beginInsertRows(propertyToIndex(code), 0, (int)func->count()); + for (i = 0; i < func->count(); i++) { + ICommand *command = func->item(i); + Property *prop = addCommandProperty(code, command); + prop->setReadOnly(true); + + QMap<uint64_t, QList<ICommand*> >::ConstIterator it = references.find(command->address()); + if (it != references.end()) { + for (int j = 0; j < it.value().size(); j++) { + Property *link_prop = addCommandProperty(prop, it.value().at(j)); + link_prop->setReadOnly(true); + } + } + } + endInsertRows(); +} + +bool FunctionPropertyManager::internalAddFunction(IFunction *func) +{ + if (!value_) + return false; + + FunctionArch *func_arch = value_->GetArchByFunction(func); + if (!func_arch) + return false; + + QMap<IArchitecture *, ArchInfo>::iterator arch = map_.find(func_arch->arch()); + if (arch == map_.end()) { + beginInsertRows(propertyToIndex(details_), details_->childCount(), details_->childCount() + 1); + QString str = QString::fromUtf8(language[lsCode].c_str()); + if (value_->show_arch_name()) + str.append(" ").append(QString::fromLatin1(func_arch->arch()->name().c_str())); + ArchInfo info; + info.code = addStringProperty(details_, str, QString()); + info.code->setReadOnly(true); + endInsertRows(); + arch = map_.insert(func_arch->arch(), info); + } + QMap<IFunction *, StringProperty *>::const_iterator it = arch.value().map.find(func); + if (it == arch.value().map.end()) { + StringProperty *code = arch.value().code; + if (!arch.value().map.empty()) { + if (arch.value().map.size() == 1) { + QMap<IFunction *, StringProperty *>::iterator tmp = arch.value().map.begin(); + if (tmp.value() == code) { + beginRemoveRows(propertyToIndex(code), 0, code->childCount()); + code->clear(); + endRemoveRows(); + + beginInsertRows(propertyToIndex(code), code->childCount(), code->childCount() + 1); + StringProperty *newCode = addStringProperty(code, QString::fromLatin1(tmp.key()->display_address("").c_str()), QString()); + newCode->setReadOnly(true); + endInsertRows(); + tmp.value() = newCode; + + createCommands(tmp.key(), newCode); + } + } + beginInsertRows(propertyToIndex(code), code->childCount(), code->childCount() + 1); + code = addStringProperty(code, QString::fromLatin1(func->display_address("").c_str()), QString()); + code->setReadOnly(true); + endInsertRows(); + } + it = arch.value().map.insert(func, code); + } + createCommands(func, it.value()); + + return true; +} + +void FunctionPropertyManager::updateFunction(IFunction *func) +{ + if (value_ && value_->GetArchByFunction(func)) + update(); +} + +bool FunctionPropertyManager::removeFunction(IFunction *func) +{ + if (internalRemoveFunction(func)) { + update(); + return true; + } + return false; +} + +bool FunctionPropertyManager::internalRemoveFunction(IFunction *func) +{ + if (!value_) + return false; + + FunctionArch *func_arch = value_->GetArchByFunction(func); + if (!func_arch) + return false; + + QMap<IArchitecture *, ArchInfo>::iterator arch = map_.find(func_arch->arch()); + if (arch != map_.end()) { + QMap<IFunction *, StringProperty *>::iterator it = arch.value().map.find(func); + if (it != arch.value().map.end()) { + StringProperty *code = it.value(); + if (code == arch.value().code) { + beginRemoveRows(propertyToIndex(code), 0, code->childCount()); + code->clear(); + endRemoveRows(); + } else { + int index = code->parent()->children().indexOf(code); + beginRemoveRows(propertyToIndex(code->parent()), index, index + 1); + delete code; + endRemoveRows(); + } + arch.value().map.erase(it); + } + } + + return true; +} + +void FunctionPropertyManager::update() +{ + lock_ = true; + + name_->setValue(value_ ? QString::fromUtf8(value_->display_name().c_str()) : QString()); + + QString str; + if (value_) { + switch (value_->type()) { + case otAPIMarker: + case otMarker: + str = QString::fromUtf8(language[lsMarker].c_str()); + break; + case otString: + str = QString::fromUtf8(language[lsString].c_str()); + break; + case otCode: + str = QString::fromUtf8(language[lsFunction].c_str()); + break; + case otExport: + str = QString::fromUtf8(language[lsExport].c_str()); + break; + default: + str = QString::fromUtf8(language[lsUnknown].c_str()); + break; + } + } else { + str = ""; + } + type_->setValue(str); + address_->setValue(value_ ? QString::fromUtf8(value_->display_address().c_str()) : QString()); + + compilationType_->setValue(value_ && value_->need_compile() ? value_->compilation_type() : ctNone); + compilationType_->setDefaultValue(value_ ? value_->default_compilation_type() : ctNone); + lockToKey_->setReadOnly(value_ && (!value_->need_compile() || value_->compilation_type() == ctMutation)); + lockToKey_->setValue((value_ && !lockToKey_->readOnly()) ? (value_->compilation_options() & coLockToKey) != 0 : false); + + for (QMap<IArchitecture *, ArchInfo>::const_iterator arch = map_.begin(); arch != map_.end(); arch++) { + ArchInfo info = arch.value(); + if (info.code->childCount()) + info.code->setValue(QString::number(info.code->childCount()) + " " + QString::fromUtf8(language[lsItems].c_str())); + else + info.code->setValue(QString()); + for (QMap<IFunction *, StringProperty *>::const_iterator it = info.map.begin(); it != info.map.end(); it++) { + IFunction *func = it.key(); + StringProperty *code = it.value(); + + str.clear(); + if (func->type() != otUnknown) { + str = QString::number(func->count()) + " " + QString::fromUtf8(language[lsItems].c_str()); + QString hint; + if (func->ext_command_list()->count()) { + if (!hint.isEmpty()) + hint.append(", "); + hint.append(QString::fromUtf8(language[lsExternalAddress].c_str())).append(": ").append(QString::number(func->ext_command_list()->count())); + } + if (func->break_address()) { + if (!hint.isEmpty()) + hint.append(", "); + hint.append(QString::fromUtf8(language[lsBreakAddress].c_str())); + } + if (!hint.isEmpty()) + str.append(" (").append(hint).append(")"); + } + code->setValue(str); + } + } + + lock_ = false; +} + +void FunctionPropertyManager::compilationTypeChanged(CompilationType value) +{ + if (!value_ || lock_) + return; + + if (value == ctNone) { + value_->set_need_compile(false); + } else { + value_->set_need_compile(true); + value_->set_compilation_type(value); + } +} + +void FunctionPropertyManager::lockToKeyChanged(bool value) +{ + if (!value_ || lock_) + return; + + uint32_t options = value_->compilation_options(); + if (value) { + options |= coLockToKey; + } else { + options &= ~coLockToKey; + } + value_->set_compilation_options(options); +} + +ICommand *FunctionPropertyManager::indexToCommand(const QModelIndex &index) const +{ + if (!index.isValid()) + return NULL; + + Property *prop = indexToProperty(index); + if (prop) { + if (CommandProperty *c = qobject_cast<CommandProperty*>(prop)) + return c->value(); + } + return NULL; +} + +IFunction *FunctionPropertyManager::indexToFunction(const QModelIndex &index) const +{ + if (!index.isValid()) + return NULL; + + Property *prop = indexToProperty(index); + if (prop) { + for (QMap<IArchitecture *, ArchInfo>::const_iterator arch = map_.begin(); arch != map_.end(); arch++) { + for (QMap<IFunction *, StringProperty *>::const_iterator it = arch.value().map.begin(); it != arch.value().map.end(); it++) { + if (it.value() == prop) + return it.key(); + } + } + } + return NULL; +} + +QModelIndex FunctionPropertyManager::commandToIndex(ICommand *command) const +{ + for (QMap<IArchitecture *, ArchInfo>::const_iterator arch = map_.begin(); arch != map_.end(); arch++) { + ArchInfo info = arch.value(); + for (QMap<IFunction *, StringProperty *>::const_iterator it = info.map.begin(); it != info.map.end(); it++) { + QList<Property *> propList = it.value()->children(); + for (int j = 0; j < propList.size(); j++) { + Property *prop = propList[j]; + if (reinterpret_cast<CommandProperty*>(prop)->value() == command) + return propertyToIndex(prop); + } + } + } + return QModelIndex(); +} + +/** + * SectionPropertyManager + */ + +SectionPropertyManager::SectionPropertyManager(QObject *parent) + : PropertyManager(parent), value_(NULL) +{ + details_ = addGroupProperty(NULL, QString::fromUtf8(language[lsDetails].c_str())); + + name_ = addStringProperty(details_, QString::fromUtf8(language[lsName].c_str()), QString()); + name_->setReadOnly(true); + address_ = addStringProperty(details_, QString::fromUtf8(language[lsAddress].c_str()), QString()); + address_->setReadOnly(true); + virtual_size_ = addStringProperty(details_, QString::fromUtf8(language[lsSize].c_str()), QString()); + virtual_size_->setReadOnly(true); + physical_offset_ = addStringProperty(details_, QString::fromUtf8(language[lsRawAddress].c_str()), QString()); + physical_offset_->setReadOnly(true); + physical_size_ = addStringProperty(details_, QString::fromUtf8(language[lsRawSize].c_str()), QString()); + physical_size_->setReadOnly(true); + flags_ = addStringProperty(details_, QString::fromUtf8(language[lsFlags].c_str()), QString()); + flags_->setReadOnly(true); +} + +void SectionPropertyManager::localize() +{ + details_->setName(QString::fromUtf8(language[lsDetails].c_str())); + name_->setName(QString::fromUtf8(language[lsName].c_str())); + address_->setName(QString::fromUtf8(language[lsAddress].c_str())); + virtual_size_->setName(QString::fromUtf8(language[lsSize].c_str())); + physical_offset_->setName(QString::fromUtf8(language[lsRawAddress].c_str())); + physical_size_->setName(QString::fromUtf8(language[lsRawSize].c_str())); + flags_->setName(QString::fromUtf8(language[lsFlags].c_str())); +} + +void SectionPropertyManager::setValue(ISection *value) +{ + value_ = value; + + update(); +} + +void SectionPropertyManager::update() +{ + name_->setValue(value_ ? QString::fromUtf8(value_->name().c_str()) : QString()); + address_->setValue(value_ ? QString::fromUtf8(DisplayValue(value_->address_size(), value_->address()).c_str()) : QString()); + virtual_size_->setValue(value_ ? QString::fromUtf8(DisplayValue(value_->address_size(), value_->size()).c_str()) : QString()); + physical_offset_->setValue(value_ ? QString::fromUtf8(DisplayValue(osDWord, value_->physical_offset()).c_str()) : QString()); + physical_size_->setValue(value_ ? QString::fromUtf8(DisplayValue(osDWord, value_->physical_size()).c_str()) : QString()); + flags_->setValue(value_ ? QString::fromLatin1(DisplayValue(osDWord, value_->flags()).c_str()) : QString()); +} + +/** + * SegmentPropertyManager + */ + +SegmentPropertyManager::SegmentPropertyManager(QObject *parent) + : PropertyManager(parent), value_(NULL), lock_(false) +{ + options_ = addGroupProperty(NULL, QString::fromUtf8(language[lsOptions].c_str())); + excluded_from_memory_protection_ = addBoolProperty(options_, QString::fromUtf8(language[lsExcludedFromMemoryProtection].c_str()), false); + excluded_from_packing_ = addBoolProperty(options_, QString::fromUtf8(language[lsExcludedFromPacking].c_str()), false); + + details_ = addGroupProperty(NULL, QString::fromUtf8(language[lsDetails].c_str())); + name_ = addStringProperty(details_, QString::fromUtf8(language[lsName].c_str()), QString()); + name_->setReadOnly(true); + address_ = addStringProperty(details_, QString::fromUtf8(language[lsAddress].c_str()), QString()); + address_->setReadOnly(true); + virtual_size_ = addStringProperty(details_, QString::fromUtf8(language[lsSize].c_str()), QString()); + virtual_size_->setReadOnly(true); + physical_offset_ = addStringProperty(details_, QString::fromUtf8(language[lsRawAddress].c_str()), QString()); + physical_offset_->setReadOnly(true); + physical_size_ = addStringProperty(details_, QString::fromUtf8(language[lsRawSize].c_str()), QString()); + physical_size_->setReadOnly(true); + flags_ = addStringProperty(details_, QString::fromUtf8(language[lsFlags].c_str()), QString()); + flags_->setReadOnly(true); + flag_readable_ = addBoolProperty(flags_, "Readable", false); + flag_readable_->setReadOnly(true); + flag_writable_ = addBoolProperty(flags_, "Writable", false); + flag_writable_->setReadOnly(true); + flag_executable_ = addBoolProperty(flags_, "Executable", false); + flag_executable_->setReadOnly(true); + flag_shared_ = addBoolProperty(flags_, "Shared", false); + flag_shared_->setReadOnly(true); + flag_discardable_ = addBoolProperty(flags_, "Discardable", false); + flag_discardable_->setReadOnly(true); + flag_notpaged_ = addBoolProperty(flags_, "NotPaged", false); + flag_notpaged_->setReadOnly(true); + + connect(excluded_from_packing_, SIGNAL(valueChanged(bool)), this, SLOT(excludedFromPackingChanged(bool))); + connect(excluded_from_memory_protection_, SIGNAL(valueChanged(bool)), this, SLOT(excludedFromMemoryProtectionChanged(bool))); +} + +void SegmentPropertyManager::localize() +{ + options_->setName(QString::fromUtf8(language[lsOptions].c_str())); + excluded_from_packing_->setName(QString::fromUtf8(language[lsExcludedFromPacking].c_str())); + excluded_from_memory_protection_->setName(QString::fromUtf8(language[lsExcludedFromMemoryProtection].c_str())); + + details_->setName(QString::fromUtf8(language[lsDetails].c_str())); + name_->setName(QString::fromUtf8(language[lsName].c_str())); + virtual_size_->setName(QString::fromUtf8(language[lsSize].c_str())); + address_->setName(QString::fromUtf8(language[lsAddress].c_str())); + physical_offset_->setName(QString::fromUtf8(language[lsRawAddress].c_str())); + physical_size_->setName(QString::fromUtf8(language[lsRawSize].c_str())); + flags_->setName(QString::fromUtf8(language[lsFlags].c_str())); +} + +void SegmentPropertyManager::setValue(ISection *value) +{ + value_ = value; + update(); +} + +void SegmentPropertyManager::update() +{ + lock_ = true; + + excluded_from_packing_->setValue(value_ ? value_->excluded_from_packing() : false); + excluded_from_memory_protection_->setValue(value_ ? value_->excluded_from_memory_protection() : false); + name_->setValue(value_ ? QString::fromUtf8(value_->name().c_str()) : QString()); + address_->setValue(value_ ? QString::fromUtf8(DisplayValue(value_->address_size(), value_->address()).c_str()) : QString()); + virtual_size_->setValue(value_ ? QString::fromUtf8(DisplayValue(value_->address_size(), value_->size()).c_str()) : QString()); + physical_offset_->setValue(value_ ? QString::fromUtf8(DisplayValue(osDWord, value_->physical_offset()).c_str()) : QString()); + physical_size_->setValue(value_ ? QString::fromUtf8(DisplayValue(osDWord, value_->physical_size()).c_str()) : QString()); + flags_->setValue(value_ ? QString::fromLatin1(DisplayValue(osDWord, value_->flags()).c_str()) : QString()); + uint32_t memoryType = value_ ? value_->memory_type() : mtNone; + flag_readable_->setValue(memoryType & mtReadable); + flag_writable_->setValue(memoryType & mtWritable); + flag_executable_->setValue(memoryType & mtExecutable); + flag_shared_->setValue(memoryType & mtShared); + flag_notpaged_->setValue(memoryType & mtNotPaged); + flag_discardable_->setValue(memoryType & mtDiscardable); + + lock_ = false; +} + +void SegmentPropertyManager::excludedFromPackingChanged(bool value) +{ + if (!value_ || lock_) + return; + + value_->set_excluded_from_packing(value); +} + +void SegmentPropertyManager::excludedFromMemoryProtectionChanged(bool value) +{ + if (!value_ || lock_) + return; + + value_->set_excluded_from_memory_protection(value); +} + +/** + * LoadCommandPropertyManager + */ + +LoadCommandPropertyManager::LoadCommandPropertyManager(QObject *parent) + : PropertyManager(parent), value_(NULL) +{ + details_ = addGroupProperty(NULL, QString::fromUtf8(language[lsDetails].c_str())); + + name_ = addStringProperty(details_, QString::fromUtf8(language[lsName].c_str()), QString()); + name_->setReadOnly(true); + address_ = addStringProperty(details_, QString::fromUtf8(language[lsAddress].c_str()), QString()); + address_->setReadOnly(true); + size_ = addStringProperty(details_, QString::fromUtf8(language[lsSize].c_str()), QString()); + size_->setReadOnly(true); + segment_ = addStringProperty(details_, QString::fromUtf8(language[lsSegment].c_str()), QString()); + segment_->setReadOnly(true); +} + +void LoadCommandPropertyManager::localize() +{ + details_->setName(QString::fromUtf8(language[lsDetails].c_str())); + name_->setName(QString::fromUtf8(language[lsName].c_str())); + address_->setName(QString::fromUtf8(language[lsAddress].c_str())); + size_->setName(QString::fromUtf8(language[lsSize].c_str())); + segment_->setName(QString::fromUtf8(language[lsSegment].c_str())); +} + +void LoadCommandPropertyManager::setValue(ILoadCommand *value) +{ + value_ = value; + + update(); +} + +void LoadCommandPropertyManager::update() +{ + name_->setValue(value_ ? QString::fromUtf8(value_->name().c_str()) : QString()); + address_->setValue(value_ ? QString::fromUtf8(DisplayValue(value_->address_size(), value_->address()).c_str()) : QString()); + size_->setValue(value_ ? QString::fromUtf8(DisplayValue(osDWord, value_->size()).c_str()) : QString()); + + ISection *segment = NULL; + if (value_) { + IArchitecture *file = value_->owner()->owner(); + segment = file->segment_list()->GetSectionByAddress(value_->address()); + if (file->owner()->format_name() == "ELF") { + switch (value_->type()) { + case DT_NEEDED: + case DT_PLTRELSZ: + case DT_RELASZ: + case DT_RELAENT: + case DT_STRSZ: + case DT_SYMENT: + case DT_SONAME: + case DT_RPATH: + case DT_RELSZ: + case DT_RELENT: + case DT_PLTREL: + case DT_DEBUG: + case DT_BIND_NOW: + case DT_INIT_ARRAYSZ: + case DT_FINI_ARRAYSZ: + case DT_RUNPATH: + case DT_FLAGS: + case DT_PREINIT_ARRAYSZ: + case DT_GNU_HASH: + case DT_RELACOUNT: + case DT_RELCOUNT: + case DT_FLAGS_1: + case DT_VERDEFNUM: + case DT_VERNEEDNUM: + segment = NULL; + break; + } + } + } + segment_->setValue(segment ? QString::fromUtf8(segment->name().c_str()) : QString()); +} + +/** + * ImportPropertyManager + */ + +ImportPropertyManager::ImportPropertyManager(QObject *parent) + : PropertyManager(parent), value_(NULL), func_(NULL) +{ + details_ = addGroupProperty(NULL, QString::fromUtf8(language[lsDetails].c_str())); + + name_ = addStringProperty(details_, QString::fromUtf8(language[lsName].c_str()), QString()); + name_->setReadOnly(true); + address_ = addStringProperty(details_, QString::fromUtf8(language[lsAddress].c_str()), QString()); + address_->setReadOnly(true); + references_ = addStringProperty(details_, QString::fromUtf8(language[lsReferences].c_str()), QString()); + references_->setReadOnly(true); +} + +ImportPropertyManager::~ImportPropertyManager() +{ + delete func_; +} + +void ImportPropertyManager::localize() +{ + details_->setName(QString::fromUtf8(language[lsDetails].c_str())); + name_->setName(QString::fromUtf8(language[lsName].c_str())); + address_->setName(QString::fromUtf8(language[lsAddress].c_str())); + references_->setName(QString::fromUtf8(language[lsReferences].c_str())); + references_->setValue(value_ ? QString::number(references_->childCount()) + " " + QString::fromUtf8(language[lsItems].c_str()) : QString()); +} + +QVariant ImportPropertyManager::data(const QModelIndex &index, int role) const +{ + Property *prop = indexToProperty(index); + if (role == Qt::FontRole) { + if (prop && prop->parent() == references_) + return QFont(MONOSPACE_FONT_FAMILY); + } + + return PropertyManager::data(index, role); +} + +void ImportPropertyManager::setValue(IImportFunction *value) +{ + value_ = value; + delete func_; + func_ = NULL; + + if (references_->childCount()) { + beginRemoveRows(propertyToIndex(references_), 0, references_->childCount()); + references_->clear(); + endRemoveRows(); + } + + if (value_) { + IArchitecture *file = value_->owner()->owner()->owner(); + func_ = file->function_list()->CreateFunction(); + ReferenceList *reference_list = value_->map_function()->reference_list(); + for (size_t i = 0; i < reference_list->count(); i++) { + Reference *reference = reference_list->item(i); + if (file->AddressSeek(reference->address())) + func_->ParseCommand(*file, reference->address()); + } + beginInsertRows(propertyToIndex(references_), 0, (int)reference_list->count()); + for (size_t i = 0; i < func_->count(); i++) { + Property *prop = addCommandProperty(references_, func_->item(i)); + prop->setReadOnly(true); + } + endInsertRows(); + } + + update(); +} + +void ImportPropertyManager::update() +{ + name_->setValue(value_ ? QString::fromUtf8(value_->name().c_str()) : QString()); + address_->setValue(value_ ? QString::fromUtf8(DisplayValue(value_->address_size(), value_->address()).c_str()) : QString()); + references_->setValue(value_ ? QString::number(references_->childCount()) + " " + QString::fromUtf8(language[lsItems].c_str()) : QString()); +} + +/** + * ExportPropertyManager + */ + +ExportPropertyManager::ExportPropertyManager(QObject *parent) + : PropertyManager(parent), value_(NULL) +{ + details_ = addGroupProperty(NULL, QString::fromUtf8(language[lsDetails].c_str())); + + name_ = addStringProperty(details_, QString::fromUtf8(language[lsName].c_str()), QString()); + name_->setReadOnly(true); + forwarded_ = addStringProperty(details_, "Forwarded", QString()); + forwarded_->setReadOnly(true); + address_ = addStringProperty(details_, QString::fromUtf8(language[lsAddress].c_str()), QString()); + address_->setReadOnly(true); +} + +void ExportPropertyManager::localize() +{ + details_->setName(QString::fromUtf8(language[lsDetails].c_str())); + name_->setName(QString::fromUtf8(language[lsName].c_str())); + address_->setName(QString::fromUtf8(language[lsAddress].c_str())); +} + +void ExportPropertyManager::setValue(IExport *value) +{ + value_ = value; + + update(); +} + +void ExportPropertyManager::update() +{ + name_->setValue(value_ ? QString::fromUtf8(value_->name().c_str()) : QString()); + forwarded_->setValue(value_ ? QString::fromUtf8(value_->forwarded_name().c_str()) : QString()); + address_->setValue(value_ ? QString::fromUtf8(DisplayValue(value_->address_size(), value_->address()).c_str()) : QString()); +} + +/** + * ResourcePropertyManager + */ + +ResourcePropertyManager::ResourcePropertyManager(QObject *parent) + : PropertyManager(parent), value_(NULL), lock_(false) +{ + options_ = addGroupProperty(NULL, QString::fromUtf8(language[lsPacking].c_str())); + excluded_from_packing_ = addBoolProperty(options_, QString::fromUtf8(language[lsExcludedFromPacking].c_str()), false); + + details_ = addGroupProperty(NULL, QString::fromUtf8(language[lsDetails].c_str())); + name_ = addStringProperty(details_, QString::fromUtf8(language[lsName].c_str()), QString()); + name_->setReadOnly(true); + address_ = addStringProperty(details_, QString::fromUtf8(language[lsAddress].c_str()), QString()); + address_->setReadOnly(true); + size_ = addStringProperty(details_, QString::fromUtf8(language[lsSize].c_str()), QString()); + size_->setReadOnly(true); + + connect(excluded_from_packing_, SIGNAL(valueChanged(bool)), this, SLOT(excludedFromPackingChanged(bool))); +} + +void ResourcePropertyManager::localize() +{ + options_->setName(QString::fromUtf8(language[lsOptions].c_str())); + excluded_from_packing_->setName(QString::fromUtf8(language[lsExcludedFromPacking].c_str())); + + details_->setName(QString::fromUtf8(language[lsDetails].c_str())); + name_->setName(QString::fromUtf8(language[lsName].c_str())); + address_->setName(QString::fromUtf8(language[lsAddress].c_str())); + size_->setName(QString::fromUtf8(language[lsSize].c_str())); +} + +void ResourcePropertyManager::setValue(IResource *value) +{ + value_ = value; + + update(); +} + +void ResourcePropertyManager::update() +{ + lock_ = true; + + name_->setValue(value_ ? QString::fromUtf8(value_->name().c_str()) : QString()); + address_->setValue(value_ ? QString::fromUtf8(DisplayValue(value_->address_size(), value_->address()).c_str()) : QString()); + size_->setValue(value_ ? QString::fromUtf8(DisplayValue(osDWord, value_->size()).c_str()) : QString()); + excluded_from_packing_->setValue(value_ ? value_->excluded_from_packing() : false); + + lock_ = false; +} + +void ResourcePropertyManager::excludedFromPackingChanged(bool value) +{ + if (!value_ || lock_) + return; + + value_->set_excluded_from_packing(value); +} + +/** + * CorePropertyManager + */ + +CorePropertyManager::CorePropertyManager(QObject *parent) + : PropertyManager(parent), core_(NULL), lock_(false) +{ + file_ = addGroupProperty(NULL, QString::fromUtf8(language[lsFile].c_str())); + memoryProtection_ = addBoolProperty(file_, QString::fromUtf8(language[lsMemoryProtection].c_str()), false); + connect(memoryProtection_, SIGNAL(valueChanged(bool)), this, SLOT(memoryProtectionChanged(bool))); + importProtection_ = addBoolProperty(file_, QString::fromUtf8(language[lsImportProtection].c_str()), false); + connect(importProtection_, SIGNAL(valueChanged(bool)), this, SLOT(importProtectionChanged(bool))); + resourceProtection_ = addBoolProperty(file_, QString::fromUtf8(language[lsResourceProtection].c_str()), false); + connect(resourceProtection_, SIGNAL(valueChanged(bool)), this, SLOT(resourceProtectionChanged(bool))); + packOutputFile_ = addBoolProperty(file_, QString::fromUtf8(language[lsPackOutputFile].c_str()), false); + connect(packOutputFile_, SIGNAL(valueChanged(bool)), this, SLOT(packOutputFileChanged(bool))); + outputFileName_ = addFileNameProperty(file_, QString::fromUtf8(language[lsOutputFile].c_str()), QString("%1 (" +#ifdef VMP_GNU + "*.dylib *.exe *.dll *.bpl *.ocx *.sys *.scr *.so);;%2 (*)" +#else + "*.exe *.dll *.bpl *.ocx *.sys *.scr *.dylib *.so);;%2 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsExecutableFiles].c_str())).arg(QString::fromUtf8(language[lsAllFiles].c_str())), QString(), true); + connect(outputFileName_, SIGNAL(valueChanged(const QString &)), this, SLOT(outputFileChanged(const QString &))); + + detection_ = addGroupProperty(NULL, QString::fromUtf8(language[lsDetection].c_str())); + detectionDebugger_ = addEnumProperty(detection_, QString::fromUtf8(language[lsDebugger].c_str()), QStringList() << QString::fromUtf8(language[lsNo].c_str()) << "User-mode" << "User-mode + Kernel-mode", 0); + connect(detectionDebugger_, SIGNAL(valueChanged(int)), this, SLOT(detectionDebuggerChanged(int))); + detectionVMTools_ = addBoolProperty(detection_, QString::fromUtf8(language[lsVirtualizationTools].c_str()), false); + connect(detectionVMTools_, SIGNAL(valueChanged(bool)), this, SLOT(detectioncpVMToolsChanged(bool))); + + additional_ = addGroupProperty(NULL, QString::fromUtf8(language[lsAdditional].c_str())); + vmSectionName_ = addStringProperty(additional_, QString::fromUtf8(language[lsVMSegments].c_str()), QString()); + connect(vmSectionName_, SIGNAL(valueChanged(const QString &)), this, SLOT(vmSectionNameChanged(const QString &))); + stripDebugInfo_ = addBoolProperty(additional_, QString::fromUtf8(language[lsStripDebugInfo].c_str()), false); + connect(stripDebugInfo_, SIGNAL(valueChanged(bool)), this, SLOT(stripDebugInfoChanged(bool))); + stripRelocations_ = addBoolProperty(additional_, QString::fromUtf8(language[lsStripRelocations].c_str()), false); + connect(stripRelocations_, SIGNAL(valueChanged(bool)), this, SLOT(stripRelocationsChanged(bool))); +#ifndef LITE + watermarkName_ = addWatermarkProperty(additional_, QString::fromUtf8(language[lsWatermark].c_str()), QString()); + connect(watermarkName_, SIGNAL(valueChanged(const QString &)), this, SLOT(watermarkNameChanged(const QString &))); +#ifdef ULTIMATE + hwid_ = addStringProperty(additional_, QString::fromUtf8(language[lsLockToHWID].c_str()), QString()); + connect(hwid_, SIGNAL(valueChanged(const QString &)), this, SLOT(hwidChanged(const QString &))); +#ifdef DEMO + if (true) +#else + if (VMProtectGetSerialNumberState() != SERIAL_STATE_SUCCESS) +#endif + { + size_t size = VMProtectGetCurrentHWID(NULL, 0); + char *hwid = new char[size]; + VMProtectGetCurrentHWID(hwid, (int)size); + hwid_->setValue(QString().fromLatin1(hwid)); + hwid_->setReadOnly(true); + delete [] hwid; + } + +#endif + + messages_ = addGroupProperty(NULL, QString::fromUtf8(language[lsMessages].c_str())); + messageDebuggerFound_ = addStringListProperty(messages_, QString::fromUtf8(language[lsDebuggerFound].c_str()), QString()); + connect(messageDebuggerFound_, SIGNAL(valueChanged(const QString &)), this, SLOT(messageDebuggerFoundChanged(const QString &))); + messageVMToolsFound_ = addStringListProperty(messages_, QString::fromUtf8(language[lsVirtualizationToolsFound].c_str()), QString()); + connect(messageVMToolsFound_, SIGNAL(valueChanged(const QString &)), this, SLOT(messageVMToolsFoundChanged(const QString &))); + messageFileCorrupted_ = addStringListProperty(messages_, QString::fromUtf8(language[lsFileCorrupted].c_str()), QString()); + connect(messageFileCorrupted_, SIGNAL(valueChanged(const QString &)), this, SLOT(messageFileCorruptedChanged(const QString &))); + messageSerialNumberRequired_ = addStringListProperty(messages_, QString::fromUtf8(language[lsSerialNumberRequired].c_str()), QString()); + connect(messageSerialNumberRequired_, SIGNAL(valueChanged(const QString &)), this, SLOT(messageSerialNumberRequiredChanged(const QString &))); + messageHWIDMismatched_ = addStringListProperty(messages_, QString::fromUtf8(language[lsHWIDMismatched].c_str()), QString()); + connect(messageHWIDMismatched_, SIGNAL(valueChanged(const QString &)), this, SLOT(messageHWIDMismatchedChanged(const QString &))); +#endif + +#ifdef ULTIMATE + licensingParameters_ = addGroupProperty(NULL, QString::fromUtf8(language[lsLicensingParameters].c_str())); + licenseDataFileName_ = addFileNameProperty(licensingParameters_, QString::fromUtf8(language[lsFileName].c_str()), QString("%1 (*.vmp);;" +#ifdef VMP_GNU + " %2 (*)" +#else + " %2 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsProjectFiles].c_str())).arg(QString::fromUtf8(language[lsAllFiles].c_str())), QString()); + connect(licenseDataFileName_, SIGNAL(valueChanged(const QString &)), this, SLOT(licenseDataFileNameChanged(const QString &))); + keyPairAlgorithm_ = addStringProperty(licensingParameters_, QString::fromUtf8(language[lsKeyPairAlgorithm].c_str()), QString()); + keyPairAlgorithm_->setReadOnly(true); + activationServer_ = addStringProperty(licensingParameters_, QString::fromUtf8(language[lsActivationServer].c_str()), QString()); + connect(activationServer_, SIGNAL(valueChanged(const QString &)), this, SLOT(activationServerChanged(const QString &))); +#endif +} + +void CorePropertyManager::localize() +{ + file_->setName(QString::fromUtf8(language[lsFile].c_str())); + memoryProtection_->setName(QString::fromUtf8(language[lsMemoryProtection].c_str())); + memoryProtection_->setToolTip(QString::fromUtf8(language[lsMemoryProtectionHelp].c_str())); + importProtection_->setName(QString::fromUtf8(language[lsImportProtection].c_str())); + importProtection_->setToolTip(QString::fromUtf8(language[lsImportProtectionHelp].c_str())); + resourceProtection_->setName(QString::fromUtf8(language[lsResourceProtection].c_str())); + resourceProtection_->setToolTip(QString::fromUtf8(language[lsResourceProtectionHelp].c_str())); + packOutputFile_->setName(QString::fromUtf8(language[lsPackOutputFile].c_str())); + packOutputFile_->setToolTip(QString::fromUtf8(language[lsPackOutputFileHelp].c_str())); +#ifndef LITE + watermarkName_->setName(QString::fromUtf8(language[lsWatermark].c_str())); + watermarkName_->setToolTip(QString::fromUtf8(language[lsWatermarkHelp].c_str())); +#endif + outputFileName_->setName(QString::fromUtf8(language[lsOutputFile].c_str())); + outputFileName_->setFilter(QString("%1 (" +#ifdef VMP_GNU + "*.dylib *.exe *.dll *.bpl *.ocx *.sys *.scr *.so);;%2 (*)" +#else + "*.exe *.dll *.bpl *.ocx *.sys *.scr *.dylib *.so);;%2 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsExecutableFiles].c_str())).arg(QString::fromUtf8(language[lsAllFiles].c_str()))); + + detection_->setName(QString::fromUtf8(language[lsDetection].c_str())); + detectionDebugger_->setName(QString::fromUtf8(language[lsDebugger].c_str())); + detectionDebugger_->setToolTip(QString::fromUtf8(language[lsDebuggerHelp].c_str())); + detectionDebugger_->setText(0, QString::fromUtf8(language[lsNo].c_str())); + detectionVMTools_->setName(QString::fromUtf8(language[lsVirtualizationTools].c_str())); + detectionVMTools_->setToolTip(QString::fromUtf8(language[lsVirtualizationToolsHelp].c_str())); + +#ifndef LITE + messages_->setName(QString::fromUtf8(language[lsMessages].c_str())); + messageDebuggerFound_->setName(QString::fromUtf8(language[lsDebuggerFound].c_str())); + messageVMToolsFound_->setName(QString::fromUtf8(language[lsVirtualizationToolsFound].c_str())); + messageFileCorrupted_->setName(QString::fromUtf8(language[lsFileCorrupted].c_str())); + messageSerialNumberRequired_->setName(QString::fromUtf8(language[lsSerialNumberRequired].c_str())); + messageHWIDMismatched_->setName(QString::fromUtf8(language[lsHWIDMismatched].c_str())); +#endif + + additional_->setName(QString::fromUtf8(language[lsAdditional].c_str())); + vmSectionName_->setName(QString::fromUtf8(language[lsVMSegments].c_str())); + vmSectionName_->setToolTip(QString::fromUtf8(language[lsVMSegmentsHelp].c_str())); + stripDebugInfo_->setName(QString::fromUtf8(language[lsStripDebugInfo].c_str())); + stripRelocations_->setName(QString::fromUtf8(language[lsStripRelocations].c_str())); + +#ifdef ULTIMATE + hwid_->setName(QString::fromUtf8(language[lsLockToHWID].c_str())); + licensingParameters_->setName(QString::fromUtf8(language[lsLicensingParameters].c_str())); + licensingParameters_->setToolTip(QString::fromUtf8(language[lsLicensingParametersHelp].c_str())); + licenseDataFileName_->setName(QString::fromUtf8(language[lsFileName].c_str())); + licenseDataFileName_->setFilter(QString( +#ifdef VMP_GNU + "%1 (*.vmp);;%2 (*)" +#else + "%1 (*.vmp);;%2 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsProjectFiles].c_str())).arg(QString::fromUtf8(language[lsAllFiles].c_str()))); + keyPairAlgorithm_->setName(QString::fromUtf8(language[lsKeyPairAlgorithm].c_str())); + if (keyPairAlgorithm_->childCount()) { + QList<Property *> keyProps = keyPairAlgorithm_->children(); + keyProps[0]->setName(QString::fromUtf8(language[lsPublicExp].c_str())); + keyProps[1]->setName(QString::fromUtf8(language[lsPrivateExp].c_str())); + keyProps[2]->setName(QString::fromUtf8(language[lsModulus].c_str())); + keyProps[3]->setName(QString::fromUtf8(language[lsProductCode].c_str())); + } else { + keyPairAlgorithm_->setValue(QString::fromUtf8(language[lsNone].c_str())); + } + activationServer_->setName(QString::fromUtf8(language[lsActivationServer].c_str())); +#endif +} + +void CorePropertyManager::setCore(Core *core) +{ + core_ = core; + if (core_ && core_->input_file()) { + uint32_t disable_options = core_->input_file()->disable_options(); + stripRelocations_->setReadOnly(disable_options & cpStripFixups); + importProtection_->setReadOnly(disable_options & cpImportProtection); + resourceProtection_->setReadOnly(disable_options & cpResourceProtection); + packOutputFile_->setReadOnly(disable_options & cpPack); + } + outputFileName_->setRelativePath(core ? QString::fromUtf8(core->project_path().c_str()) : QString()); +#ifdef ULTIMATE + licenseDataFileName_->setRelativePath(core ? QString::fromUtf8(core->project_path().c_str()) : QString()); +#endif + update(); +} + +QVariant CorePropertyManager::data(const QModelIndex &index, int role) const +{ + if (role == Qt::FontRole) { +#ifdef ULTIMATE + Property *prop = indexToProperty(index); + if (prop && prop->parent() == keyPairAlgorithm_ && index.column() == 1) + return QFont(MONOSPACE_FONT_FAMILY); +#endif + } + + return PropertyManager::data(index, role); +} + +void CorePropertyManager::update() +{ + lock_ = true; + + uint32_t options = core_ ? core_->options() : 0; + if (core_ && core_->input_file()) + options &= ~core_->input_file()->disable_options(); + memoryProtection_->setValue(core_ ? (options & cpMemoryProtection) != 0 : false); + importProtection_->setValue(core_ ? (options & cpImportProtection) != 0 : false); + resourceProtection_->setValue(core_ ? (options & cpResourceProtection) != 0 : false); + packOutputFile_->setValue(core_ ? (options & cpPack) != 0 : false); +#ifndef LITE + watermarkName_->setValue(core_ ? QString::fromUtf8(core_->watermark_name().c_str()) : QString()); +#endif + outputFileName_->setValue(core_ ? QString::fromUtf8(core_->output_file_name().c_str()) : QString()); + int i; + switch (options & (cpCheckDebugger | cpCheckKernelDebugger)) { + case cpCheckDebugger: + i = 1; + break; + case cpCheckDebugger | cpCheckKernelDebugger: + i = 2; + break; + default: + i = 0; + break; + } + detectionDebugger_->setValue(core_ ? i : 0); + detectionVMTools_->setValue(core_ ? (options & cpCheckVirtualMachine) != 0 : false); +#ifndef LITE + messageDebuggerFound_->setValue(core_ ? QString::fromUtf8(core_->message(MESSAGE_DEBUGGER_FOUND).c_str()) : QString()); + messageVMToolsFound_->setValue(core_ ? QString::fromUtf8(core_->message(MESSAGE_VIRTUAL_MACHINE_FOUND).c_str()) : QString()); + messageFileCorrupted_->setValue(core_ ? QString::fromUtf8(core_->message(MESSAGE_FILE_CORRUPTED).c_str()) : QString()); + messageSerialNumberRequired_->setValue(core_ ? QString::fromUtf8(core_->message(MESSAGE_SERIAL_NUMBER_REQUIRED).c_str()) : QString()); + messageHWIDMismatched_->setValue(core_ ? QString::fromUtf8(core_->message(MESSAGE_HWID_MISMATCHED).c_str()) : QString()); +#endif + + vmSectionName_->setValue(core_ ? QString::fromUtf8(core_->vm_section_name().c_str()) : QString()); + stripDebugInfo_->setValue(core_ ? (options & cpStripDebugInfo) != 0 : false); + stripRelocations_->setValue(core_ ? (options & cpStripFixups) != 0 : false); + +#ifdef ULTIMATE + if (!hwid_->readOnly()) + hwid_->setValue(core_ ? QString::fromUtf8(core_->hwid().c_str()) : QString()); + licenseDataFileName_->setValue(core_ ? QString::fromUtf8(core_->license_data_file_name().c_str()) : QString()); + QString str; + if (core_) { + LicensingManager *licensingManager = core_->licensing_manager(); + switch (licensingManager->algorithm()) { + case alNone: + str = QString::fromUtf8(language[lsNone].c_str()); + if (keyPairAlgorithm_->childCount()) { + beginRemoveRows(propertyToIndex(keyPairAlgorithm_), 0, keyPairAlgorithm_->childCount()); + keyPairAlgorithm_->clear(); + endRemoveRows(); + } + break; + case alRSA: + str = QString("RSA %1").arg(licensingManager->bits()); + if (!keyPairAlgorithm_->childCount()) { + beginInsertRows(propertyToIndex(keyPairAlgorithm_), 0, 4); + + StringProperty *prop = addStringProperty(keyPairAlgorithm_, QString::fromUtf8(language[lsPublicExp].c_str()), QString()); + prop->setReadOnly(true); + + prop = addStringProperty(keyPairAlgorithm_, QString::fromUtf8(language[lsPrivateExp].c_str()), QString()); + prop->setReadOnly(true); + + prop = addStringProperty(keyPairAlgorithm_, QString::fromUtf8(language[lsModulus].c_str()), QString()); + prop->setReadOnly(true); + + prop = addStringProperty(keyPairAlgorithm_, QString::fromUtf8(language[lsProductCode].c_str()), QString()); + prop->setReadOnly(true); + + endInsertRows(); + } + QList<Property *> list = keyPairAlgorithm_->children(); + reinterpret_cast<StringProperty *>(list.at(0))->setValue(QString::fromLatin1(formatVector(licensingManager->public_exp()).c_str())); + reinterpret_cast<StringProperty *>(list.at(1))->setValue(QString::fromLatin1(formatVector(licensingManager->private_exp()).c_str())); + reinterpret_cast<StringProperty *>(list.at(2))->setValue(QString::fromLatin1(formatVector(licensingManager->modulus()).c_str())); + uint64_t product_code = licensingManager->product_code(); + reinterpret_cast<StringProperty *>(list.at(3))->setValue(QByteArray(reinterpret_cast<char *>(&product_code), sizeof(product_code)).toBase64()); + break; + } + } + keyPairAlgorithm_->setValue(str); + activationServer_->setValue(core_ ? QString::fromUtf8(core_->activation_server().c_str()) : QString()); +#endif + + lock_ = false; +} + +void CorePropertyManager::memoryProtectionChanged(bool value) +{ + if (!core_ || lock_) + return; + + if (value) { + core_->include_option(cpMemoryProtection); + } else { + core_->exclude_option(cpMemoryProtection); + } +} + +void CorePropertyManager::importProtectionChanged(bool value) +{ + if (!core_ || lock_) + return; + + if (value) { + core_->include_option(cpImportProtection); + } else { + core_->exclude_option(cpImportProtection); + } +} + +void CorePropertyManager::resourceProtectionChanged(bool value) +{ + if (!core_ || lock_) + return; + + if (value) { + core_->include_option(cpResourceProtection); + } else { + core_->exclude_option(cpResourceProtection); + } +} + +void CorePropertyManager::packOutputFileChanged(bool value) +{ + if (!core_ || lock_) + return; + + if (value) { + core_->include_option(cpPack); + } else { + core_->exclude_option(cpPack); + } +} + +void CorePropertyManager::watermarkNameChanged(const QString &value) +{ + if (!core_ || lock_) + return; + + core_->set_watermark_name(value.toUtf8().constData()); +} + +void CorePropertyManager::outputFileChanged(const QString &value) +{ + if (!core_ || lock_) + return; + + core_->set_output_file_name(value.toUtf8().constData()); +} + +void CorePropertyManager::detectionDebuggerChanged(int value) +{ + if (!core_ || lock_) + return; + + if (value) + core_->include_option(cpCheckDebugger); + else + core_->exclude_option(cpCheckDebugger); + if (value == 2) + core_->include_option(cpCheckKernelDebugger); + else + core_->exclude_option(cpCheckKernelDebugger); +} + +void CorePropertyManager::detectioncpVMToolsChanged(bool value) +{ + if (!core_ || lock_) + return; + + if (value) { + core_->include_option(cpCheckVirtualMachine); + } else { + core_->exclude_option(cpCheckVirtualMachine); + } +} + +void CorePropertyManager::vmSectionNameChanged(const QString &value) +{ + if (!core_ || lock_) + return; + + core_->set_vm_section_name(value.toUtf8().constData()); +} + +void CorePropertyManager::stripDebugInfoChanged(bool value) +{ + if (!core_ || lock_) + return; + + if (value) { + core_->include_option(cpStripDebugInfo); + } else { + core_->exclude_option(cpStripDebugInfo); + } +} + +void CorePropertyManager::stripRelocationsChanged(bool value) +{ + if (!core_ || lock_) + return; + + if (value) { + core_->include_option(cpStripFixups); + } else { + core_->exclude_option(cpStripFixups); + } +} + +void CorePropertyManager::debugModeChanged(bool value) +{ + if (!core_ || lock_) + return; + + if (value) { + core_->include_option(cpDebugMode); + } else { + core_->exclude_option(cpDebugMode); + } +} + +void CorePropertyManager::messageDebuggerFoundChanged(const QString &value) +{ + if (!core_ || lock_) + return; + + core_->set_message(MESSAGE_DEBUGGER_FOUND, value.toUtf8().constData()); +} + +void CorePropertyManager::messageVMToolsFoundChanged(const QString &value) +{ + if (!core_ || lock_) + return; + + core_->set_message(MESSAGE_VIRTUAL_MACHINE_FOUND, value.toUtf8().constData()); +} + +void CorePropertyManager::messageFileCorruptedChanged(const QString &value) +{ + if (!core_ || lock_) + return; + + core_->set_message(MESSAGE_FILE_CORRUPTED, value.toUtf8().constData()); +} + +void CorePropertyManager::messageSerialNumberRequiredChanged(const QString &value) +{ + if (!core_ || lock_) + return; + + core_->set_message(MESSAGE_SERIAL_NUMBER_REQUIRED, value.toUtf8().constData()); +} + +void CorePropertyManager::messageHWIDMismatchedChanged(const QString &value) +{ + if (!core_ || lock_) + return; + + core_->set_message(MESSAGE_HWID_MISMATCHED, value.toUtf8().constData()); +} + +#ifdef ULTIMATE +void CorePropertyManager::hwidChanged(const QString &value) +{ + if (!core_ || lock_) + return; + + core_->set_hwid(value.toUtf8().constData()); +} + +void CorePropertyManager::licenseDataFileNameChanged(const QString &value) +{ + if (!core_ || lock_) + return; + + core_->set_license_data_file_name(value.toUtf8().constData()); +} + +void CorePropertyManager::activationServerChanged(const QString &value) +{ + if (!core_ || lock_) + return; + + core_->set_activation_server(value.toUtf8().constData()); +} +#else +void CorePropertyManager::hwidChanged(const QString &) {} +void CorePropertyManager::licenseDataFileNameChanged(const QString &) {} +void CorePropertyManager::activationServerChanged(const QString &) {} +#endif + +/** + * WatermarkPropertyManager + */ + +WatermarkPropertyManager::WatermarkPropertyManager(QObject *parent) + : PropertyManager(parent), lock_(false), watermark_(NULL) +{ + GroupProperty *details_ = addGroupProperty(NULL, QString::fromUtf8(language[lsDetails].c_str())); + name_ = addStringProperty(details_, QString::fromUtf8(language[lsName].c_str()), QString()); + blocked_ = addBoolProperty(details_, QString::fromUtf8(language[lsBlocked].c_str()), false); + useCount_ = addStringProperty(details_, QString::fromUtf8(language[lsUsageCount].c_str()), QString()); + useCount_->setReadOnly(true); + + connect(name_, SIGNAL(valueChanged(const QString &)), this, SLOT(nameChanged(const QString &))); + connect(blocked_, SIGNAL(valueChanged(bool)), this, SLOT(blockedChanged(bool))); +} + +void WatermarkPropertyManager::setWatermark(Watermark *watermark) +{ + watermark_ = watermark; + update(); +} + +void WatermarkPropertyManager::update() +{ + lock_ = true; + + name_->setValue(watermark_ ? QString::fromUtf8(watermark_->name().c_str()) : QString()); + blocked_->setValue(watermark_ ? !watermark_->enabled() : false); + useCount_->setValue(watermark_ ? QString::number(watermark_->use_count()) : QString()); + + lock_ = false; +} + +void WatermarkPropertyManager::nameChanged(const QString &value) +{ + if (!watermark_ || lock_) + return; + + watermark_->set_name(value.toUtf8().constData()); +} + +void WatermarkPropertyManager::blockedChanged(bool value) +{ + if (!watermark_ || lock_) + return; + + watermark_->set_enabled(!value); +} + +/** + * AddressCalculator + */ + +AddressCalculator::AddressCalculator(QObject *parent) + : PropertyManager(parent), lock_(false), file_(NULL) +{ + address_ = addStringProperty(NULL, QString::fromUtf8(language[lsAddress].c_str()), QString()); + offset_ = addStringProperty(NULL, QString::fromUtf8(language[lsRawAddress].c_str()), QString()); + segment_ = addEnumProperty(NULL, QString::fromUtf8(language[lsSegment].c_str()), QStringList(), -1); + + connect(address_, SIGNAL(valueChanged(const QString &)), this, SLOT(addressChanged(const QString &))); + connect(offset_, SIGNAL(valueChanged(const QString &)), this, SLOT(offsetChanged(const QString &))); + connect(segment_, SIGNAL(valueChanged(int)), this, SLOT(segmentChanged(int))); +} + +void AddressCalculator::localize() +{ + address_->setName(QString::fromUtf8(language[lsAddress].c_str())); + offset_->setName(QString::fromUtf8(language[lsRawAddress].c_str())); + segment_->setName(QString::fromUtf8(language[lsSegment].c_str())); +} + +void AddressCalculator::setValue(IArchitecture *file) +{ + if (file_ == file) + return; + + file_ = file; + + lock_ = true; + address_->setValue(QString()); + offset_->setValue(QString()); + QStringList segments; + if (file_) { + for (size_t i = 0; i < file_->segment_list()->count(); i++) { + segments.push_back(QString::fromUtf8(file_->segment_list()->item(i)->name().c_str())); + } + } + segment_->setValue(-1); + segment_->setItems(segments); + lock_ = false; +} + +void AddressCalculator::addressChanged(const QString &value) +{ + if (!file_ || lock_) + return; + + lock_ = true; + bool is_valid; + ISection *segment = NULL; + uint64_t address = value.toULongLong(&is_valid, 16); + if (is_valid) + segment = file_->segment_list()->GetSectionByAddress(address); + offset_->setValue(segment ? QString::fromUtf8(DisplayValue(osDWord, segment->physical_offset() + address - segment->address()).c_str()) : QString()); + segment_->setValue(segment ? (int)file_->segment_list()->IndexOf(segment) : -1); + lock_ = false; +} + +void AddressCalculator::offsetChanged(const QString &value) +{ + if (!file_ || lock_) + return; + + lock_ = true; + bool is_valid; + ISection *segment = NULL; + uint64_t offset = value.toULongLong(&is_valid, 16); + if (is_valid) + segment = file_->segment_list()->GetSectionByOffset(offset); + uint64_t address = segment ? segment->address() + offset - segment->physical_offset() : 0; + address_->setValue(segment ? QString::fromUtf8(DisplayValue(file_->cpu_address_size(), address).c_str()) : QString()); + segment_->setValue(segment ? (int)file_->segment_list()->IndexOf(segment) : -1); + lock_ = false; +} + +void AddressCalculator::segmentChanged(int value) +{ + if (!file_ || lock_) + return; + + lock_ = true; + ISection *segment = file_->segment_list()->item(value); + uint64_t address = segment ? segment->address() : 0; + address_->setValue(segment ? QString::fromUtf8(DisplayValue(file_->cpu_address_size(), address).c_str()) : QString()); + offset_->setValue(segment ? QString::fromUtf8(DisplayValue(osDWord, segment->physical_offset() + address - segment->address()).c_str()) : QString()); + lock_ = false; +}
\ No newline at end of file diff --git a/VMProtect/property_editor.h b/VMProtect/property_editor.h new file mode 100644 index 0000000..3f589b6 --- /dev/null +++ b/VMProtect/property_editor.h @@ -0,0 +1,642 @@ +#ifndef PROPERTY_EDITOR_H +#define PROPERTY_EDITOR_H + +class Property : public QObject +{ + Q_OBJECT +public: + Property(Property *parent, const QString &name); + ~Property(); + QString name() const { return name_; } + void setName(const QString &name); + virtual QString valueText() const; + virtual QWidget *createEditor(QWidget *parent); + Property *parent() const { return parent_; } + virtual bool hasValue() const { return true; } + bool readOnly() const { return readOnly_; } + void setReadOnly(bool value); + QList<Property *> children() const { return children_; } + void addChild(Property *child); + void insertChild(int index, Property *child); + void removeChild(Property *child); + void clear(); + int childCount() const { return children_.size(); } + virtual bool hasStaticText(int column) const { return false; } + virtual QString staticText(int column) const { return QString(); } + virtual QColor staticColor(int column) const { return QColor(); } + QString toolTip() const { return toolTip_; } + void setToolTip(const QString &value) { toolTip_ = value; } +signals: + void destroyed(Property *prop); + void changed(Property *prop); +private: + Property *parent_; + QString name_; + bool readOnly_; + QList<Property *> children_; + QString toolTip_; +}; + +class StringProperty : public Property +{ + Q_OBJECT +public: + StringProperty(Property *parent, const QString &name, const QString &value); + virtual QString valueText() const; + virtual QWidget *createEditor(QWidget *parent); + QString value() const { return value_; } + void setValue(const QString &value); +signals: + void valueChanged(const QString &value); +private slots: + void editorChanged(const QString &value); +private: + QString value_; +}; + +class BoolProperty : public Property +{ + Q_OBJECT +public: + BoolProperty(Property *parent, const QString &name, bool value); + virtual QString valueText() const; + virtual QWidget *createEditor(QWidget *parent); + bool value() const { return value_; } + void setValue(bool value); +signals: + void valueChanged(bool value); +private slots: + void editorChanged(bool value); +private: + bool value_; +}; + +class DateProperty : public Property +{ + Q_OBJECT +public: + DateProperty(Property *parent, const QString &name, const QDate &value); + virtual QString valueText() const; + virtual QWidget *createEditor(QWidget *parent); + QDate value() const { return value_; } + void setValue(const QDate &value); +signals: + void valueChanged(const QDate &value); +private slots: + void editorChanged(const QDate &value); +private: + QDate value_; +}; + +class StringListProperty : public StringProperty +{ +public: + StringListProperty(Property *parent, const QString &name, const QString &value); + virtual QWidget *createEditor(QWidget *parent); +}; + +class GroupProperty : public Property +{ + Q_OBJECT +public: + GroupProperty(Property *parent, const QString &name); + virtual bool hasValue() const { return false; } +}; + +class CommandProperty : public Property +{ + Q_OBJECT +public: + CommandProperty(Property *parent, ICommand *value); + virtual QString valueText() const; + ICommand *value() const { return value_; } + virtual bool hasStaticText(int column) const; + virtual QString staticText(int column) const; + virtual QColor staticColor(int column) const; +private: + ICommand *value_; + QString text_; +}; + +class EnumProperty : public Property +{ + Q_OBJECT +public: + EnumProperty(Property *parent, const QString &name, const QStringList &items, int value); + int value() const { return value_; } + void setValue(int value); + void setItems(const QStringList &items) { items_ = items; } + virtual QString valueText() const; + virtual QWidget *createEditor(QWidget *parent); + void setText(int index, const QString &text) { items_[index] = text; } +signals: + void valueChanged(int value); +private slots: + void editorChanged(int value); +private: + QStringList items_; + int value_; +}; + +class CompilationTypeProperty : public Property +{ + Q_OBJECT +public: + CompilationTypeProperty(Property *parent, const QString &name, CompilationType value); + CompilationType value() const { return value_; } + void setValue(CompilationType value); + virtual QString valueText() const; + virtual QWidget *createEditor(QWidget *parent); + void setDefaultValue(CompilationType value) { defaultValue_ = value; } + void setText(int index, const QString &text) { items_[index] = text; } +signals: + void valueChanged(CompilationType value); +private slots: + void editorChanged(int value); +private: + QStringList items_; + CompilationType value_; + CompilationType defaultValue_; +}; + +class FileNameProperty : public Property +{ + Q_OBJECT +public: + FileNameProperty(Property *parent, const QString &name, const QString &filter, const QString &value, bool saveMode = false); + QString value() const { return value_; } + void setValue(const QString &value); + void setRelativePath(const QString &relativePath) { relativePath_ = relativePath; } + virtual QString valueText() const; + virtual QWidget *createEditor(QWidget *parent); + void setFilter(const QString &filter) { filter_ = filter; } +signals: + void valueChanged(const QString &value); +private slots: + void editorChanged(const QString &value); +private: + QString filter_; + QString value_; + QString relativePath_; + bool saveMode_; +}; + +class WatermarkProperty : public Property +{ + Q_OBJECT +public: + WatermarkProperty(Property *parent, const QString &name, const QString &value); + QString value() const { return value_; } + void setValue(const QString &value); + virtual QString valueText() const; + virtual QWidget *createEditor(QWidget *parent); +signals: + void valueChanged(const QString &value); +private slots: + void editorChanged(const QString &value); +private: + QString value_; +}; + +class PropertyManager : public QAbstractItemModel +{ + Q_OBJECT +public: + PropertyManager(QObject *parent = 0); + ~PropertyManager(); + void clear(); + virtual QModelIndex index(int row, int column, const QModelIndex &parent) const; + virtual QModelIndex parent(const QModelIndex &index) const; + virtual int rowCount(const QModelIndex &parent) const; + virtual int columnCount(const QModelIndex &parent) const; + virtual QVariant data(const QModelIndex &index, int role) const; + virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const; + virtual Qt::ItemFlags flags(const QModelIndex &index) const; + BoolProperty *addBoolProperty(Property *parent, const QString &name, bool value); + StringProperty *addStringProperty(Property *parent, const QString &name, const QString &value); + GroupProperty *addGroupProperty(Property *parent, const QString &name); + DateProperty *addDateProperty(Property *parent, const QString &name, const QDate &value); + StringListProperty *addStringListProperty(Property *parent, const QString &name, const QString &value); + EnumProperty *addEnumProperty(Property *parent, const QString &name, const QStringList &items, int value); + FileNameProperty *addFileNameProperty(Property *parent, const QString &name, const QString &filter, const QString &value, bool saveMode = false); + CommandProperty *addCommandProperty(Property *parent, ICommand *value); + WatermarkProperty *addWatermarkProperty(Property *parent, const QString &name, const QString &value); + CompilationTypeProperty *addCompilationTypeProperty(Property *parent, const QString &name, CompilationType value); + QModelIndex propertyToIndex(Property *prop) const; + Property *indexToProperty(const QModelIndex &index) const; + GroupProperty *root() const { return root_; } +private slots: + void slotPropertyChanged(Property *prop); + void slotPropertyDestroyed(Property *prop); +private: + void addProperty(Property *prop); + GroupProperty *root_; +}; + +class PropertyEditorDelegate : public TreeViewItemDelegate +{ + Q_OBJECT +public: + PropertyEditorDelegate(QObject *parent = 0); + QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &, const QModelIndex &index) const; +private: + void setEditorData(QWidget * /*widget*/, const QModelIndex &) const; + Property *indexToProperty(const QModelIndex &index) const; +}; + +class TreePropertyEditor : public TreeView +{ + Q_OBJECT +public: + TreePropertyEditor(QWidget *parent = NULL); +protected: + void keyPressEvent(QKeyEvent *event); + void mousePressEvent(QMouseEvent *event); + Property *indexToProperty(const QModelIndex &index) const; +protected slots: + virtual void dataChanged (const QModelIndex & topLeft, const QModelIndex & bottomRight, const QVector<int> &roles = QVector<int>()); +}; + +class License; +class InternalFile; + +class LicensePropertyManager : public PropertyManager +{ + Q_OBJECT +public: + LicensePropertyManager(QObject *parent = 0); + License *value() const { return value_; } + void setValue(License *value); + void update(); + virtual QVariant data(const QModelIndex &index, int role) const; + void localize(); + StringProperty *serialNumber() const { return licenseSerialNumber_; } +private slots: + void nameChanged(const QString &value); + void emailChanged(const QString &value); + void orderChanged(const QString &value); + void dateChanged(const QDate &value); + void commentsChanged(const QString &value); + void blockedChanged(bool value); +private: + License *value_; + bool lock_; + + GroupProperty *details_; + StringProperty *licenseName_; + StringProperty *licenseEmail_; + DateProperty *licenseDate_; + StringProperty *licenseOrder_; + StringListProperty *licenseComments_; + StringProperty *licenseSerialNumber_; + BoolProperty *licenseBlocked_; + + GroupProperty *contents_; + StringProperty *serialName_; + StringProperty *serialEmail_; + StringProperty *serialHWID_; + StringProperty *serialTimeLimit_; + DateProperty *serialExpirationDate_; + DateProperty *serialMaxBuildDate_; + StringProperty *serialUserData_; +}; + +class InternalFilePropertyManager : public PropertyManager +{ + Q_OBJECT +public: + InternalFilePropertyManager(QObject *parent = 0); + InternalFile *value() const { return value_; } + void setValue(InternalFile *value); + void update(); + void localize(); + QModelIndex fileNameIndex() const { return propertyToIndex(fileName_); } +private slots: + void nameChanged(const QString &value); + void fileNameChanged(const QString &value); + void actionChanged(int value); +private: + InternalFile *value_; + bool lock_; + + GroupProperty *details_; + StringProperty *name_; + FileNameProperty *fileName_; + EnumProperty *action_; +}; + +class AssemblyPropertyManager : public PropertyManager +{ + Q_OBJECT +public: + AssemblyPropertyManager(QObject *parent = 0); + InternalFile *value() const { return value_; } + void setValue(InternalFile *value); + void update(); + void localize(); + QModelIndex fileNameIndex() const { return propertyToIndex(fileName_); } + private slots: + void nameChanged(const QString &value); + void fileNameChanged(const QString &value); +private: + InternalFile *value_; + bool lock_; + + GroupProperty *details_; + StringProperty *name_; + FileNameProperty *fileName_; +}; + +class FunctionPropertyManager : public PropertyManager +{ + Q_OBJECT +public: + FunctionPropertyManager(QObject *parent = 0); + FunctionBundle *value() const { return value_; } + void setValue(FunctionBundle *value); + void update(); + void localize(); + void addFunction(IFunction *func); + void updateFunction(IFunction *func); + bool removeFunction(IFunction *func); + virtual QVariant data(const QModelIndex &index, int role) const; + QModelIndex commandToIndex(ICommand *command) const; + ICommand *indexToCommand(const QModelIndex &index) const; + IFunction *indexToFunction(const QModelIndex &index) const; +private slots: + void compilationTypeChanged(CompilationType value); + void lockToKeyChanged(bool value); +private: + void createCommands(IFunction *func, Property *code); + bool internalAddFunction(IFunction *func); + bool internalRemoveFunction(IFunction *func); + struct ArchInfo { + StringProperty *code; + QMap<IFunction *, StringProperty *> map; + ArchInfo() : code(NULL) {} + }; + FunctionBundle *value_; + bool lock_; + + GroupProperty *protection_; + CompilationTypeProperty *compilationType_; + BoolProperty *lockToKey_; + GroupProperty *details_; + StringProperty *name_; + StringProperty *address_; + StringProperty *type_; + QMap<IArchitecture *, ArchInfo> map_; +}; + +class SectionPropertyManager : public PropertyManager +{ + Q_OBJECT +public: + SectionPropertyManager(QObject *parent = 0); + ISection *value() const { return value_; } + void setValue(ISection *value); + void update(); + void localize(); +private: + ISection *value_; + + GroupProperty *details_; + StringProperty *name_; + StringProperty *address_; + StringProperty *virtual_size_; + StringProperty *physical_offset_; + StringProperty *physical_size_; + StringProperty *flags_; +}; + +class SegmentPropertyManager : public PropertyManager +{ + Q_OBJECT +public: + SegmentPropertyManager(QObject *parent = 0); + ISection *value() const { return value_; } + void setValue(ISection *value); + void update(); + void localize(); +private slots: + void excludedFromPackingChanged(bool value); + void excludedFromMemoryProtectionChanged(bool value); +private: + ISection *value_; + bool lock_; + + GroupProperty *options_; + GroupProperty *details_; + BoolProperty *excluded_from_packing_; + BoolProperty *excluded_from_memory_protection_; + StringProperty *name_; + StringProperty *address_; + StringProperty *virtual_size_; + StringProperty *physical_offset_; + StringProperty *physical_size_; + StringProperty *flags_; + BoolProperty *flag_readable_; + BoolProperty *flag_writable_; + BoolProperty *flag_executable_; + BoolProperty *flag_shared_; + BoolProperty *flag_discardable_; + BoolProperty *flag_notpaged_; +}; + +class ImportPropertyManager : public PropertyManager +{ + Q_OBJECT +public: + ImportPropertyManager(QObject *parent = 0); + ~ImportPropertyManager(); + virtual QVariant data(const QModelIndex &index, int role) const; + IImportFunction *value() const { return value_; } + void setValue(IImportFunction *value); + void update(); + void localize(); +private: + IImportFunction *value_; + + GroupProperty *details_; + StringProperty *name_; + StringProperty *address_; + StringProperty *references_; + IFunction *func_; +}; + +class ExportPropertyManager : public PropertyManager +{ + Q_OBJECT +public: + ExportPropertyManager(QObject *parent = 0); + IExport *value() const { return value_; } + void setValue(IExport *value); + void update(); + void localize(); +private: + IExport *value_; + + GroupProperty *details_; + StringProperty *name_; + StringProperty *forwarded_; + StringProperty *address_; +}; + +class ResourcePropertyManager : public PropertyManager +{ + Q_OBJECT +public: + ResourcePropertyManager(QObject *parent = 0); + IResource *value() const { return value_; } + void setValue(IResource *value); + void update(); + void localize(); +private slots: + void excludedFromPackingChanged(bool value); +private: + IResource *value_; + bool lock_; + + GroupProperty *options_; + BoolProperty *excluded_from_packing_; + GroupProperty *details_; + StringProperty *name_; + StringProperty *address_; + StringProperty *size_; +}; + +class LoadCommandPropertyManager : public PropertyManager +{ + Q_OBJECT +public: + LoadCommandPropertyManager(QObject *parent = 0); + ILoadCommand *value() const { return value_; } + void setValue(ILoadCommand *value); + void update(); + void localize(); +private: + ILoadCommand *value_; + + GroupProperty *details_; + StringProperty *name_; + StringProperty *address_; + StringProperty *size_; + StringProperty *segment_; +}; + +class CorePropertyManager : public PropertyManager +{ + Q_OBJECT +public: + CorePropertyManager(QObject *parent = 0); + Core *core() const { return core_; } + void setCore(Core *core); + void update(); + virtual QVariant data(const QModelIndex &index, int role) const; + void localize(); +#ifndef LITE + QModelIndex watermarkNameIndex() const { return propertyToIndex(watermarkName_); } +#endif +private slots: + void memoryProtectionChanged(bool value); + void importProtectionChanged(bool value); + void resourceProtectionChanged(bool value); + void packOutputFileChanged(bool value); + void watermarkNameChanged(const QString &value); + void hwidChanged(const QString &value); + void outputFileChanged(const QString &value); + void detectionDebuggerChanged(int value); + void detectioncpVMToolsChanged(bool value); + void vmSectionNameChanged(const QString &value); + void stripDebugInfoChanged(bool value); + void stripRelocationsChanged(bool value); + void debugModeChanged(bool value); + void messageDebuggerFoundChanged(const QString &value); + void messageVMToolsFoundChanged(const QString &value); + void messageFileCorruptedChanged(const QString &value); + void messageSerialNumberRequiredChanged(const QString &value); + void messageHWIDMismatchedChanged(const QString &value); + void licenseDataFileNameChanged(const QString &value); + void activationServerChanged(const QString &value); +private: + Core *core_; + bool lock_; + + GroupProperty *file_; + BoolProperty *memoryProtection_; + BoolProperty *importProtection_; + BoolProperty *resourceProtection_; + BoolProperty *packOutputFile_; +#ifndef LITE + WatermarkProperty *watermarkName_; +#endif +#ifdef ULTIMATE + StringProperty *hwid_; +#endif + FileNameProperty *outputFileName_; + + GroupProperty *detection_; + EnumProperty *detectionDebugger_; + BoolProperty *detectionVMTools_; + +#ifndef LITE + GroupProperty *messages_; + StringListProperty *messageDebuggerFound_; + StringListProperty *messageVMToolsFound_; + StringListProperty *messageFileCorrupted_; + StringListProperty *messageSerialNumberRequired_; + StringListProperty *messageHWIDMismatched_; +#endif + + GroupProperty *additional_; + StringProperty *vmSectionName_; + BoolProperty *stripDebugInfo_; + BoolProperty *stripRelocations_; + +#ifdef ULTIMATE + GroupProperty *licensingParameters_; + FileNameProperty *licenseDataFileName_; + StringProperty *keyPairAlgorithm_; + StringProperty *activationServer_; +#endif +}; + +class WatermarkPropertyManager : public PropertyManager +{ + Q_OBJECT +public: + WatermarkPropertyManager(QObject *parent = 0); + void setWatermark(Watermark *watermark); + Watermark *value() const { return watermark_; } + void update(); +private slots: + void nameChanged(const QString &value); + void blockedChanged(bool value); +private: + bool lock_; + StringProperty *name_; + BoolProperty *blocked_; + StringProperty *useCount_; + Watermark *watermark_; +}; + +class AddressCalculator : public PropertyManager +{ + Q_OBJECT +public: + AddressCalculator(QObject *parent = 0); + void setValue(IArchitecture *file); + void localize(); +private slots: + void addressChanged(const QString &value); + void offsetChanged(const QString &value); + void segmentChanged(int value); +private: + IArchitecture *file_; + bool lock_; + StringProperty *address_; + StringProperty *offset_; + EnumProperty *segment_; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/remotecontrol.cc b/VMProtect/remotecontrol.cc new file mode 100644 index 0000000..2761c3b --- /dev/null +++ b/VMProtect/remotecontrol.cc @@ -0,0 +1,102 @@ +//#include "../core/objects.h" +#include "remotecontrol.h" +#include "moc/moc_remotecontrol.cc" + +#ifndef VMP_GNU +#include "remotecontrol_win.h" +#include "moc/moc_remotecontrol_win.cc" + +StdInListenerWin::StdInListenerWin(QObject *parent) + : QThread(parent) +{ +} + +StdInListenerWin::~StdInListenerWin() +{ + terminate(); + wait(); +} + +void StdInListenerWin::run() +{ + bool ok = true; + char chBuf[4096]; + DWORD dwRead; + + HANDLE hStdin, hStdinDup; + + hStdin = GetStdHandle(STD_INPUT_HANDLE); + if (hStdin == INVALID_HANDLE_VALUE) + return; + + DuplicateHandle(GetCurrentProcess(), hStdin, + GetCurrentProcess(), &hStdinDup, + 0, false, DUPLICATE_SAME_ACCESS); + + CloseHandle(hStdin); + + while (ok) { + ok = ReadFile(hStdinDup, chBuf, sizeof(chBuf), &dwRead, NULL); + if (ok && dwRead != 0) + emit receivedCommand(QString::fromLocal8Bit(chBuf, dwRead)); + } + CloseHandle(hStdinDup); +} +#endif + +RemoteControl::RemoteControl(QMainWindow *mainWindow) + : QObject(mainWindow) +{ +#ifndef VMP_GNU + StdInListenerWin *l = new StdInListenerWin(this); + connect(l, SIGNAL(receivedCommand(QString)), + this, SLOT(handleCommandString(QString))); + l->start(); +#else + QSocketNotifier *notifier = new QSocketNotifier(fileno(stdin), + QSocketNotifier::Read, this); + connect(notifier, SIGNAL(activated(int)), this, SLOT(receivedData())); + notifier->setEnabled(true); +#endif +} + +void RemoteControl::receivedData() +{ + QByteArray ba; + while (true) { + int c = getc(stdin); + if (c == EOF || c == 0) + break; + ba.append(char(c)); + if (c == '\n') + break; + } + handleCommandString(QString::fromLocal8Bit(ba)); +} + +void RemoteControl::handleCommandString(const QString &cmdString) +{ + QStringList cmds = cmdString.split(QLatin1Char(';')); + QStringList::const_iterator it = cmds.constBegin(); + while (it != cmds.constEnd()) { + QString cmd, arg; + splitInputString(*it, cmd, arg); + + if (cmd == QLatin1String("navigatetokeyword")) + emit handleNavigateToKeywordCommand(arg); + else + break; + + ++it; + } +} + +void RemoteControl::splitInputString(const QString &input, QString &cmd, + QString &arg) +{ + QString cmdLine = input.trimmed(); + int i = cmdLine.indexOf(QLatin1Char('#')); + cmd = cmdLine.left(i); + arg = cmdLine.mid(i+1); + cmd = cmd.toLower(); +} diff --git a/VMProtect/remotecontrol.h b/VMProtect/remotecontrol.h new file mode 100644 index 0000000..633a6cd --- /dev/null +++ b/VMProtect/remotecontrol.h @@ -0,0 +1,29 @@ +#ifndef REMOTECONTROL_H +#define REMOTECONTROL_H + +#include <QtCore/QObject> +#include <QtCore/QString> +#include <QtCore/QUrl> + +class HelpEngineWrapper; +class MainWindow; + +class RemoteControl : public QObject +{ + Q_OBJECT + +public: + RemoteControl(QMainWindow *mainWindow); + +signals: + void handleNavigateToKeywordCommand(const QString &arg); + +private slots: + void receivedData(); + void handleCommandString(const QString &cmdString); + +private: + void splitInputString(const QString &input, QString &cmd, QString &arg); +}; + +#endif diff --git a/VMProtect/remotecontrol_win.h b/VMProtect/remotecontrol_win.h new file mode 100644 index 0000000..19d601e --- /dev/null +++ b/VMProtect/remotecontrol_win.h @@ -0,0 +1,19 @@ +#ifndef REMOTECONTROL_WIN_H +#define REMOTECONTROL_WIN_H + +class StdInListenerWin : public QThread +{ + Q_OBJECT + +public: + StdInListenerWin(QObject *parent); + ~StdInListenerWin(); + +signals: + void receivedCommand(const QString &cmd); + +private: + void run(); +}; + +#endif diff --git a/VMProtect/res.bat b/VMProtect/res.bat new file mode 100644 index 0000000..930489d --- /dev/null +++ b/VMProtect/res.bat @@ -0,0 +1,31 @@ +echo res.bat: generating QT resources... +SET RC_DIR=%~dp0 + +set rc_out=%RC_DIR%resources.cc +set rc=%rc_out% +set check_rc=0 +if exist %rc_out% ( + set rc_out=%RC_DIR%resources.cc.tmp + set check_rc=1 +) +%QTDIR%/msvc2015_64/bin/rcc.exe %RC_DIR%application.qrc -o %rc_out% + +call :ReplaceOld %check_rc% %rc_out% %rc% +goto :EOF + +:ReplaceOld +setlocal enableextensions enabledelayedexpansion +if "%1" == "1" ( + fc %2 %3 /B>>nul 2>&1 + if !ERRORLEVEL! == 1 ( + copy /y %2 %3>>nul 2>&1 + del %2>>nul 2>&1 + echo res.bat: QT resources '%3' are updated + ) else ( + echo res.bat: QT resources '%3' are up to date + ) +) else ( + echo res.bat: QT resources '%3' are generated +) +endlocal +goto :EOF
\ No newline at end of file diff --git a/VMProtect/settings_dialog.cc b/VMProtect/settings_dialog.cc new file mode 100644 index 0000000..40b7d9f --- /dev/null +++ b/VMProtect/settings_dialog.cc @@ -0,0 +1,119 @@ +#include "../core/objects.h" +//#include "../core/files.h" +#include "../core/lang.h" +#include "../core/core.h" +#include "../core/inifile.h" +#include "widgets.h" +#include "settings_dialog.h" +#include "help_browser.h" +#include "moc/moc_settings_dialog.cc" +#include "application.h" + +/** + * SettingsDialog + */ + +SettingsDialog::SettingsDialog(QWidget *parent) + : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::MSWindowsFixedSizeDialogHint | Qt::WindowCloseButtonHint) +{ + setWindowTitle(QString::fromUtf8(language[lsSettings].c_str())); + + QList<QString> languageList; + LanguageManager *languageManager = settings_file().language_manager(); + size_t lang_index = 0; + std::string lang_id = settings_file().language(); + for (size_t i = 0; i < languageManager->count(); i++) { + Language *lang = languageManager->item(i); + if (lang->id() == lang_id) + lang_index = i; + languageList.append(QString::fromUtf8(lang->name().c_str())); + } + + QFrame *group = new QFrame(this); + group->setObjectName("gridEditor"); + group->setFrameShape(QFrame::StyledPanel); + + QLabel *languageLabel = new QLabel(QString::fromUtf8(language[lsLanguage].c_str()), this); + languageLabel->setObjectName("editor"); + + languageEdit_ = new EnumEdit(this, languageList); + languageEdit_->setFrame(false); + languageEdit_->setObjectName("editor"); + + QLabel *autoSaveLabel = new QLabel(QString::fromUtf8(language[lsAutoSaveProject].c_str()), this); + autoSaveLabel->setObjectName("editor"); + + autoSaveEdit_ = new BoolEdit(this); + autoSaveEdit_->setFrame(false); + autoSaveEdit_->setObjectName("editor"); + + QGridLayout *layout = new QGridLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setHorizontalSpacing(0); + layout->setVerticalSpacing(1); + layout->setColumnStretch(0, 1); + layout->setColumnStretch(1, 1); + + layout->addWidget(languageLabel, 0, 0); + layout->addWidget(languageEdit_, 0, 1); + layout->addWidget(autoSaveLabel, 1, 0); + layout->addWidget(autoSaveEdit_, 1, 1); + group->setLayout(layout); + + QToolButton *helpButton = new QToolButton(this); + helpButton->setShortcut(HelpContentsKeySequence()); + helpButton->setIconSize(QSize(20, 20)); + helpButton->setIcon(QIcon(":/images/help_gray.png")); + helpButton->setToolTip(QString::fromUtf8(language[lsHelp].c_str())); + connect(helpButton, SIGNAL(clicked(bool)), this, SLOT(helpClicked())); + + QPushButton *okButton = new PushButton(QString::fromUtf8(language[lsOK].c_str()), this); + connect(okButton, SIGNAL(clicked()), this, SLOT(okButtonClicked())); + + QPushButton *cancelButton = new PushButton(QString::fromUtf8(language[lsCancel].c_str()), this); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + QHBoxLayout *buttonLayout = new QHBoxLayout(); + buttonLayout->setContentsMargins(0, 0, 0, 0); + buttonLayout->setSpacing(10); + buttonLayout->addWidget(helpButton); + buttonLayout->addStretch(); +#ifdef __APPLE__ + buttonLayout->addWidget(cancelButton); + buttonLayout->addWidget(okButton); +#else + buttonLayout->addWidget(okButton); + buttonLayout->addWidget(cancelButton); +#endif + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->setContentsMargins(10, 10, 10, 10); + mainLayout->setSpacing(10); + mainLayout->addWidget(group); + mainLayout->addLayout(buttonLayout); + setLayout(mainLayout); + + languageEdit_->setCurrentIndex((int)lang_index); + autoSaveEdit_->setCurrentIndex((int)settings_file().auto_save_project()); + + resize(400 * Application::stylesheetScaleFactor(), 10); +} + +void SettingsDialog::okButtonClicked() +{ + std::string lang_id = settings_file().language_manager()->item(languageEdit_->currentIndex())->id(); + bool auto_save_project = (autoSaveEdit_->currentIndex() == 1); + + if (settings_file().language() != lang_id) + settings_file().set_language(lang_id); + + if (settings_file().auto_save_project() != auto_save_project) + settings_file().set_auto_save_project(auto_save_project); + + accept(); +} + +void SettingsDialog::helpClicked() +{ + HelpBrowser::showTopic("settings"); +}
\ No newline at end of file diff --git a/VMProtect/settings_dialog.h b/VMProtect/settings_dialog.h new file mode 100644 index 0000000..faf7eab --- /dev/null +++ b/VMProtect/settings_dialog.h @@ -0,0 +1,21 @@ +#ifndef SETTINGS_DIALOG_H +#define SETTINGS_DIALOG_H + +class SettingsDialog : public QDialog +{ + Q_OBJECT +public: + SettingsDialog(QWidget *parent = NULL); +private slots: + void okButtonClicked(); + void helpClicked(); +private: + EnumEdit *languageEdit_; + BoolEdit *autoSaveEdit_; +#ifndef VMP_GNU + BoolEdit *shellExtEdit_; + bool shellExt_; +#endif +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/styles.qss b/VMProtect/styles.qss new file mode 100644 index 0000000..eee44a7 --- /dev/null +++ b/VMProtect/styles.qss @@ -0,0 +1,882 @@ +* +{ + font-family: "Tahoma", "Segoe UI", Helvetica, Verdana; + font-size: <8.25>; + color: black; +} + +QLabel#note +{ + font-size: <11.25>; + color: #bababa; +} + +QLabel#messageBox +{ + font-size: <9>; + font-weight: bold; + color: #41464b; +} + +QLabel#header +{ + font-size: <12>; + color: #9ba2aa; + padding: 0; +} + +QLabel#version +{ + font-size: <15.75>; + color: #2c3746; +} + +QLabel#unregistered +{ + font-weight: bold; +} + +QLabel#boot +{ + font-size: <12>; + color: #838f9e; +} + +QLabel#copyright, QLabel#build +{ + color: #545f6e; +} + +QLabel#editor +{ + background-color: white; + padding: 2px 2px 2px 8px; +} + +QCheckBox#editor +{ + background-color: white; + padding-left: <6>; + min-height: <18>; +} + +QCheckBox +{ + outline: none; +} + +QCheckBox::indicator:unchecked +{ + image: url(:/images/checkbox.png); +} + +QCheckBox::indicator:checked +{ + image: url(:/images/checkbox_checked.png); +} + +QFrame#desktop +{ + background-color: #2A2F36; +} + +QFrame#editor +{ + background-color: white; +} + +QFrame#boot +{ + background-color: #F6F7F9; +} + +QToolButton#boot +{ + border: none; + min-height: <15>; +} + +QToolButton#boot:hover, QToolButton#boot:pressed +{ + background-color: #B4C9E6; +} + +QFrame#bootTop, QFrame#aboutTop +{ + background-color: #cbd9e5; +} + +QFrame#bootHSeparator +{ + background-color: #a0b6c8; +} + +QFrame#bootVSeparator +{ + background-color: #cdd8e0; +} + +QFrame#gridEditor +{ + background-color: #e5e5e5; +} + +QFrame#gridEditor[frameShape="6"] +{ + border: 1px solid #C1C1C1; +} + +QTreeView, QLineEdit, QComboBox, QComboBox QAbstractItemView, ScriptEdit, QTextEdit, QDateEdit, QSpinBox, QPlainTextEdit, BinEditor +{ + outline: none; + border: 1px solid #C1C1C1; + background-color: white; +} + +QLineEdit[frame="false"], QComboBox[frame="false"], ButtonLineEdit[frame="false"], QDateEdit[frame="false"], QSpinBox[frame="false"] +{ + border: none; +} + +QLineEdit#editor[corrBearing="true"] +{ + /* FIXED QCommonStyle::pixelMetric(PM_FocusFrameVMargin) + 1 = 3, íî QLineEditPrivate::horizontalMargin = 2 + ñ äðóãîé ñòîðîíû, âèíäîâûé æèðíûé øðèôò (â äåðåâå ñâîéñòâ) èìååò fm.minLeftBearing() = -1 è + ýòà êîððåêöèÿ íå íóæíà + */ + padding-left: <2>; +} + +TreePropertyEditor QLineEdit#editor[corrBearing="true"] +{ + /* ñì. êîììåíòàðèé âûøå + */ + padding-left: <1>; +} + +QLineEdit#editor[OSX="true"], QComboBox#editor[OSX="true"], QDateEdit#editor[OSX="true"] +{ + padding-top: -1px; + padding-left: 1px; +} + +QLineEdit#editor[OSX="false"], QComboBox#editor[OSX="false"], QDateEdit#editor[OSX="false"] +{ + padding-left: 1px; +} + +ScriptEdit, QTreeView[frameShape="0"], QPlainTextEdit[frameShape="0"], BinEditor[frameShape="0"], QTextBrowser[frameShape="0"] +{ + border: none; +} + +QTreeView[frameShape="4"] +{ + border: none; + border-top: 1px solid #E5E5E5; +} + +QFrame[frameShape="5"] +{ + border: none; + border-left: 1px solid #E5E5E5; +} + +QTreeView#project +{ + background-color: #D9E0E6; +} + +QTreeView::branch +{ + background: transparent; + padding-left: <6>; +} + +QTreeView::branch:has-children:closed +{ + image: url(:/images/branch_closed.png); +} + +QTreeView::branch:has-children:open +{ + image: url(:/images/branch_open.png); +} + +QTableView#grid::item, QTreeView#grid::item, QTreeView#grid::branch +{ + border-bottom: 1px solid #E5E5E5; +} + +QTreeView::item:selected, QTreeView::branch:selected, QListView::item:selected, QTableView::item:selected +{ + color: black; + background-color: #B4C9E6; +} + +StringListEdit +{ + margin-left: <2.25>; + margin-bottom: 0; + margin-top: 1px; +} + +QHeaderView::section +{ + font: bold; + color: #8B8B8B; + background-color: #F7F7F7; + border: transparent; + border-bottom: 1px solid #C0C0C0; + min-height: <13.5>; + padding-left: 6px; +} + +QHeaderView::section:pressed +{ + color: white; + background-color: #8B8B8B; +} + +QHeaderView#project::section +{ + font: <12>; + color: #9ba2aa; + background-color: #D9E0E6; + border: none; + padding: 6px 0 6px 10px; +} + +QToolBar +{ + background-color: #535F6D; + border: 1px solid #444C59; + border-left: none; + spacing: <2.25>; + padding: 0; + min-height: <27>; +} + +QToolBar::separator +{ + background-color: #444C59; + width: 1px; +} + +QToolBar QToolButton +{ + font: <9.75>; + color: #d5d5d5; + background: transparent; + padding: 0; +} + +QToolButton +{ + background: transparent; + padding: 0; +} + +QToolButton:pressed, QToolButton:checked +{ + border: 2px solid transparent; +} + +QToolBar QToolButton:hover +{ + color: white; +} + +QToolBar QToolButton:disabled +{ + color: #7b838d; +} + +QToolBar QToolButton[popupMode="1"] +{ + padding-right: 9px; + border: 1px; +} + +QToolBar QToolButton[popupMode="2"] +{ + padding-right: 1px; + border: 1px; +} + +QToolBar QToolButton[popupMode="1"]::menu-arrow +{ + margin-top: <11.25>; + image: url(:/images/menu_arrow.png); +} + +QToolBar QToolButton[popupMode="2"]::menu-indicator +{ + margin-bottom: <2.25>; + image: url(:/images/menu_arrow.png); +} + +QToolBar QToolButton[popupMode="1"]::menu-arrow:disabled, QToolBar QToolButton[popupMode="2"]::menu-indicator:disabled +{ + image: url(:/images/menu_arrow_disabled.png); +} + +QToolBar QToolButton[popupMode="1"]::menu-arrow:hover, QToolBar QToolButton[popupMode="2"]::menu-indicator:hover +{ + image: url(:/images/menu_arrow_hover.png); +} + +QToolBar QComboBox +{ + padding-left: 4px; + margin-left: 2px; + color: #d5d5d5; + background: transparent; +} + +QToolBar QComboBox:hover +{ + color: white; +} + +QSplitter::handle +{ + background-color: #BABABA; +} + +QSplitter::handle:horizontal +{ + width: 1px; +} + +QSplitter::handle:vertical +{ + height: 1px; +} + +QLineEdit +{ + min-height: <18>; +} + +QScrollBar +{ + background: #F0F0F0; +} + +QScrollBar::handle +{ + background: #CDCDCD; +} + +QScrollBar::handle:hover +{ + background: #a6a6a6; +} + +QScrollBar::add-line, QScrollBar::sub-line +{ + background: #F0F0F0; +} + +QScrollBar::add-line:hover, QScrollBar::sub-line:hover +{ + background: #dadada; +} + +QScrollBar:horizontal +{ + border-top: 1px solid white; + border-bottom: 1px solid transparent; + height: <12.75>; + margin: 0 <12.75> 0 <12.75>; +} + +QScrollBar::handle:horizontal +{ + min-width: <15>; +} + +QScrollBar::add-line:horizontal +{ + border-top: 1px solid white; + border-bottom: 1px solid #F0F0F0; + width: <12.75>; + subcontrol-position: right; + subcontrol-origin: margin; + image: url(:/images/scroll_right.png); +} + +QScrollBar::add-line:horizontal:hover +{ + image: url(:/images/scroll_right_hover.png); +} + + +QScrollBar::sub-line:horizontal +{ + border-top: 1px solid white; + border-bottom: 1px solid #F0F0F0; + width: <12.75>; + subcontrol-position: left; + subcontrol-origin: margin; + image: url(:/images/scroll_left.png); +} + +QScrollBar::sub-line:horizontal:hover +{ + image: url(:/images/scroll_left_hover.png); +} + +QScrollBar:vertical +{ + border-left: 1px solid white; + border-right: 1px solid transparent; + width: <12.75>; + margin: <12.75> 0 <12.75> 0; +} + +QScrollBar::handle:vertical +{ + min-height: <15>; +} + +QScrollBar::add-line:vertical +{ + border-left: 1px solid white; + border-right: 1px solid #F0F0F0; + height: <12.75>; + subcontrol-position: bottom; + subcontrol-origin: margin; + image: url(:/images/scroll_down.png); +} + +QScrollBar::add-line:vertical:hover +{ + image: url(:/images/scroll_down_hover.png); +} + +QScrollBar::sub-line:vertical +{ + border-left: 1px solid white; + border-right: 1px solid #F0F0F0; + height: <12.75>; + subcontrol-position: top; + subcontrol-origin: margin; + image: url(:/images/scroll_up.png); +} + +QScrollBar::sub-line:vertical:hover +{ + image: url(:/images/scroll_up_hover.png); +} + +QDialog +{ + background-color: #D9E0E6; +} + +QTabWidget::pane +{ + border-top: 1px solid #959595; + top: -1px; +} + +QTabWidget::tab-bar +{ + alignment: center; +} + +QTabBar::tab +{ + border: 1px solid #959595; + border-right-color: transparent; + padding: 2px 10px 2px 10px; + min-height: <18>; +} + +QTabBar::tab:!selected +{ + border-bottom-color:#959595; + background-color: #CCD3D9; +} + +QTabBar::tab:selected +{ + border-bottom-color:#D9E0E6; + background-color: #D9E0E6; +} + +QTabBar::tab:hover:!selected +{ + background-color: #E5EAEE; +} + +QTabBar::tab:last, QTabBar::tab:only-one +{ + border-right-color: #959595; +} + +QRadioButton#project, QRadioButton#functions, QRadioButton#details +{ + padding: 15px 0 0 16px; + min-width: 49px; + max-width: 49px; + min-height: 32px; + max-height: 32px; +} + +QRadioButton#editor +{ + background-color: white; + padding-left: <6>; + min-height: <18>; +} + +QRadioButton +{ + outline: none; +} + +QRadioButton::indicator:unchecked +{ + image: url(:/images/radiobutton.png); +} + +QRadioButton::indicator:checked +{ + image: url(:/images/radiobutton_checked.png); +} + +QRadioButton#project::indicator::checked +{ + image: url(:/images/project_checked.png); +} + +QRadioButton#project::indicator::unchecked +{ + image: url(:/images/project.png); +} + +QRadioButton#project::indicator::unchecked::hover +{ + image: url(:/images/project_hover.png); +} + +QRadioButton#functions::indicator::checked +{ + image: url(:/images/functions_checked.png); +} + +QRadioButton#functions::indicator::unchecked +{ + image: url(:/images/functions.png); +} + +QRadioButton#functions::indicator::unchecked::hover +{ + image: url(:/images/functions_hover.png); +} + +QRadioButton#details::indicator::checked +{ + image: url(:/images/details_checked.png); +} + +QRadioButton#details::indicator::unchecked +{ + image: url(:/images/details.png); +} + +QRadioButton#details::indicator::unchecked::hover +{ + image: url(:/images/details_hover.png); +} + +QPushButton +{ + margin: 0; + outline: none; + font-weight: bold; + color: white; + border: none; + min-width: <45>; + min-height: <24>; + padding: 0 <14.25> 0 <14.25>; +} + +QPushButton:enabled +{ + background-color: #6D7583; +} + +QPushButton:hover +{ + background-color: #8F96A4; +} + +QPushButton:focus, QPushButton:default +{ + background-color: #FC5F0A; +} + +QPushButton:pressed +{ + background-color: #626975; +} + +QPushButton:disabled +{ + background-color: #B8C0C8; +} + +QPushButton:disabled:default +{ + background-color: #e4b9a4; +} + +QPushButton:hover:focus, QPushButton:hover:default +{ + background: #FF813D; +} + +QPushButton:pressed:focus, QPushButton:pressed:default +{ + background: #E3580C; +} + +QComboBox +{ + min-height: <18>; + color: black; + padding: 0px; /*This makes text colour work*/ +} + +QComboBox#editor +{ + padding-left: 0; + font-weight: bold; +} + +QComboBox::drop-down +{ + subcontrol-origin: padding; + subcontrol-position: top right; + width: <13.5>; + border: none; + background: transparent; + image: url(:/images/up_down.png); +} + +QComboBox::drop-down:hover +{ +} + +QComboBox::drop-down:disabled +{ + image: url(:/images/up_down_disabled.png); +} + +QComboBox QAbstractItemView +{ + selection-background-color: #B4C9E6; + selection-color: black; +} + +QPlainTextEdit +{ + selection-background-color: #B4C9E6; + selection-color: black; +} + +ButtonLineEdit +{ + padding-right: <13.5>; + min-height: <18>; +} + +ButtonLineEdit#editor +{ + font-weight: bold; +} + +ButtonLineEdit#editor[corrBearing="true"] +{ + padding-left: 0; + margin-left: 0; +} + +QTreeView ButtonLineEdit +{ + border: none; +} + +QAbstractSpinBox +{ + padding-right: <15>; + min-height: <18>; +} + +QAbstractSpinBox::up-button +{ + subcontrol-origin: border; + subcontrol-position: top right; + width: <12>; + margin: 2px 2px 1px 2px; + background: #d9e0e6; + image: url(:/images/up_arrow.png); +} + +QAbstractSpinBox::up-button:hover +{ + background: #eaf0f4 +} + +QAbstractSpinBox::up-button:pressed +{ + background: #bdc7d0; +} + +QAbstractSpinBox::up-button:disabled, QAbstractSpinBox::up-button:off +{ + background: #f4f6f7; + image: url(:/images/up_arrow_disabled.png); +} + +QAbstractSpinBox::down-button +{ + subcontrol-origin: border; + subcontrol-position: bottom right; + width: <12>; + margin: 1px 2px 2px 2px; + background: #d9e0e6; + image: url(:/images/down_arrow.png); +} + +QAbstractSpinBox::down-button:hover +{ + background: #eaf0f4 +} + +QAbstractSpinBox::down-button:pressed +{ + background: #bdc7d0; +} + +QAbstractSpinBox::down-button:disabled, QAbstractSpinBox::down-button:off +{ + background: #f4f6f7; + image: url(:/images/down_arrow_disabled.png); +} + +QProgressBar +{ + border: 1px solid #bababa; + background: transparent; + text-align: right; +} + +QProgressBar::chunk +{ + background: #b3c9e6; + width: 1px; +} + +QToolButton#cancel +{ + border-image: url(:/images/cancel.png) 0 0 0 0 stretch stretch; + border-width: 0px; +} + +QToolButton#cancel:hover +{ + border-image: url(:/images/cancel_hover.png) 0 0 0 0 stretch stretch; + border-width: 0px; +} + +BinEditor +{ + padding: <2.25>; + font-family: "Courier New"; + font-size: <10.5>; + font-weight: bold; +} + +QToolBar SearchLineEdit +{ + font: <9.75>; + color: white; + background: transparent; +} + +FindWidget +{ + border: none; + border-top: 1px solid #BABABA; +} + +QMenuBar +{ + background-color: #F6F7F9; +} + +QMenuBar::item +{ + spacing: <3.75>; + padding: 4px 10px; +} + +QMenuBar::item:selected +{ + background-color: #B4C9E6; +} + +QMenuBar::item:pressed +{ + background-color: #C1C1C1; +} + +QMenu +{ + background-color: #F6F7F9; + border: 1px solid #C1C1C1; +} + +QMenu::separator +{ + height: 1px; + background: #C1C1C1; + margin: <2.25>; +} + +QMenu::item +{ + background-color: transparent; + height: <18>; +} + +QMenu::item::selected +{ + background-color: #B4C9E6; +} + +QMenu::item::selected:enabled +{ + color: black; +} + +QStatusBar +{ + background-color: #535F6D; + border-top: 1px solid #444C59; +} + +QStatusBar::item +{ + border: none; +} + +QStatusBar QLabel +{ + color: white; +}
\ No newline at end of file diff --git a/VMProtect/template_save_dialog.cc b/VMProtect/template_save_dialog.cc new file mode 100644 index 0000000..81693fb --- /dev/null +++ b/VMProtect/template_save_dialog.cc @@ -0,0 +1,122 @@ +#include "../core/objects.h" +#include "../core/files.h" +#include "../core/lang.h" +#include "../core/core.h" +//#include "../core/inifile.h" +#include "widgets.h" +#include "template_save_dialog.h" +#include "help_browser.h" +#include "message_dialog.h" +#include "moc/moc_template_save_dialog.cc" + +/** + * TemplateSaveDialog + */ + +TemplateSaveDialog::TemplateSaveDialog(ProjectTemplateManager *ptm, QWidget *parent) + : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint) +{ + setWindowTitle(QString::fromUtf8(language[lsSaveTemplateAs].c_str())); + + QList<QString> list; + for (size_t i = 0; i < ptm->count(); i++) { + list.append(QString::fromUtf8(ptm->item(i)->display_name().c_str())); + } + + QFrame *group = new QFrame(this); + group->setObjectName("gridEditor"); + group->setFrameShape(QFrame::StyledPanel); + + QLabel *label = new QLabel(QString::fromUtf8(language[lsName].c_str()), this); + label->setObjectName("editor"); + + nameEdit_ = new EnumEdit(this, list); + nameEdit_->setEditable(true); + nameEdit_->setFrame(false); + nameEdit_->setObjectName("editor"); + connect(nameEdit_, SIGNAL(editTextChanged(const QString &)), this, SLOT(nameChanged())); + + QGridLayout *layout = new QGridLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setHorizontalSpacing(0); + layout->setVerticalSpacing(1); + layout->setColumnStretch(0, 1); + layout->setColumnStretch(1, 1); + + layout->addWidget(label, 0, 0); + layout->addWidget(nameEdit_, 0, 1); + group->setLayout(layout); + + QToolButton *helpButton = new QToolButton(this); + helpButton->setShortcut(HelpContentsKeySequence()); + helpButton->setIconSize(QSize(20, 20)); + helpButton->setIcon(QIcon(":/images/help_gray.png")); + helpButton->setToolTip(QString::fromUtf8(language[lsHelp].c_str())); + connect(helpButton, SIGNAL(clicked(bool)), this, SLOT(helpClicked())); + + okButton_ = new PushButton(QString::fromUtf8(language[lsOK].c_str()), this); + okButton_->setEnabled(false); + connect(okButton_, SIGNAL(clicked()), this, SLOT(okButtonClicked())); + + QPushButton *cancelButton = new PushButton(QString::fromUtf8(language[lsCancel].c_str()), this); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + QHBoxLayout *buttonLayout = new QHBoxLayout(); + buttonLayout->setContentsMargins(0, 0, 0, 0); + buttonLayout->setSpacing(10); + buttonLayout->addWidget(helpButton); + buttonLayout->addStretch(); +#ifdef __APPLE__ + buttonLayout->addWidget(cancelButton); + buttonLayout->addWidget(okButton_); +#else + buttonLayout->addWidget(okButton_); + buttonLayout->addWidget(cancelButton); +#endif + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->setContentsMargins(10, 10, 10, 10); + mainLayout->setSpacing(10); + mainLayout->addWidget(group); + mainLayout->addLayout(buttonLayout); + setLayout(mainLayout); + + QString tryName, defaultName = QString::fromUtf8(language[lsNewTemplate].c_str()); + int unique = 1; + do + { + tryName = defaultName; + if (unique > 1) + tryName += QString(" (%1)").arg(unique); + unique++; + } while(nameEdit_->findText(tryName) != -1); + nameEdit_->setCurrentText(tryName); + nameEdit_->lineEdit()->selectAll(); + + resize(600, 10); +} + +void TemplateSaveDialog::okButtonClicked() +{ + if (nameEdit_->findText(nameEdit_->currentText()) != -1) + { + if(MessageDialog::question(this, QString::fromUtf8(language[lsOverwriteTemplate].c_str()), QMessageBox::Yes | QMessageBox::No) == QMessageBox::No) + return; + } + accept(); +} + +void TemplateSaveDialog::helpClicked() +{ + //FIXME HelpBrowser::showTopic("templates"); +} + +void TemplateSaveDialog::nameChanged() +{ + okButton_->setEnabled(!nameEdit_->currentText().isEmpty()); +} + +QString TemplateSaveDialog::name() +{ + return nameEdit_->currentText(); +} diff --git a/VMProtect/template_save_dialog.h b/VMProtect/template_save_dialog.h new file mode 100644 index 0000000..1e519fd --- /dev/null +++ b/VMProtect/template_save_dialog.h @@ -0,0 +1,19 @@ +#ifndef TEMPLATE_SAVE_DIALOG_H +#define TEMPLATE_SAVE_DIALOG_H + +class TemplateSaveDialog : public QDialog +{ + Q_OBJECT +public: + TemplateSaveDialog(ProjectTemplateManager *ptm, QWidget *parent = NULL); + QString name(); +private slots: + void okButtonClicked(); + void helpClicked(); + void nameChanged(); +private: + EnumEdit *nameEdit_; + QPushButton *okButton_; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/templates_window.cc b/VMProtect/templates_window.cc new file mode 100644 index 0000000..0bc96b5 --- /dev/null +++ b/VMProtect/templates_window.cc @@ -0,0 +1,120 @@ +#include "../core/objects.h" +#include "../core/files.h" +#include "../core/lang.h" +#include "../core/core.h" +#include "models.h" +#include "widgets.h" +#include "help_browser.h" +#include "message_dialog.h" +#include "templates_window.h" +#include "moc/moc_templates_window.cc" + +/** + * TemplatesWindow + */ + +TemplatesModel *TemplatesWindow::templates_model_ = NULL; + +TemplatesWindow::TemplatesWindow(QWidget *parent) + : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::WindowCloseButtonHint) +{ + setWindowTitle(QString::fromUtf8(language[lsTemplates].c_str())); + + renameAct_ = new QAction(QString::fromUtf8(language[lsRename].c_str()), this); + renameAct_->setShortcut(QString("F2")); + renameAct_->setEnabled(false); + connect(renameAct_, SIGNAL(triggered()), this, SLOT(renameClicked())); + delAct_ = new QAction(QString::fromUtf8(language[lsDelete].c_str()), this); + delAct_->setShortcut(QString("Del")); + delAct_->setEnabled(false); + connect(delAct_, SIGNAL(triggered()), this, SLOT(delClicked())); + + contextMenu_ = new QMenu(this); + contextMenu_->addAction(delAct_); + contextMenu_->addAction(renameAct_); + + templateTree_ = new TreeView(this); + templateTree_->setObjectName("grid"); + templateTree_->setRootIsDecorated(false); + templateTree_->setUniformRowHeights(true); + templateTree_->setIconSize(QSize(18, 18)); + templateTree_->setContextMenuPolicy(Qt::CustomContextMenu); + templateTree_->setItemDelegate(new TemplatesTreeDelegate(this)); + templateTree_->setModel(templates_model_); + templateTree_->addAction(delAct_); + connect(templateTree_->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(templateIndexChanged())); + connect(templateTree_, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(contextMenuRequested(const QPoint &))); + + QToolButton *helpButton = new QToolButton(this); + helpButton->setShortcut(HelpContentsKeySequence()); + helpButton->setIconSize(QSize(20, 20)); + helpButton->setIcon(QIcon(":/images/help_gray.png")); + helpButton->setToolTip(QString::fromUtf8(language[lsHelp].c_str())); + connect(helpButton, SIGNAL(clicked(bool)), this, SLOT(helpClicked())); + + closeButton_ = new PushButton(QString::fromUtf8(language[lsClose].c_str()), this); + connect(closeButton_, SIGNAL(clicked()), this, SLOT(reject())); + + QHBoxLayout *buttonLayout = new QHBoxLayout(); + buttonLayout->setContentsMargins(0, 0, 0, 0); + buttonLayout->setSpacing(10); + buttonLayout->addWidget(helpButton); + buttonLayout->addStretch(); + buttonLayout->addWidget(closeButton_); + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->setContentsMargins(10, 10, 10, 10); + mainLayout->setSpacing(10); + mainLayout->addWidget(templateTree_); + mainLayout->addLayout(buttonLayout); + setLayout(mainLayout); + + resize(600, 300); +} + +void TemplatesWindow::contextMenuRequested(const QPoint &p) +{ + contextMenu_->exec(templateTree_->viewport()->mapToGlobal(p)); +} + +void TemplatesWindow::helpClicked() +{ + //FIXME HelpBrowser::showTopic("templates"); +} + +void TemplatesWindow::templateIndexChanged() +{ + ProjectTemplate *pt = selectedTemplate(); + templateTree_->selectionModel()->select(templateTree_->currentIndex(), QItemSelectionModel::ClearAndSelect); + + delAct_->setEnabled(pt != NULL); + renameAct_->setEnabled(pt != NULL && templateTree_->currentIndex().row() > 0); +} + +void TemplatesWindow::delClicked() +{ + ProjectTemplate *pt = selectedTemplate(); + if (!pt) + return; + + if (pt->is_default()) { + if (MessageDialog::warning(this, QString(QString::fromUtf8(language[lsDeleteDefaultTemplate].c_str())), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + pt->Reset(); + } else { + if (MessageDialog::question(this, QString(QString::fromUtf8(language[lsDeleteTemplate].c_str()) +"?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) + delete pt; + } +} + +void TemplatesWindow::renameClicked() +{ + templateTree_->edit(templateTree_->currentIndex()); +} + +ProjectTemplate *TemplatesWindow::selectedTemplate() const +{ + QModelIndex idx = templateTree_->currentIndex(); + ProjectNode *node = templates_model_->indexToNode(idx); + return (node && node->type() == NODE_TEMPLATE) ? reinterpret_cast<ProjectTemplate *>(node->data()) : NULL; +} + diff --git a/VMProtect/templates_window.h b/VMProtect/templates_window.h new file mode 100644 index 0000000..4634ace --- /dev/null +++ b/VMProtect/templates_window.h @@ -0,0 +1,26 @@ +#ifndef TEMPLATES_WINDOW_H +#define TEMPLATES_WINDOW_H + +class TemplatesWindow : public QDialog +{ + Q_OBJECT +public: + TemplatesWindow(QWidget *parent = NULL); + static void setModel(TemplatesModel *model) { templates_model_ = model; } +private slots: + void helpClicked(); + void contextMenuRequested(const QPoint &p); + void delClicked(); + void renameClicked(); + void templateIndexChanged(); +private: + ProjectTemplate *selectedTemplate() const; + static TemplatesModel *templates_model_; + QPushButton *closeButton_; + QAction *renameAct_; + QAction *delAct_; + QMenu *contextMenu_; + QTreeView *templateTree_; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/wait_cursor.h b/VMProtect/wait_cursor.h new file mode 100644 index 0000000..1f307f4 --- /dev/null +++ b/VMProtect/wait_cursor.h @@ -0,0 +1,13 @@ +#ifndef WAITCURSOR_H +#define WAITCURSOR_H + +class WaitCursor +{ +public: + WaitCursor() { QApplication::setOverrideCursor(QCursor(Qt::WaitCursor)); } + ~WaitCursor() { QApplication::restoreOverrideCursor(); } +protected: +private: +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/watermark_dialog.cc b/VMProtect/watermark_dialog.cc new file mode 100644 index 0000000..1406fe3 --- /dev/null +++ b/VMProtect/watermark_dialog.cc @@ -0,0 +1,123 @@ +#include "../core/objects.h" +#include "../core/lang.h" +#include "../core/core.h" +#include "widgets.h" +#include "watermark_dialog.h" +#include "moc/moc_watermark_dialog.cc" +#include "help_browser.h" +#include "application.h" + +/** + * WatermarkDialog + */ + +WatermarkDialog::WatermarkDialog(WatermarkManager *manager, QWidget *parent) + : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint | Qt::MSWindowsFixedSizeDialogHint), manager_(manager), watermark_(NULL) +{ + setWindowTitle(QString::fromUtf8(language[lsAddWatermark].c_str())); + + QFont font; + font.setBold(true); + + QLabel *details = new QLabel(QString::fromUtf8(language[lsDetails].c_str()), this); + details->setObjectName("header"); + QFrame *groupDetails = new QFrame(this); + groupDetails->setObjectName("gridEditor"); + groupDetails->setFrameShape(QFrame::StyledPanel); + + QLabel *nameLabel = new QLabel(QString::fromUtf8(language[lsName].c_str()), this); + nameLabel->setObjectName("editor"); + nameEdit_ = new LineEdit(this); + nameEdit_->setFrame(false); + nameEdit_->setFont(font); + + QFrame *valueFrame = new QFrame(this); + valueFrame->setObjectName("editor"); + QLabel *valueLabel = new QLabel(QString::fromUtf8(language[lsValue].c_str()), valueFrame); + valueLabel->setObjectName("editor"); + valueEdit_ = new BinEditor(this); + valueEdit_->setFrameShape(QFrame::NoFrame); + valueEdit_->setOverwriteMode(false); + valueEdit_->setMaskAllowed(true); + font = valueEdit_->font(); + font.setBold(true); + valueEdit_->setFont(font); + valueEdit_->setMaximumHeight(60 * Application::stylesheetScaleFactor()); + + QGridLayout *layout = new QGridLayout(); + layout->setContentsMargins(0, 0, 0, 0); + layout->setHorizontalSpacing(0); + layout->setVerticalSpacing(1); + layout->setColumnMinimumWidth(0, 180 * Application::stylesheetScaleFactor()); + layout->setColumnStretch(1, 1); + layout->setRowStretch(1, 1); + layout->addWidget(nameLabel, 0, 0); + layout->addWidget(nameEdit_, 0, 1); + layout->addWidget(valueFrame, 1, 0); + layout->addWidget(valueEdit_, 1, 1); + + groupDetails->setLayout(layout); + + QToolButton *helpButton = new QToolButton(this); + helpButton->setShortcut(HelpContentsKeySequence()); + helpButton->setIconSize(QSize(20, 20)); + helpButton->setIcon(QIcon(":/images/help_gray.png")); + helpButton->setToolTip(QString::fromUtf8(language[lsHelp].c_str())); + connect(helpButton, SIGNAL(clicked(bool)), this, SLOT(helpClicked())); + + okButton_ = new PushButton(QString::fromUtf8(language[lsAddWatermark].c_str()), this); + okButton_->setEnabled(false); + QPushButton *cancelButton = new PushButton(QString::fromUtf8(language[lsCancel].c_str()), this); + QPushButton *generateButton = new PushButton(QString::fromUtf8(language[lsGenerate].c_str()), this); + QHBoxLayout *buttonLayout = new QHBoxLayout(); + buttonLayout->setContentsMargins(0, 0, 0, 0); + buttonLayout->setSpacing(10); + buttonLayout->addWidget(helpButton); + buttonLayout->addStretch(); + buttonLayout->addWidget(generateButton); +#ifdef __APPLE__ + buttonLayout->addWidget(cancelButton); + buttonLayout->addWidget(okButton_); +#else + buttonLayout->addWidget(okButton_); + buttonLayout->addWidget(cancelButton); +#endif + + QVBoxLayout *mainLayout = new QVBoxLayout(); + mainLayout->setContentsMargins(10, 10, 10, 10); + mainLayout->setSpacing(10); + mainLayout->addWidget(details); + mainLayout->addWidget(groupDetails); + mainLayout->addLayout(buttonLayout); + setLayout(mainLayout); + + connect(nameEdit_, SIGNAL(textChanged(const QString &)), this, SLOT(changed())); + connect(valueEdit_, SIGNAL(dataChanged()), this, SLOT(changed())); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + connect(generateButton, SIGNAL(clicked()), this, SLOT(generateClicked())); + connect(okButton_, SIGNAL(clicked()), this, SLOT(okButtonClicked())); + + setMinimumSize(450 * Application::stylesheetScaleFactor(), 100 * Application::stylesheetScaleFactor()); +} + +void WatermarkDialog::okButtonClicked() +{ + watermark_ = manager_->Add(nameEdit_->text().toUtf8().constData(), valueEdit_->value().toUtf8().constData()); + + accept(); +} + +void WatermarkDialog::changed() +{ + okButton_->setEnabled(!nameEdit_->text().isEmpty() && !valueEdit_->isEmpty()); +} + +void WatermarkDialog::generateClicked() +{ + valueEdit_->setValue(QString::fromUtf8(manager_->CreateValue().c_str())); +} + +void WatermarkDialog::helpClicked() +{ + HelpBrowser::showTopic("watermarks::setup"); +}
\ No newline at end of file diff --git a/VMProtect/watermark_dialog.h b/VMProtect/watermark_dialog.h new file mode 100644 index 0000000..cb05587 --- /dev/null +++ b/VMProtect/watermark_dialog.h @@ -0,0 +1,24 @@ +#ifndef WATERMARK_DIALOG_H +#define WATERMARK_DIALOG_H + +class WatermarkDialog : public QDialog +{ + Q_OBJECT +public: + WatermarkDialog(WatermarkManager *manager, QWidget *parent = NULL); + Watermark *watermark() const { return watermark_; } +private slots: + void okButtonClicked(); + void changed(); + void generateClicked(); + void helpClicked(); +private: + WatermarkManager *manager_; + Watermark *watermark_; + + QPushButton *okButton_; + QLineEdit *nameEdit_; + BinEditor *valueEdit_; +}; + +#endif
\ No newline at end of file diff --git a/VMProtect/watermarks_window.cc b/VMProtect/watermarks_window.cc new file mode 100644 index 0000000..462a00b --- /dev/null +++ b/VMProtect/watermarks_window.cc @@ -0,0 +1,596 @@ +#include "../core/objects.h" +#include "../core/osutils.h" +#include "../core/core.h" +#include "../core/streams.h" +#include "../core/files.h" +#include "../core/pefile.h" +#include "../core/macfile.h" +#include "../core/elffile.h" +#include "../core/lang.h" +#include "models.h" +#include "widgets.h" +#include "progress_dialog.h" +#include "watermarks_window.h" +#include "moc/moc_watermarks_window.cc" +#include "message_dialog.h" +#include "watermark_dialog.h" +#include "wait_cursor.h" +#include "help_browser.h" +#include "application.h" + +WatermarksModel *WatermarksWindow::watermarks_model = NULL; + +WatermarksWindow::WatermarksWindow(bool selectMode, QWidget *parent) + : QDialog(parent, Qt::WindowSystemMenuHint | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint), processEditLocked(false) +#ifndef VMP_GNU + , debugPrivilegeEnabled(false) +#endif +{ + setWindowTitle(QString::fromUtf8(language[lsWatermarks].c_str())); + + searchModel = new SearchModel(this); + scanModel = new WatermarkScanModel(this); + + tabBar = new TabWidget(this); + tabBar->setIconSize(QSize(18, 18)); + + addAct = new QAction(QString::fromUtf8(language[lsAddWatermark].c_str()) + "...", this); + addAct->setShortcut(QString("Ins")); + connect(addAct, SIGNAL(triggered()), this, SLOT(addClicked())); + renameAct = new QAction(QString::fromUtf8(language[lsRename].c_str()), this); + renameAct->setShortcut(QString("F2")); + renameAct->setEnabled(false); + connect(renameAct, SIGNAL(triggered()), this, SLOT(renameClicked())); + delAct = new QAction(QString::fromUtf8(language[lsDelete].c_str()), this); + delAct->setShortcut(QString("Del")); + delAct->setEnabled(false); + connect(delAct, SIGNAL(triggered()), this, SLOT(delClicked())); + blockAct = new QAction(QString::fromUtf8(language[lsBlocked].c_str()), this); + blockAct->setEnabled(false); + blockAct->setCheckable(true); + connect(blockAct, SIGNAL(triggered()), this, SLOT(blockClicked())); + + contextMenu = new QMenu(this); + contextMenu->addAction(addAct); + contextMenu->addSeparator(); + contextMenu->addAction(delAct); + contextMenu->addAction(renameAct); + contextMenu->addSeparator(); + contextMenu->addAction(blockAct); + + pagePanel = new QStackedWidget(this); + + addButton = new QToolButton(this); + addButton->setToolButtonStyle(Qt::ToolButtonTextBesideIcon); + addButton->setAutoRaise(true); + addButton->setText(addAct->text()); + addButton->setIconSize(QSize(20, 20)); + addButton->setIcon(QIcon(":/images/add_gray.png")); + connect(addButton, SIGNAL(clicked(bool)), this, SLOT(addClicked())); + + watermarkFilter = new SearchLineEdit(this); + watermarkFilter->setPlaceholderText(QString::fromUtf8(language[lsSearch].c_str())); + connect(watermarkFilter, SIGNAL(textChanged(const QString &)), this, SLOT(watermarkSearchChanged())); + connect(watermarkFilter, SIGNAL(returnPressed()), this, SLOT(watermarkSearchChanged())); + + watermarkTree = new TreeView(this); + watermarkTree->setObjectName("grid"); + watermarkTree->setRootIsDecorated(false); + watermarkTree->setUniformRowHeights(true); + watermarkTree->setIconSize(QSize(18, 18)); + watermarkTree->setContextMenuPolicy(Qt::CustomContextMenu); + watermarkTree->setItemDelegate(new WatermarksTreeDelegate(this)); + watermarkTree->setModel(watermarks_model); + watermarkTree->addAction(addAct); + watermarkTree->addAction(delAct); + connect(watermarkTree->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(watermarkIndexChanged())); + connect(watermarkTree, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(itemDoubleClicked(QModelIndex))); + connect(watermarkTree, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(contextMenuRequested(const QPoint &))); + pagePanel->addWidget(watermarkTree); + + searchTree = new TreeView(this); + searchTree->setObjectName("grid"); + searchTree->setIconSize(QSize(18, 18)); + searchTree->setRootIsDecorated(false); + searchTree->setUniformRowHeights(true); + //searchTree->setFrameShape(QFrame::NoFrame); + searchTree->setModel(searchModel); + connect(searchTree->selectionModel(), SIGNAL(currentChanged(QModelIndex, QModelIndex)), this, SLOT(watermarkIndexChanged())); + connect(searchTree, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(itemDoubleClicked(QModelIndex))); + pagePanel->addWidget(searchTree); + + QTreeView *scanTree = new TreeView(this); + scanTree->setObjectName("grid"); + scanTree->setRootIsDecorated(false); + scanTree->setIconSize(QSize(18, 18)); + scanTree->setModel(scanModel); + scanTree->header()->resizeSection(0, 300 * Application::stylesheetScaleFactor()); + + QToolButton *helpButton = new QToolButton(this); + helpButton->setShortcut(HelpContentsKeySequence()); + helpButton->setIconSize(QSize(20, 20)); + helpButton->setIcon(QIcon(":/images/help_gray.png")); + helpButton->setToolTip(QString::fromUtf8(language[lsHelp].c_str())); + connect(helpButton, SIGNAL(clicked(bool)), this, SLOT(helpClicked())); + + okButton = new PushButton(QString::fromUtf8(language[lsOK].c_str()), this); + okButton->setVisible(selectMode); + connect(okButton, SIGNAL(clicked()), this, SLOT(okButtonClicked())); + + QPushButton *cancelButton = new PushButton(QString::fromUtf8(language[selectMode ? lsCancel : lsClose].c_str()), this); + connect(cancelButton, SIGNAL(clicked()), this, SLOT(reject())); + + QHBoxLayout *buttonLayout = new QHBoxLayout(); + buttonLayout->setContentsMargins(0, 0, 0, 0); + buttonLayout->setSpacing(10); + buttonLayout->addWidget(helpButton); + buttonLayout->addStretch(); +#ifdef __APPLE__ + buttonLayout->addWidget(cancelButton); + buttonLayout->addWidget(okButton); +#else + buttonLayout->addWidget(okButton); + buttonLayout->addWidget(cancelButton); +#endif + + QFrame *panel = new QFrame(this); + QGridLayout *gridLayout = new QGridLayout(); + gridLayout->setContentsMargins(0, 10, 0, 0); + gridLayout->setVerticalSpacing(10); + gridLayout->addWidget(addButton, 0, 0); + gridLayout->addItem(new QSpacerItem(30, 0, QSizePolicy::Expanding, QSizePolicy::Ignored), 0, 1); + gridLayout->addWidget(watermarkFilter, 0, 2); + gridLayout->addWidget(pagePanel, 1, 0, 1, 3); + panel->setLayout(gridLayout); + tabBar->addTab(panel, QIcon(":/images/tool.png"), QString::fromUtf8(language[lsSetup].c_str())); + + QFrame *filePanel = new QFrame(this); + filePanel->setObjectName("gridEditor"); + filePanel->setFrameShape(QFrame::StyledPanel); + + fileButton = new QRadioButton(QString::fromUtf8(language[lsSearchInFile].c_str()), this); + fileButton->setObjectName("editor"); + connect(fileButton, SIGNAL(clicked()), this, SLOT(fileButtonClicked())); + + QFrame *fileSpacer = new QFrame(this); + fileSpacer->setObjectName("editor"); + fileSpacer->setFixedWidth(17); + + QFont font; + font.setBold(true); + + fileNameLabel = new QLabel(QString::fromUtf8(language[lsFileName].c_str()), this); + fileNameLabel->setObjectName("editor"); + + fileNameEdit = new FileNameEdit(this); + fileNameEdit->setObjectName("editor"); + fileNameEdit->setFrame(false); + fileNameEdit->setFilter(QString( +#ifdef VMP_GNU + "%1 (*)" +#else + "%1 (*.*)" +#endif + ).arg(QString::fromUtf8(language[lsAllFiles].c_str()))); + + processButton = new QRadioButton(QString::fromUtf8(language[lsSearchInModule].c_str()), this); + processButton->setObjectName("editor"); + connect(processButton, SIGNAL(clicked()), this, SLOT(processButtonClicked())); + + QFrame *processSpacer = new QFrame(this); + processSpacer->setObjectName("editor"); + processSpacer->setFixedWidth(17); + + processLabel = new QLabel(QString::fromUtf8(language[lsProcess].c_str()), this); + processLabel->setObjectName("editor"); + + processEdit = new EnumEdit(this, QStringList()); + processEdit->setFrame(false); + processEdit->setObjectName("editor"); + processEdit->setFont(font); + connect(processEdit, SIGNAL(dropDown()), this, SLOT(processEditDropDown())); + connect(processEdit, SIGNAL(currentIndexChanged(int)), this, SLOT(processEditChanged())); + + QFrame *moduleSpacer = new QFrame(this); + moduleSpacer->setObjectName("editor"); + moduleSpacer->setFixedWidth(17); + + moduleLabel = new QLabel(QString::fromUtf8(language[lsModule].c_str()), this); + moduleLabel->setObjectName("editor"); + + moduleEdit = new EnumEdit(this, QStringList()); + moduleEdit->setFrame(false); + moduleEdit->setObjectName("editor"); + moduleEdit->setFont(font); + + gridLayout = new QGridLayout(); + gridLayout->setContentsMargins(0, 0, 0, 0); + gridLayout->setHorizontalSpacing(0); + gridLayout->setVerticalSpacing(1); + gridLayout->addWidget(fileButton, 0, 0, 1, 3); + gridLayout->addWidget(fileSpacer, 1, 0); + gridLayout->addWidget(fileNameLabel, 1, 1); + gridLayout->addWidget(fileNameEdit, 1, 2); + gridLayout->addWidget(processButton, 2, 0, 1, 3); + gridLayout->addWidget(processSpacer, 3, 0); + gridLayout->addWidget(processLabel, 3, 1); + gridLayout->addWidget(processEdit, 3, 2); + gridLayout->addWidget(moduleSpacer, 4, 0); + gridLayout->addWidget(moduleLabel, 4, 1); + gridLayout->addWidget(moduleEdit, 4, 2); + gridLayout->setColumnMinimumWidth(1, 100 * Application::stylesheetScaleFactor()); + gridLayout->setColumnStretch(2, 1); + filePanel->setLayout(gridLayout); + + QPushButton *scanButton = new PushButton(QString::fromUtf8(language[lsStart].c_str()), this); + connect(scanButton, SIGNAL(clicked()), this, SLOT(scanButtonClicked())); + + panel = new QFrame(this); + QBoxLayout *layout = new QVBoxLayout(); + layout->setContentsMargins(0, 10, 0, 0); + layout->setSpacing(10); + layout->addWidget(filePanel); + layout->addWidget(scanButton, 0, Qt::AlignCenter); + layout->addWidget(scanTree, 1); + panel->setLayout(layout); + tabBar->addTab(panel, QIcon(":/images/search_gray.png"), QString::fromUtf8(language[lsSearch].c_str())); + + layout = new QVBoxLayout(); + layout->setContentsMargins(10, 10, 10, 10); + layout->setSpacing(10); + layout->addWidget(tabBar); + layout->addLayout(buttonLayout); + setLayout(layout); + + connect(watermarks_model, SIGNAL(nodeUpdated(ProjectNode *)), this, SLOT(watermarkNodeUpdated(ProjectNode *))); + connect(watermarks_model, SIGNAL(nodeRemoved(ProjectNode *)), this, SLOT(watermarkNodeRemoved(ProjectNode *))); + + fileButton->setChecked(true); + fileButtonClicked(); + + setMinimumSize(450 * Application::stylesheetScaleFactor(), 300 * Application::stylesheetScaleFactor()); +} + +WatermarksWindow::~WatermarksWindow() +{ + disconnect(watermarks_model, SIGNAL(nodeUpdated(ProjectNode *)), this, SLOT(watermarkNodeUpdated(ProjectNode *))); + disconnect(watermarks_model, SIGNAL(nodeRemoved(ProjectNode *)), this, SLOT(watermarkNodeRemoved(ProjectNode *))); + + delete searchModel; + delete scanModel; +} + +void WatermarksWindow::watermarkNodeUpdated(ProjectNode *node) +{ + searchModel->updateNode(node); +} + +void WatermarksWindow::watermarkNodeRemoved(ProjectNode *node) +{ + searchModel->removeNode(node); + scanModel->removeWatermark(static_cast<Watermark *>(node->data())); +} + +void WatermarksWindow::okButtonClicked() +{ + if (selectedWatermark()) + accept(); +} + +ProjectNode *WatermarksWindow::currentNode() const +{ + ProjectNode *res = NULL; + if (pagePanel->currentWidget() == watermarkTree) { + res = watermarks_model->indexToNode(watermarkTree->currentIndex()); + } else if (pagePanel->currentWidget() == searchTree) { + res = searchModel->indexToNode(searchTree->currentIndex()); + } + return res; +} + +Watermark *WatermarksWindow::selectedWatermark() const +{ + ProjectNode *node = currentNode(); + return (node && node->type() == NODE_WATERMARK) ? reinterpret_cast<Watermark *>(node->data()) : NULL; +} + +void WatermarksWindow::watermarkSearchChanged() +{ + Watermark *watermark = selectedWatermark(); + if (!watermarkFilter->text().isEmpty()) { + searchModel->search(watermarks_model->root(), watermarkFilter->text()); + pagePanel->setCurrentWidget(searchTree); + searchTree->setCurrentIndex(searchModel->nodeToIndex(watermarks_model->objectToNode(watermark))); + } else { + pagePanel->setCurrentWidget(watermarkTree); + watermarkTree->setCurrentIndex(watermarks_model->objectToIndex(watermark)); + } + + watermarkIndexChanged(); +} + +QTreeView *WatermarksWindow::currentTreeView() const +{ + if (pagePanel->currentWidget() == watermarkTree) + return watermarkTree; + else + return searchTree; +} + +void WatermarksWindow::watermarkIndexChanged() +{ + Watermark *watermark = selectedWatermark(); + + okButton->setEnabled(watermark != NULL); + delAct->setEnabled(watermark != NULL); + renameAct->setEnabled(watermark != NULL); + blockAct->setEnabled(watermark != NULL); + blockAct->setChecked(watermark != NULL && !watermark->enabled()); +} + +void WatermarksWindow::itemDoubleClicked(const QModelIndex & /*index*/) +{ + if (!okButton->isVisible()) + return; + + okButtonClicked(); +} + +QString WatermarksWindow::watermarkName() const +{ + Watermark *watermark = selectedWatermark(); + return watermark ? QString::fromUtf8(watermark->name().c_str()) : QString(); +} + +void WatermarksWindow::setWatermarkName(const QString &name) +{ + QModelIndex index = watermarks_model->indexByName(name); + watermarkTree->setCurrentIndex(index); + if (index.isValid()) + watermarkTree->scrollTo(index, QAbstractItemView::PositionAtTop); +} + +std::map<Watermark*, size_t> WatermarksWindow::internalScanWatermarks(IFile *file) +{ + std::map<Watermark*, size_t> res; + try { + res = file->SearchWatermarks(*watermarks_model->core()->watermark_manager()); + } catch(canceled_error &error) { + file->Notify(mtWarning, NULL, error.what()); + } catch(std::runtime_error &error) { + file->Notify(mtError, NULL, error.what()); + } + return res; +} + +void WatermarksWindow::scanButtonClicked() +{ + if (fileButton->isChecked()) { + if (fileNameEdit->text().isEmpty()) { + MessageDialog::critical(this, QString::fromUtf8(language[lsFileNameNotSpecified].c_str()), QMessageBox::Ok); + fileNameEdit->setFocus(); + return; + } + } else { + if (processEdit->currentIndex() == -1) { + MessageDialog::critical(this, QString::fromUtf8(language[lsProcessNotSpecified].c_str()), QMessageBox::Ok); + processEdit->setFocus(); + return; + } + if (moduleEdit->currentIndex() == -1) { + MessageDialog::critical(this, QString::fromUtf8(language[lsModuleNotSpecified].c_str()), QMessageBox::Ok); + moduleEdit->setFocus(); + return; + } + } + + scanModel->clear(); + std::auto_ptr<IFile> file; + GUILog log; + + if (fileButton->isChecked()) { + std::string fileName = fileNameEdit->text().toUtf8().data(); + std::auto_ptr<IFile> files[] = { + std::auto_ptr<IFile>(new PEFile(qobject_cast<ILog*>(&log))) + , std::auto_ptr<IFile>(new MacFile(qobject_cast<ILog*>(&log))) + , std::auto_ptr<IFile>(new ELFFile(qobject_cast<ILog*>(&log))) + , std::auto_ptr<IFile>(new IFile(qobject_cast<ILog*>(&log))) + }; + for (size_t i = 0; i < _countof(files); i++) { + + OpenStatus status = files[i]->Open(fileName.c_str(), foRead | foHeaderOnly); + if (status == osSuccess) { + file = files[i]; + break; + } + + if (status == osOpenError) { + MessageDialog::critical(this, QString::fromUtf8(string_format(language[lsOpenFileError].c_str(), fileName.c_str()).c_str()), QMessageBox::Ok); + break; + } else if (status != osUnknownFormat) { + LangString message_id; + switch (status) { + case osUnsupportedCPU: + message_id = lsFileHasUnsupportedProcessor; + break; + case osUnsupportedSubsystem: + message_id = lsFileHasUnsupportedSubsystem; + break; + default: + message_id = lsFileHasIncorrectFormat; + break; + } + if (MessageDialog::warning(this, QString::fromUtf8(string_format(language[message_id].c_str(), fileName.c_str(), "").append("\n").append(language[lsContinue]).append("?").c_str()), QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes) + break; + } + } + } else { + QVariant process = processEdit->itemData(processEdit->currentIndex()); + QVariant module = moduleEdit->itemData(moduleEdit->currentIndex()); + std::string moduleName = moduleEdit->currentText().toUtf8().data(); + file.reset(new IFile(qobject_cast<ILog*>(&log))); + if (!file->OpenModule(process.toUInt(), reinterpret_cast<HMODULE>(module.toULongLong()))) { + MessageDialog::critical(this, QString::fromUtf8(string_format(language[lsOpenModuleError].c_str(), moduleName.c_str()).c_str()), QMessageBox::Ok); + } + } + + if (file.get()) { + QFutureWatcher<std::map<Watermark*, size_t>> watcher; + ProgressDialog progress(this); + + connect(&watcher, SIGNAL(finished()), &progress, SLOT(reject())); + connect(&progress, SIGNAL(cancel()), &log, SLOT(cancel())); + connect(&log, SIGNAL(notify(MessageType, IObject *, const QString &)), &progress, SLOT(notify(MessageType, IObject *, const QString &))); + connect(&log, SIGNAL(startProgress(const QString &, unsigned long long)), &progress, SLOT(startProgress(const QString &, unsigned long long))); + connect(&log, SIGNAL(stepProgress(unsigned long long)), &progress, SLOT(stepProgress(unsigned long long))); + + watcher.setFuture(QtConcurrent::run(this, &WatermarksWindow::internalScanWatermarks, file.get())); + progress.exec(); + watcher.waitForFinished(); + scanModel->setWatermarkData(watcher.result()); + } +} + +void WatermarksWindow::addClicked() +{ + WatermarkDialog dialog(watermarks_model->manager(), this); + + if (dialog.exec() == QDialog::Accepted) { + watermarkFilter->clear(); + Watermark *watermark = dialog.watermark(); + watermarkTree->setCurrentIndex(watermarks_model->objectToIndex(watermark)); + } +} + +void WatermarksWindow::delClicked() +{ + Watermark *watermark = selectedWatermark(); + if (!watermark) + return; + + int res; + if (watermark->use_count()) { + res = MessageDialog::warning(this, QString("%1.\n%2?").arg(QString::fromUtf8(string_format(language[lsWatermarkIsUsed].c_str(), watermark->name().c_str()).c_str())).arg(QString(QString::fromUtf8(language[lsDeleteWatermark].c_str()))), QMessageBox::Yes | QMessageBox::No); + } else { + res = MessageDialog::question(this, QString(QString::fromUtf8(language[lsDeleteWatermark].c_str()) + "?"), QMessageBox::Yes | QMessageBox::No); + } + if (res == QMessageBox::Yes) + delete watermark; +} + +void WatermarksWindow::renameClicked() +{ + QTreeView *tree_view = currentTreeView(); + tree_view->edit(tree_view->currentIndex()); +} + +void WatermarksWindow::blockClicked() +{ + Watermark *watermark = selectedWatermark(); + if (!watermark) + return; + + watermark->set_enabled(!watermark->enabled()); +} + +void WatermarksWindow::fileButtonClicked() +{ + fileNameLabel->setEnabled(true); + fileNameEdit->setEnabled(true); + processLabel->setEnabled(false); + processEdit->setEnabled(false); + moduleLabel->setEnabled(false); + moduleEdit->setEnabled(false); + + fileNameEdit->setFocus(); + fileNameEdit->selectAll(); +} + +void WatermarksWindow::processButtonClicked() +{ + fileNameLabel->setEnabled(false); + fileNameEdit->setEnabled(false); + processLabel->setEnabled(true); + processEdit->setEnabled(true); + moduleLabel->setEnabled(true); + moduleEdit->setEnabled(true); + + processEdit->setFocus(); + processEdit->lineEdit()->selectAll(); +} + +void WatermarksWindow::processEditDropDown() +{ +#ifndef VMP_GNU + if (!debugPrivilegeEnabled) { + HANDLE token; + if (OpenProcessToken(INVALID_HANDLE_VALUE, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &token)) { + LUID value; + if (LookupPrivilegeValueA(NULL, "SeDebugPrivilege", &value)) { + TOKEN_PRIVILEGES privileges; + privileges.PrivilegeCount = 1; + privileges.Privileges[0].Luid = value; + privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + debugPrivilegeEnabled = !!(AdjustTokenPrivileges(token, FALSE, &privileges, sizeof(privileges), NULL, NULL)); + } + CloseHandle(token); + } + } +#endif + + processEditLocked = true; + + QString oldText = processEdit->currentText(); + processEdit->clear(); + processEdit->setCurrentIndex(-1); + + std::vector<PROCESS_ITEM> processes = os::EnumProcesses(); + for (size_t i = 0; i < processes.size(); i++) { + processEdit->addItem( + QString("[%1] ").arg(processes[i].id) + QString::fromUtf8(processes[i].name.c_str()), + QVariant(static_cast<qulonglong>(processes[i].id))); + } + + processEdit->setCurrentIndex(processEdit->findText(oldText)); + if (processEdit->currentIndex() == -1) + moduleEdit->clear(); + + processEditLocked = false; +} + +void WatermarksWindow::processEditChanged() +{ + if (processEditLocked) + return; + + moduleEdit->clear(); + int i = processEdit->currentIndex(); + if (i == -1) + return; + + QVariant data = processEdit->itemData(i); + std::vector<MODULE_ITEM> modules = os::EnumModules(data.toInt()); + for (size_t i = 0; i < modules.size(); i++) { + + moduleEdit->addItem( + QString::fromUtf8(modules[i].name.c_str()) +#ifdef __unix__ // ìîæåò áûòü ìíîãî ñòðîê äëÿ îäíîãî ôàéëà ïî ðàçíûì àäðåñàì (addr === HANDLE) + + QString(" @%1").arg((uint64_t)modules[i].handle, sizeof(void *) * 2, 16, QLatin1Char('0')).toUpper() +#endif + , + QVariant(reinterpret_cast<qulonglong>(modules[i].handle))); + } + + if (moduleEdit->count()) + moduleEdit->setCurrentIndex(0); +} + +void WatermarksWindow::contextMenuRequested(const QPoint &p) +{ + contextMenu->exec(watermarkTree->viewport()->mapToGlobal(p)); +} + +void WatermarksWindow::helpClicked() +{ + HelpBrowser::showTopic(tabBar->currentIndex() == 0 ? "watermarks::setup" : "watermarks::search"); +}
\ No newline at end of file diff --git a/VMProtect/watermarks_window.h b/VMProtect/watermarks_window.h new file mode 100644 index 0000000..f5c6bf7 --- /dev/null +++ b/VMProtect/watermarks_window.h @@ -0,0 +1,66 @@ +#ifndef WATERMARKS_WINDOW_H +#define WATERMARKS_WINDOW_H + +class WatermarksWindow : public QDialog +{ + Q_OBJECT +public: + WatermarksWindow(bool selectMode, QWidget *parent = NULL); + ~WatermarksWindow(); + static void setModel(WatermarksModel *model) { watermarks_model = model; } + QString watermarkName() const; + void setWatermarkName(const QString &name); +private slots: + void addClicked(); + void delClicked(); + void renameClicked(); + void blockClicked(); + void watermarkSearchChanged(); + void watermarkIndexChanged(); + void itemDoubleClicked(const QModelIndex &index); + void okButtonClicked(); + void scanButtonClicked(); + void watermarkNodeUpdated(ProjectNode *node); + void watermarkNodeRemoved(ProjectNode *node); + void fileButtonClicked(); + void processButtonClicked(); + void processEditDropDown(); + void processEditChanged(); + void contextMenuRequested(const QPoint &p); + void helpClicked(); +private: + std::map<Watermark*, size_t> internalScanWatermarks(IFile *file); + static WatermarksModel *watermarks_model; + ProjectNode *currentNode() const; + Watermark *selectedWatermark() const; + QTreeView *currentTreeView() const; + + QTabWidget *tabBar; + QAction *addAct; + QAction *renameAct; + QAction *delAct; + QAction *blockAct; + QTreeView *watermarkTree; + QPushButton *okButton; + QToolButton *addButton; + SearchLineEdit *watermarkFilter; + QTreeView *searchTree; + SearchModel *searchModel; + WatermarkScanModel *scanModel; + FileNameEdit *fileNameEdit; + QStackedWidget *pagePanel; + QRadioButton *fileButton; + QRadioButton *processButton; + QLabel *fileNameLabel; + QLabel *processLabel; + QLabel *moduleLabel; + EnumEdit *processEdit; + EnumEdit *moduleEdit; + bool processEditLocked; +#ifndef VMP_GNU + bool debugPrivilegeEnabled; +#endif + QMenu *contextMenu; +}; + +#endif diff --git a/VMProtect/widgets.cc b/VMProtect/widgets.cc new file mode 100644 index 0000000..bea368d --- /dev/null +++ b/VMProtect/widgets.cc @@ -0,0 +1,1622 @@ +#include "../core/objects.h" +#include "../core/lang.h" +#include "widgets.h" +#include "moc/moc_widgets.cc" +#include "models.h" +#include "watermarks_window.h" +#include "application.h" + +#ifdef __APPLE__ +#include <CoreFoundation/CoreFoundation.h> +#endif + +/** + * SearchLineEdit + */ + +SearchLineEdit::SearchLineEdit(QWidget *parent) + : ButtonLineEdit(parent) +{ + button()->setIcon(QIcon(":/images/search.png")); + setPlaceholderText(language[lsSearch].c_str()); + + connect(this, SIGNAL(textChanged(const QString&)), this, SLOT(updateButton(const QString&))); +} + +void SearchLineEdit::updateButton(const QString& text) +{ + QIcon icon = text.isEmpty() ? QIcon(":/images/search.png") : QIcon(":/images/cancel.png"); + button()->setIcon(icon); +} + +void SearchLineEdit::mouseDoubleClickEvent(QMouseEvent *e) +{ + LineEdit::mouseDoubleClickEvent(e); +} + +void SearchLineEdit::buttonClicked() +{ + clear(); +} + +/** + * LineEditHelper + */ + +LineEditHelper::LineEditHelper(QWidget * parent) + : QLineEdit(parent) +{ + +} + +void LineEditHelper::mouseDoubleClickEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + emit doubleClicked(); +} + +/** + * EnumEdit + */ + +EnumEdit::EnumEdit(QWidget * parent, const QStringList &items) + : QComboBox(parent) +{ + setInsertPolicy(QComboBox::NoInsert); + LineEditHelper *edit = new LineEditHelper(this); + setLineEdit(edit); + connect(edit, SIGNAL(doubleClicked()), this, SLOT(editDoubleClicked())); + + addItems(items); +} + +void EnumEdit::keyPressEvent(QKeyEvent *event) +{ + QString text = event->text(); + if (!text.isEmpty()) { + int i = findText(text.left(1), Qt::MatchStartsWith); + if (i != -1) { + setCurrentIndex(i); + lineEdit()->selectAll(); + return; + } + } + QComboBox::keyPressEvent(event); +} + +void EnumEdit::showPopup() +{ + emit dropDown(); + QComboBox::showPopup(); +} + +void EnumEdit::editDoubleClicked() +{ + int i = currentIndex() + 1; + if (i >= count()) + i = 0; + setCurrentIndex(i); +} + +/** + * BoolEdit + */ + +BoolEdit::BoolEdit(QWidget * parent) + : EnumEdit(parent, QStringList() << QString::fromUtf8(language[lsNo].c_str()) << QString::fromUtf8(language[lsYes].c_str())) +{ + connect(this, SIGNAL(currentIndexChanged(int)), this, SLOT(slotCurrentIndexChanged(int))); +} + +void BoolEdit::slotCurrentIndexChanged(int value) +{ + emit toggled(value == 1); +} + +/** + * StringListEdit + */ + +StringListEdit::StringListEdit(QWidget * parent) + : QPlainTextEdit(parent) +{ + connect(this, SIGNAL(textChanged()), this, SLOT(slotTextChanged())); +} + +void StringListEdit::slotTextChanged() +{ + emit textChanged(toPlainText()); +} + +/** + * ButtonLineEdit + */ + +ButtonLineEdit::ButtonLineEdit(QWidget *parent) + : LineEdit(parent) +{ + button_ = new QToolButton(this); + button_->setToolButtonStyle(Qt::ToolButtonIconOnly); + button_->setIcon(QIcon(":/images/browse.png")); + QSize sz = sizeHint(); + int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this); + button_->resize(QSize(sz.height() - frameWidth * 2, sz.height() - frameWidth * 2)); + button_->setCursor(Qt::ArrowCursor); + connect(button_, SIGNAL(clicked()), this, SLOT(buttonClicked())); +} + +void ButtonLineEdit::resizeEvent(QResizeEvent *) +{ + QSize sz = button_->size(); + int frameWidth = style()->pixelMetric(QStyle::PM_DefaultFrameWidth, 0, this); + button_->move(rect().right() - sz.width(), rect().top() + frameWidth); +} + +void ButtonLineEdit::mouseDoubleClickEvent(QMouseEvent *e) +{ + if (e->button() == Qt::LeftButton) { + e->accept(); + buttonClicked(); + return; + } + + LineEdit::mouseDoubleClickEvent(e); +} + +/** + * FileDialog + */ + +QString FileDialog::defaultPath_ = QString(); + +QString FileDialog::getOpenFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) +{ + QString result = QFileDialog::getOpenFileName(parent, caption, dir, filter, selectedFilter, options); + if (!result.isEmpty()) { + result = QDir::toNativeSeparators(result); + defaultPath_ = QFileInfo(result).path(); + } + return result; +} + +QString FileDialog::getSaveFileName(QWidget *parent, const QString &caption, const QString &dir, const QString &filter, QString *selectedFilter, QFileDialog::Options options) +{ + QString result = QFileDialog::getSaveFileName(parent, caption, dir, filter, selectedFilter, options); + if (!result.isEmpty()) { + result = QDir::toNativeSeparators(result); + defaultPath_ = QFileInfo(result).path(); + } + return result; +} + +/** + * FileNameEdit + */ + +FileNameEdit::FileNameEdit(QWidget *parent) + : ButtonLineEdit(parent), saveMode_(false) +{ + +} + +void FileNameEdit::buttonClicked() +{ + QDir dir(relativePath_); + + // to prevent self-destroy while QFileDialog-ing + QIntValidator invalid(1, 0); + setValidator(&invalid); + QString fileName = saveMode_ ? FileDialog::getSaveFileName(this, QString::fromUtf8(language[lsSave].c_str()), dir.absoluteFilePath(text()), filter_) + : FileDialog::getOpenFileName(this, QString::fromUtf8(language[lsOpen].c_str()), dir.absoluteFilePath(text()), filter_); + setValidator(NULL); + if (fileName.isEmpty()) + return; + + if (!relativePath_.isEmpty()) { + QString tmp = dir.relativeFilePath(fileName); + if (tmp.mid(0, 2) != "..") + fileName = tmp; + } + setText(fileName); +} + +bool FileNameEdit::event(QEvent *e) +{ + if(e->type() == QEvent::DeferredDelete && validator()) + { + // to prevent self-destroy while QFileDialog-ing + return true; + } + return ButtonLineEdit::event(e); +} + +/** + * WatermarkEdit + */ + +WatermarkEdit::WatermarkEdit(QWidget *parent) + : ButtonLineEdit(parent) +{ + +} + +void WatermarkEdit::buttonClicked() +{ + WatermarksWindow dialog(true, this); + QString watermarkName = text(); + if (!watermarkName.isEmpty()) + dialog.setWatermarkName(watermarkName); + if (dialog.exec() == QDialog::Accepted) + setText(dialog.watermarkName()); +} + +/** + * ScriptEdit + */ + +static const char *keywords[] = { + "sand break do else elseif end false for function goto if in local nil not or repeat return then true until while", + "_ENV _G _VERSION assert collectgarbage dofile error getfenv getmetatable ipairs load loadfile loadstring module next pairs pcall print rawequal rawget rawlen rawset require select setfenv setmetatable tonumber tostring type unpack xpcall string table math bit32 coroutine io os debug package __index __newindex __call __add __sub __mul __div __mod __pow __unm __concat __len __eq __lt __le __gc __mode", + "byte char dump find format gmatch gsub len lower match rep reverse sub upper abs acos asin atan atan2 ceil cos cosh deg exp floor fmod frexp ldexp log log10 max min modf pow rad random randomseed sin sinh sqrt tan tanh arshift band bnot bor btest bxor extract lrotate lshift replace rrotate rshift shift string.byte string.char string.dump string.find string.format string.gmatch string.gsub string.len string.lower string.match string.rep string.reverse string.sub string.upper table.concat table.insert table.maxn table.pack table.remove table.sort table.unpack math.abs math.acos math.asin math.atan math.atan2 math.ceil math.cos math.cosh math.deg math.exp math.floor math.fmod math.frexp math.huge math.ldexp math.log math.log10 math.max math.min math.modf math.pi math.pow math.rad math.random math.randomseed math.sin math.sinh math.sqrt math.tan math.tanh bit32.arshift bit32.band bit32.bnot bit32.bor bit32.btest bit32.bxor bit32.extract bit32.lrotate bit32.lshift bit32.replace bit32.rrotate bit32.rshift", + "close flush lines read seek setvbuf write clock date difftime execute exit getenv remove rename setlocale time tmpname coroutine.create coroutine.resume coroutine.running coroutine.status coroutine.wrap coroutine.yield io.close io.flush io.input io.lines io.open io.output io.popen io.read io.tmpfile io.type io.write io.stderr io.stdin io.stdout os.clock os.date os.difftime os.execute os.exit os.getenv os.remove os.rename os.setlocale os.time os.tmpname debug.debug debug.getfenv debug.gethook debug.getinfo debug.getlocal debug.getmetatable debug.getregistry debug.getupvalue debug.getuservalue debug.setfenv debug.sethook debug.setlocal debug.setmetatable debug.setupvalue debug.setuservalue debug.traceback debug.upvalueid debug.upvaluejoin package.cpath package.loaded package.loaders package.loadlib package.path package.preload package.seeall", +}; + +ScriptEdit::ScriptEdit(QWidget *parent) + : ScintillaEditBase(parent) +{ + setFrameShape(StyledPanel); + setFrameShadow(Sunken); + + send(SCI_SETCODEPAGE, SC_CP_UTF8); + send(SCI_SETLEXER, SCLEX_LUA); + + send(SCI_SETMARGINWIDTHN, 0, 40); + send(SCI_SETMARGINWIDTHN, 1, 0); + send(SCI_SETMARGINWIDTHN, 2, 18); + send(SCI_SETMARGINTYPEN, 2, SC_MARGIN_SYMBOL); + send(SCI_SETMARGINMASKN, 2, SC_MASK_FOLDERS); + send(SCI_SETMARGINSENSITIVEN, 2, 1); + + send(SCI_STYLESETFORE, STYLE_LINENUMBER, 0x808080); + send(SCI_STYLESETBACK, STYLE_LINENUMBER, 0xFFFFFF); + + send(SCI_SETFOLDMARGINCOLOUR, true, 0xFFFFFF); + send(SCI_SETFOLDMARGINHICOLOUR, true, 0xFFFFFF);//xE9E9E9); + + send(SCI_SETPROPERTY, (sptr_t)"fold", (sptr_t)"1"); + send(SCI_SETPROPERTY, (sptr_t)"fold.compact", (sptr_t)"0"); + send(SCI_SETFOLDFLAGS, SC_FOLDFLAG_LINEAFTER_CONTRACTED); + send(SCI_SETAUTOMATICFOLD, SC_AUTOMATICFOLD_SHOW | SC_AUTOMATICFOLD_CLICK | SC_AUTOMATICFOLD_CHANGE); + + send(SCI_SETSCROLLWIDTHTRACKING, true); + send(SCI_SETSCROLLWIDTH, 1); + + send(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPEN, SC_MARK_BOXMINUS); + send(SCI_MARKERDEFINE, SC_MARKNUM_FOLDER, SC_MARK_BOXPLUS); + send(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERSUB, SC_MARK_VLINE); + send(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERTAIL, SC_MARK_LCORNER); + send(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEREND, SC_MARK_BOXPLUSCONNECTED); + send(SCI_MARKERDEFINE, SC_MARKNUM_FOLDEROPENMID, SC_MARK_BOXMINUSCONNECTED); + send(SCI_MARKERDEFINE, SC_MARKNUM_FOLDERMIDTAIL, SC_MARK_TCORNER); + + send(SCI_MARKERSETFORE, SC_MARKNUM_FOLDEROPEN, 0xFFFFFF); + send(SCI_MARKERSETBACK, SC_MARKNUM_FOLDEROPEN, 0x808080); + send(SCI_MARKERSETFORE, SC_MARKNUM_FOLDER, 0xFFFFFF); + send(SCI_MARKERSETBACK, SC_MARKNUM_FOLDER, 0x808080); + send(SCI_MARKERSETFORE, SC_MARKNUM_FOLDERSUB, 0xFFFFFF); + send(SCI_MARKERSETBACK, SC_MARKNUM_FOLDERSUB, 0x808080); + send(SCI_MARKERSETFORE, SC_MARKNUM_FOLDERTAIL, 0xFFFFFF); + send(SCI_MARKERSETBACK, SC_MARKNUM_FOLDERTAIL, 0x808080); + send(SCI_MARKERSETFORE, SC_MARKNUM_FOLDEREND, 0xFFFFFF); + send(SCI_MARKERSETBACK, SC_MARKNUM_FOLDEREND, 0x808080); + send(SCI_MARKERSETFORE, SC_MARKNUM_FOLDEROPENMID, 0xFFFFFF); + send(SCI_MARKERSETBACK, SC_MARKNUM_FOLDEROPENMID, 0x808080); + send(SCI_MARKERSETFORE, SC_MARKNUM_FOLDERMIDTAIL, 0xFFFFFF); + send(SCI_MARKERSETBACK, SC_MARKNUM_FOLDERMIDTAIL, 0x808080); + + for (size_t style = 0; style < _countof(keywords); style++) { + send(SCI_SETKEYWORDS, style, reinterpret_cast<sptr_t>(keywords[style])); + } + + send(SCI_STYLESETFONT, STYLE_DEFAULT, (sptr_t)MONOSPACE_FONT_FAMILY); + int fontSize = int(1100 * Application::devicePixelRatio() + 0.5); + send(SCI_STYLESETSIZEFRACTIONAL, STYLE_DEFAULT, fontSize); + + send(SCI_STYLESETFORE, SCE_LUA_COMMENT, 0x008000); + send(SCI_STYLESETFORE, SCE_LUA_COMMENTLINE, 0x008000); + send(SCI_STYLESETFORE, SCE_LUA_COMMENTDOC, 0x808000); + send(SCI_STYLESETFORE, SCE_LUA_NUMBER, 0x0080FF); + send(SCI_STYLESETFORE, SCE_LUA_WORD, 0xFF0000); + send(SCI_STYLESETFORE, SCE_LUA_STRING, 0x1515A3); + send(SCI_STYLESETFORE, SCE_LUA_CHARACTER, 0x1515A3); + send(SCI_STYLESETFORE, SCE_LUA_LITERALSTRING, 0x1515A3); + send(SCI_STYLESETFORE, SCE_LUA_PREPROCESSOR, 0x004080); + send(SCI_STYLESETFORE, SCE_LUA_OPERATOR, 0x800000); + send(SCI_STYLESETFORE, SCE_LUA_WORD2, 0xC08000); + send(SCI_STYLESETFORE, SCE_LUA_WORD3, 0xC08000); + send(SCI_STYLESETFORE, SCE_LUA_WORD4, 0xC08000); + + send(SCI_INDICSETSTYLE, 0, INDIC_STRAIGHTBOX); +} + +void ScriptEdit::setText(const QString &text) +{ + send(SCI_SETTEXT, 0, reinterpret_cast<sptr_t>(text.toUtf8().constData())); + send(SCI_EMPTYUNDOBUFFER); +} + +QString ScriptEdit::text() const +{ + QString res; + int len = send(SCI_GETTEXTLENGTH); + if (len) { + char *buf = new char[len + 1]; + send(SCI_GETTEXT, len + 1, reinterpret_cast<sptr_t>(buf)); + res = QString().fromUtf8(buf); + delete [] buf; + } + return res; +} + +void ScriptEdit::redo() +{ + send(SCI_REDO); +} + +void ScriptEdit::undo() +{ + send(SCI_UNDO); +} + +void ScriptEdit::copy() +{ + send(SCI_COPY); +} + +void ScriptEdit::cut() +{ + send(SCI_CUT); +} + +void ScriptEdit::paste() +{ + send(SCI_PASTE); +} + +bool ScriptEdit::canRedo() const +{ + return send(SCI_CANREDO); +} + +bool ScriptEdit::canUndo() const +{ + return send(SCI_CANUNDO); +} + +bool ScriptEdit::canPaste() const +{ + return send(SCI_CANPASTE); +} + +bool ScriptEdit::hasSelection() const +{ + return (send(SCI_GETSELECTIONSTART) != send(SCI_GETSELECTIONEND)); +} + +void ScriptEdit::del() +{ + send(SCI_CLEAR); +} + +QPoint ScriptEdit::currentPos() const +{ + return QPoint(send(SCI_GETCOLUMN, send(SCI_GETCURRENTPOS)), send(SCI_LINEFROMPOSITION, send(SCI_GETCURRENTPOS))); +}; + +bool ScriptEdit::getOverType() const +{ + return send(SCI_GETOVERTYPE); +}; + +void ScriptEdit::setOverType(bool value) const +{ + send(SCI_SETOVERTYPE, value); +}; + +void ScriptEdit::maintainIndentation(int ch) +{ + int eolMode = int(send(SCI_GETEOLMODE)); + int curLine = int(send(SCI_LINEFROMPOSITION, send(SCI_GETCURRENTPOS))); + int prevLine = curLine - 1; + int indentAmountPrevLine = 0; + //int tabWidth = send(SCI_GETTABWIDTH); + + if (((eolMode == SC_EOL_CRLF || eolMode == SC_EOL_LF) && ch == '\n') || + (eolMode == SC_EOL_CR && ch == '\r')) + { + // Search the non-empty previous line + while (prevLine >= 0 && send(SCI_LINELENGTH, prevLine) <= (eolMode == SC_EOL_CRLF ? 2 : 1)) + prevLine--; + + // Get previous line's Indent + if (prevLine >= 0) + { + indentAmountPrevLine = send(SCI_GETLINEINDENTATION, prevLine); + } + + send(SCI_SETLINEINDENTATION, curLine, indentAmountPrevLine); + send(SCI_SETEMPTYSELECTION, send(SCI_GETLINEINDENTPOSITION, curLine)); + } +} + +void ScriptEdit::hilightView() +{ + long docLen = (long)send(SCI_GETTEXTLENGTH); + //Clear marks + send(SCI_SETINDICATORCURRENT, 0); + send(SCI_INDICATORCLEARRANGE, 0, docLen); + + long selStart = (long)send(SCI_GETSELECTIONSTART); + if (selStart != (long)send(SCI_WORDSTARTPOSITION, selStart, 1)) + return; + long selEnd = (long)send(SCI_GETSELECTIONEND); + if (selEnd != (long)send(SCI_WORDENDPOSITION, selEnd, 1)) + return; + + //If nothing selected, don't mark anything + if (selStart == selEnd) + return; + + int textlen = selEnd - selStart; + char *bytes2Find = new char[textlen + 1]; + send(SCI_GETSELTEXT, 0, reinterpret_cast<sptr_t>(bytes2Find)); + + // Get the range of text visible and highlight everything in it + int firstLine = (int)send(SCI_GETFIRSTVISIBLELINE); + int nrLines = (int)send(SCI_LINESONSCREEN) + 1; + Scintilla::Sci_TextToFind ttf; + ttf.chrg.cpMin = (int)send(SCI_POSITIONFROMLINE, firstLine); + ttf.chrg.cpMax = (int)send(SCI_POSITIONFROMLINE, firstLine + nrLines + 1); + if (ttf.chrg.cpMax == -1) + ttf.chrg.cpMax = (int)docLen; + ttf.lpstrText = bytes2Find; + while (send(SCI_FINDTEXT, SCFIND_WHOLEWORD, reinterpret_cast<sptr_t>(&ttf)) != -1) + { + send(SCI_INDICATORFILLRANGE, ttf.chrgText.cpMin, textlen); + ttf.chrg.cpMin = ttf.chrgText.cpMin + 1; + if (ttf.chrg.cpMin >= ttf.chrg.cpMax) + break; + } + + delete [] bytes2Find; +} + +/** + * BinEditor + */ + +BinEditor::BinEditor(QWidget *parent) + : QAbstractScrollArea(parent), maskAllowed_(false) +{ + bytesPerLine_ = 8; + + QFont font(MONOSPACE_FONT_FAMILY, 14, QFont::Bold); +#ifdef __APPLE__ + font.setStyleStrategy(QFont::ForceIntegerMetrics); +#endif + setFont(font); + + setFocusPolicy(Qt::WheelFocus); + setFrameStyle(QFrame::Plain); + cursorPosition_ = 0; + anchorPosition_ = 0; + overwriteMode_ = false; + hexCursor_ = true; + cursorVisible_ = false; + maxLength_ = 0; + + init(); +} + +BinEditor::~BinEditor() +{ + +} + +void BinEditor::setData(const QByteArray &data) +{ + m_undoStack.empty(); + m_redoStack.empty(); + cursorPosition_ = 0; + anchorPosition_ = 0; + data_ = data; + mask_.clear(); + for (int i = 0; i < data_.size(); i++) { + mask_.append('0'); + } + changed(); +} + +void BinEditor::setValue(const QString &value) +{ + m_undoStack.empty(); + m_redoStack.empty(); + cursorPosition_ = 0; + anchorPosition_ = 0; + data_.clear(); + mask_.clear(); + insert(0, value); +} + +QString BinEditor::value() const +{ + QString res = data().toHex(); + if (maskAllowed_) { + for (int i = 0; i < mask_.size(); i++) { + uint8_t mask = mask_[i]; + if (mask & 0x10) + res[i * 2] = QChar('?'); + if (mask & 1) + res[i * 2 + 1] = QChar('?'); + } + } + return res; +} + +void BinEditor::init() +{ + QFontMetrics fm(fontMetrics()); + lineHeight_ = fm.lineSpacing(); + charWidth_ = fm.width(QChar(QLatin1Char('M'))); + margin_ = charWidth_; + addressWidth_ = charWidth_ * 4; + columnWidth_ = 2 * charWidth_ + fm.width(QChar(QLatin1Char(' '))); + textWidth_ = bytesPerLine_ * charWidth_ + charWidth_; + + numLines_ = data_.size() / bytesPerLine_ + 1; + numVisibleLines_ = viewport()->height() / lineHeight_; + + horizontalScrollBar()->setRange(0, 2 * charWidth_ + bytesPerLine_ * columnWidth_ + + addressWidth_ + textWidth_ - viewport()->width()); + horizontalScrollBar()->setPageStep(viewport()->width()); + verticalScrollBar()->setRange(0, numLines_ - numVisibleLines_); + verticalScrollBar()->setPageStep(numVisibleLines_); +} + +void BinEditor::resizeEvent(QResizeEvent *) +{ + init(); +} + +void BinEditor::changed() +{ + if (maxLength_ > 0 && data_.size() > maxLength_) + data_.resize(maxLength_); + numLines_ = data_.size() / bytesPerLine_ + 1; + verticalScrollBar()->setRange(0, numLines_ - numVisibleLines_); + setCursorPosition(cursorPosition_); + viewport()->update(); + + emit dataChanged(); +} + +void BinEditor::paintEvent(QPaintEvent *e) +{ + QPainter painter(viewport()); + const int topLine = verticalScrollBar()->value(); + const int xoffset = horizontalScrollBar()->value(); + const int x1 = -xoffset + margin_ + addressWidth_ - charWidth_/2 - 1; + const int x2 = -xoffset + margin_ + addressWidth_ + bytesPerLine_ * columnWidth_ + charWidth_/2; + painter.setPen(QColor(0xe5, 0xe5, 0xe5)); + painter.drawLine(x1, 0, x1, viewport()->height()); + painter.drawLine(x2, 0, x2, viewport()->height()); + + int selStart = qMin(anchorPosition_, cursorPosition_) / 2; + int selEnd = qMax(anchorPosition_, cursorPosition_) / 2; + + QString itemString(bytesPerLine_*3, QLatin1Char(' ')); + QChar *itemStringData = itemString.data(); + const char *hex = "0123456789abcdef"; + + painter.setPen(palette().text().color()); + const QFontMetrics &fm = painter.fontMetrics(); + int ascent = fm.ascent(); + int descent = fm.descent(); + for (int i = 0; i <= numVisibleLines_; ++i) { + int line = topLine + i; + if (line >= numLines_) + break; + + //int lineAddress = 0 + uint(line) * bytesPerLine_; + int y = i * lineHeight_ + ascent; + if (y - ascent > e->rect().bottom()) + break; + if (y + descent < e->rect().top()) + continue; + + painter.drawText(-xoffset, i * lineHeight_ + ascent, QString("%1").arg(line * bytesPerLine_, 4, 16, QChar('0'))); + + QString printable; + QRect selectionRect; + QRect printableSelectionRect; + int cursor = -1; + if (line == cursorPosition_ / (bytesPerLine_ * 2)) + cursor = cursorPosition_ % (bytesPerLine_ * 2); + for (int c = 0; c < bytesPerLine_; ++c) { + int pos = line * bytesPerLine_ + c; + if (pos >= data_.size()) { + while (c < bytesPerLine_) { + itemStringData[c*3] = itemStringData[c*3+1] = QLatin1Char(' '); + printable += QLatin1Char(' '); + ++c; + } + break; + } + + unsigned char value = data_[pos]; + unsigned char mask = mask_[pos]; + itemStringData[c*3] = (mask & 0x10) ? QLatin1Char('?') : QLatin1Char(hex[value >> 4]); + itemStringData[c*3+1] = (mask & 1) ? QLatin1Char('?') : QLatin1Char(hex[value & 0xf]); + + QChar qc(mask ? '?' : value); + if (qc.unicode() >= 127 || !qc.isPrint()) + qc = 0xB7; + printable += qc; + + if (selStart != selEnd && pos >= selStart && pos < selEnd) { + if (hexCursor_) { + int item_x = -xoffset + margin_ + addressWidth_ + c * columnWidth_; + selectionRect |= QRect(item_x - charWidth_/2, y - ascent, columnWidth_, lineHeight_); + } else { + int item_x = -xoffset + margin_ + addressWidth_ + bytesPerLine_ * columnWidth_ + charWidth_ + c * charWidth_; + printableSelectionRect |= QRect(item_x, y - ascent, charWidth_, lineHeight_); + } + } + } + int x = -xoffset + margin_ + addressWidth_; + painter.drawText(x, y, itemString); + + if (!selectionRect.isEmpty()) { + painter.save(); + painter.fillRect(selectionRect, palette().highlight()); + painter.setPen(palette().highlightedText().color()); + painter.setClipRect(selectionRect); + painter.drawText(x, y, itemString); + painter.restore(); + } + + int text_x = -xoffset + margin_ + addressWidth_ + bytesPerLine_ * columnWidth_ + charWidth_; + painter.drawText(text_x, y, printable); + + if (!printableSelectionRect.isEmpty()) { + painter.save(); + painter.fillRect(printableSelectionRect, palette().highlight()); + painter.setPen(palette().highlightedText().color()); + painter.setClipRect(printableSelectionRect); + painter.drawText(text_x, y, printable); + painter.restore(); + } + + if (cursor >= 0 && cursorVisible_) { + int pos = cursor / 2; + if (hexCursor_) { + int c = cursor % 2; + QRect cursorRect(x + pos * columnWidth_ + c * charWidth_, y - ascent, fm.boundingRect(itemString.mid(pos * 3 + c, 1)).width() + 1, lineHeight_); + if (!overwriteMode_) + cursorRect.setWidth(1); + painter.save(); + painter.setClipRect(cursorRect); + painter.fillRect(cursorRect, palette().text().color()); + painter.setPen(palette().highlightedText().color()); + painter.drawText(x, y, itemString); + painter.restore(); + } else { + QRect cursorRect = QRect(text_x + fm.width(printable.left(pos)), y - ascent, fm.width(printable.at(pos)), lineHeight_); + if (!overwriteMode_) + cursorRect.setWidth(1); + painter.save(); + painter.setClipRect(cursorRect); + painter.fillRect(cursorRect, palette().text().color()); + painter.setPen(palette().highlightedText().color()); + painter.drawText(text_x, y, printable); + painter.restore(); + } + } + } +} + +int BinEditor::posAt(const QPoint &pos) const +{ + int xoffset = horizontalScrollBar()->value(); + int x = xoffset + pos.x() - margin_ - addressWidth_; + int topLine = verticalScrollBar()->value(); + int line = pos.y() / lineHeight_; + int column = (qMax(0,x + charWidth_)) / columnWidth_; + int c = (x - column * columnWidth_ > charWidth_) ? 1 : 0; + if (x > bytesPerLine_ * columnWidth_ + charWidth_/2) { + c = 0; + x -= bytesPerLine_ * columnWidth_ + charWidth_; + for (column = 0; column < 15; ++column) { + int posn = (topLine + line) * bytesPerLine_ + column; + if (posn < 0 || posn >= data_.size()) + break; + QChar qc(data_[posn]); + if (!qc.isPrint()) + qc = 0xB7; + x -= fontMetrics().width(qc); + if (x <= 0) + break; + } + } + + return (topLine + line) * bytesPerLine_ * 2 + column * 2 + c; +} + +bool BinEditor::inTextArea(const QPoint &pos) const +{ + int xoffset = horizontalScrollBar()->value(); + int x = xoffset + pos.x() - margin_ - addressWidth_; + return (x > bytesPerLine_ * columnWidth_ + charWidth_/2); +} + +void BinEditor::mousePressEvent(QMouseEvent *e) +{ + if (e->button() != Qt::LeftButton) + return; + MoveMode moveMode = e->modifiers() & Qt::ShiftModifier ? KeepAnchor : MoveAnchor; + setCursorPosition(posAt(e->pos()), moveMode); + setBlinkingCursorEnabled(true); + if (hexCursor_ == inTextArea(e->pos())) { + hexCursor_ = !hexCursor_; + updateLines(); + } +} + +void BinEditor::mouseMoveEvent(QMouseEvent *e) +{ + if (!(e->buttons() & Qt::LeftButton)) + return; + setCursorPosition(posAt(e->pos()), KeepAnchor); +} + +void BinEditor::setOverwriteMode(bool value) +{ + if (overwriteMode_ != value) { + overwriteMode_ = value; + updateLines(); + } +} + +void BinEditor::setCursorPosition(int pos, MoveMode moveMode) +{ + if (overwriteMode_) { + if (pos > (data_.size() * 2 - 1)) + pos = data_.size() * 2 - 1; + } else { + if (pos > (data_.size() * 2)) + pos = data_.size() * 2; + } + if (pos < 0) + return; + + int oldCursorPosition = cursorPosition_; + cursorPosition_ = pos; + if (moveMode == MoveAnchor) { + updateLines(anchorPosition_, oldCursorPosition); + anchorPosition_ = cursorPosition_; + } + + updateLines(oldCursorPosition, cursorPosition_); + ensureCursorVisible(); +} + +void BinEditor::setBlinkingCursorEnabled(bool enable) +{ + if (enable && QApplication::cursorFlashTime() > 0) + cursorBlinkTimer_.start(QApplication::cursorFlashTime() / 2, this); + else + cursorBlinkTimer_.stop(); + cursorVisible_ = enable; + + if (cursorPosition_ != anchorPosition_) + updateLines(anchorPosition_, cursorPosition_); + else + updateLines(cursorPosition_, cursorPosition_); +} + +void BinEditor::focusInEvent(QFocusEvent *e) +{ + setBlinkingCursorEnabled(true); + bool first = true; + switch (e->reason()) { + case Qt::BacktabFocusReason: + first = false; + break; + case Qt::TabFocusReason: + break; + default: + return; + } + hexCursor_ = first; +} + +void BinEditor::focusOutEvent(QFocusEvent *) +{ + setBlinkingCursorEnabled(false); +} + +void BinEditor::timerEvent(QTimerEvent *e) +{ + if (e->timerId() == cursorBlinkTimer_.timerId()) { + cursorVisible_ = !cursorVisible_; + updateLines(); + } + QAbstractScrollArea::timerEvent(e); +} + +void BinEditor::updateLines() +{ + updateLines(cursorPosition_ , cursorPosition_); +} + +void BinEditor::updateLines(int fromPosition, int toPosition) +{ + int topLine = verticalScrollBar()->value(); + int firstLine = qMin(fromPosition, toPosition) / (bytesPerLine_ * 2); + int lastLine = qMax(fromPosition, toPosition) / (bytesPerLine_ * 2); + int y = (firstLine - topLine) * lineHeight_; + int h = (lastLine - firstLine + 1 ) * lineHeight_; + + viewport()->update(0, y, viewport()->width(), h); +} + +void BinEditor::ensureCursorVisible() +{ + QRect cr = cursorRect(); + QRect vr = viewport()->rect(); + if (!vr.contains(cr)) { + if (cr.top() < vr.top()) + verticalScrollBar()->setValue(cursorPosition_ / (bytesPerLine_ * 2)); + else if (cr.bottom() > vr.bottom()) + verticalScrollBar()->setValue(cursorPosition_ / (bytesPerLine_ * 2) - numVisibleLines_ + 1); + } +} + +QRect BinEditor::cursorRect() const +{ + int topLine = verticalScrollBar()->value(); + int line = cursorPosition_ / (bytesPerLine_ * 2); + int y = (line - topLine) * lineHeight_; + int xoffset = horizontalScrollBar()->value(); + int column = cursorPosition_ % (bytesPerLine_ * 2); + int x = hexCursor_ + ? (-xoffset + margin_ + addressWidth_ + column * columnWidth_ + (cursorPosition_ & 1) * charWidth_) + : (-xoffset + margin_ + addressWidth_ + bytesPerLine_ * columnWidth_ + charWidth_ + column * charWidth_); + int w = hexCursor_ ? columnWidth_ : charWidth_; + return QRect(x, y, w, lineHeight_); +} + +void BinEditor::insert(int index, char c) +{ + data_.insert(index, c); + mask_.insert(index, '0'); + changed(); +} + +void BinEditor::insert(int index, const QString &value) +{ + QByteArray insData; + QByteArray insMask; + bool odd_digit = false; + for (int i = 0; i < value.size(); i++) { + int ch = value.at(i).unicode(); + int tmp; + int mask = 0; + if (ch >= '0' && ch <= '9') + tmp = ch - '0'; + else if (ch >= 'a' && ch <= 'f') + tmp = ch - 'a' + 10; + else if (ch >= 'A' && ch <= 'F') + tmp = ch - 'A' + 10; + else if (maskAllowed_ && ch == '?') { + tmp = 0; + mask = 1; + } else + continue; + + if (odd_digit) { + int pos = insData.size() - 1; + insData[pos] = insData[pos] | tmp; + insMask[pos] = insMask[pos] | mask; + odd_digit = false; + } else { + insData.append(tmp << 4); + insMask.append(mask << 4); + odd_digit = true; + } + } + data_.insert(index, insData); + mask_.insert(index, insMask); + changed(); +} + +void BinEditor::replace(int index, char c, char mask) +{ + data_[index] = c; + mask_[index] = mask; + changed(); +} + +void BinEditor::remove(int index, int len) +{ + data_.remove(index, len); + mask_.remove(index, len); + changed(); +} + +void BinEditor::selectAll() +{ + setCursorPosition(0); + setCursorPosition(data_.size() * 2, KeepAnchor); +} + +void BinEditor::copy() +{ + int selStart = qMin(anchorPosition_, cursorPosition_) / 2; + int selEnd = qMax(anchorPosition_, cursorPosition_) / 2; + QByteArray data = data_.mid(selStart, selEnd - selStart); + QByteArray mask = mask_.mid(selStart, selEnd - selStart); + QString res; + if (hexCursor_) { + const char * const hex = "0123456789abcdef"; + res.reserve(3 * data.size()); + for (int i = 0; i < data.size(); ++i) { + unsigned char d = data[i]; + unsigned char m = mask[i]; + res.append(QLatin1Char((m & 0x10) ? '?' : hex[d >> 4])).append(QLatin1Char((m & 1) ? '?' : hex[d & 0xf])).append(QLatin1Char(' ')); + } + res.chop(1); + } else { + for (int i = 0; i < data.size(); ++i) { + if (mask[i]) + data[i] = '?'; + } + res = QString::fromLatin1(data); + } + QClipboard *clipboard = QApplication::clipboard(); + if (clipboard) + clipboard->setText(res); +} + +void BinEditor::cut() +{ + copy(); + deleteSelection(); +} + +void BinEditor::paste() +{ + QClipboard *clipboard = QApplication::clipboard(); + if (clipboard) { + CheckPointMaker maker(this); + deleteSelectionInternal(); + QString text = clipboard->text(); + if (!hexCursor_) + text = QByteArray(text.toLatin1()).toHex(); + insert(cursorPosition_ / 2, text); + setCursorPosition(cursorPosition_ + text.size()); + } +} + +bool BinEditor::deleteSelection() +{ + CheckPointMaker maker(this); + return deleteSelectionInternal(); +} + +bool BinEditor::deleteSelectionInternal() +{ + int selStart = qMin(anchorPosition_, cursorPosition_) / 2; + int selEnd = qMax(anchorPosition_, cursorPosition_) / 2; + if (selStart == selEnd) + return false; + + remove(selStart, selEnd - selStart); + setCursorPosition(selStart * 2); + return true; +} + +void BinEditor::keyPressEvent(QKeyEvent *e) +{ + if (e == QKeySequence::SelectAll) { + selectAll(); + e->accept(); + return; + } else if (e == QKeySequence::Copy) { + copy(); + e->accept(); + return; + } else if (e == QKeySequence::Cut) { + cut(); + e->accept(); + return; + } else if (e == QKeySequence::Paste) { + paste(); + e->accept(); + return; + } else if (e == QKeySequence::Undo) { + undo(); + e->accept(); + return; + } else if (e == QKeySequence::Redo) { + redo(); + e->accept(); + return; + } + + CheckPointMaker maker(this); + MoveMode moveMode = e->modifiers() & Qt::ShiftModifier ? KeepAnchor : MoveAnchor; + int cursorStep = hexCursor_ ? 1 : 2; + switch (e->key()) { + case Qt::Key_Up: + setCursorPosition(cursorPosition_ - bytesPerLine_ * 2, moveMode); + break; + case Qt::Key_Down: + setCursorPosition(cursorPosition_ + bytesPerLine_ * 2, moveMode); + break; + case Qt::Key_Right: + setCursorPosition(cursorPosition_ + cursorStep, moveMode); + break; + case Qt::Key_Left: + setCursorPosition(cursorPosition_ - cursorStep, moveMode); + break; + case Qt::Key_PageUp: + case Qt::Key_PageDown: + { + int line = qMax(0, cursorPosition_ / (bytesPerLine_ * 2) - verticalScrollBar()->value()); + verticalScrollBar()->triggerAction(e->key() == Qt::Key_PageUp ? QScrollBar::SliderPageStepSub : QScrollBar::SliderPageStepAdd); + setCursorPosition((verticalScrollBar()->value() + line) * bytesPerLine_ + cursorPosition_ % (bytesPerLine_ * 2), moveMode); + } + break; + case Qt::Key_Home: + { + int pos; + if (e->modifiers() & Qt::ControlModifier) + pos = 0; + else + pos = cursorPosition_ - cursorPosition_ % (bytesPerLine_ * 2); + setCursorPosition(pos, moveMode); + } + break; + case Qt::Key_End: + { + int pos; + if (e->modifiers() & Qt::ControlModifier) + pos = data_.size(); + else + pos = cursorPosition_ - cursorPosition_ % (bytesPerLine_ * 2) + (bytesPerLine_ * 2 - 1); + setCursorPosition(pos, moveMode); + } + break; + case Qt::Key_Insert: + if (e->modifiers() == Qt::NoModifier) { + overwriteMode_ = !overwriteMode_; + setCursorPosition(cursorPosition_, KeepAnchor); + } + break; + case Qt::Key_Backspace: + { + if (!deleteSelectionInternal()) { + int pos = cursorPosition_ / 2; + if (pos > 0) { + setCursorPosition(cursorPosition_ - 2); + if (overwriteMode_) + replace(pos - 1, char(0)); + else + remove(pos - 1, 1); + } + } + } + break; + case Qt::Key_Escape: + e->ignore(); + return; + case Qt::Key_Delete: + { + if (!deleteSelectionInternal()) { + int pos = cursorPosition_ / 2; + if (overwriteMode_) + replace(pos, char(0)); + else + remove(pos, 1); + setCursorPosition(cursorPosition_); + } + } + break; + default: + { + QString text = e->text(); + for (int i = 0; i < text.length(); ++i) { + QChar c = text.at(i); + if (hexCursor_) { + c = c.toLower(); + int nibble = -1; + int mask = 0; + if (c.unicode() >= 'a' && c.unicode() <= 'f') + nibble = c.unicode() - 'a' + 10; + else if (c.unicode() >= '0' && c.unicode() <= '9') + nibble = c.unicode() - '0'; + else if (maskAllowed_ && c.unicode() == '?') { + mask = 1; + nibble = 0; + } + + if (nibble < 0) + continue; + + deleteSelectionInternal(); + + int pos = cursorPosition_ / 2; + if (!overwriteMode_ && cursorPosition_ % 2 == 0) + insert(pos, 0); + + if (cursorPosition_ & 1) { + replace(pos, nibble + (data_[pos] & 0xf0), mask + (mask_[pos] & 0xf0)); + setCursorPosition(cursorPosition_ + 1); + } else { + replace(pos, (nibble << 4) + (data_[pos] & 0x0f), (mask << 4) + (mask_[pos] & 0x0f)); + setCursorPosition(cursorPosition_ + 1); + } + } else { + if (c.unicode() >= 128 || !c.isPrint()) + continue; + + deleteSelectionInternal(); + + int pos = cursorPosition_ / 2; + if (!overwriteMode_) + insert(pos, 0); + + replace(pos, c.unicode()); + setCursorPosition(cursorPosition_ + 2); + } + setBlinkingCursorEnabled(true); + } + } + } + + e->accept(); +} + +bool BinEditor::event(QEvent *e) +{ + if (e->type() == QEvent::KeyPress) { + switch (static_cast<QKeyEvent*>(e)->key()) { + case Qt::Key_Tab: + if (hexCursor_) { + hexCursor_ = !hexCursor_; + setBlinkingCursorEnabled(true); + ensureCursorVisible(); + e->accept(); + return true; + } + break; + case Qt::Key_Backtab: + if (!hexCursor_) { + hexCursor_ = !hexCursor_; + setBlinkingCursorEnabled(true); + ensureCursorVisible(); + e->accept(); + return true; + } + break; + } + } + + return QAbstractScrollArea::event(e); +} + +void BinEditor::makeUndoCheckpoint(const CheckPoint &cp) +{ + m_redoStack.clear(); + m_undoStack.push(cp); +} + +void BinEditor::undo() +{ + if (!m_undoStack.isEmpty()) { + m_redoStack.push(CurrentCheckPoint()); + restoreUndoCheckpoint(m_undoStack.pop()); + } +} + +void BinEditor::redo() +{ + if (!m_redoStack.isEmpty()) { + m_undoStack.push(CurrentCheckPoint()); + restoreUndoCheckpoint(m_redoStack.pop()); + } +} + +void BinEditor::restoreUndoCheckpoint(const CheckPoint &cp) +{ + cursorPosition_ = cp.cursorPosition; + anchorPosition_ = cp.anchorPosition; + data_.clear(); + mask_.clear(); + insert(0, cp.text); +} + +void BinEditor::contextMenuEvent(QContextMenuEvent *event) +{ + if (QMenu *menu = createStandardContextMenu()) { + menu->setAttribute(Qt::WA_DeleteOnClose); + menu->popup(event->globalPos()); + } +} + +bool BinEditor::isUndoAvailable() const +{ + return !m_undoStack.isEmpty(); +} + +bool BinEditor::isRedoAvailable() const +{ + return !m_redoStack.isEmpty(); +} + +bool BinEditor::hasSelectedText() const +{ + return anchorPosition_ != cursorPosition_; +} + +QMenu *BinEditor::createStandardContextMenu() +{ + QMenu *popup = new QMenu(this); + QAction *action = 0; + + action = popup->addAction(QLineEdit::tr("&Undo")); + action->setShortcut(QKeySequence::Undo); + action->setEnabled(isUndoAvailable()); + connect(action, SIGNAL(triggered()), this, SLOT(undo())); + + action = popup->addAction(QLineEdit::tr("&Redo")); + action->setShortcut(QKeySequence::Redo); + action->setEnabled(isRedoAvailable()); + connect(action, SIGNAL(triggered()), this, SLOT(redo())); + + popup->addSeparator(); + + action = popup->addAction(QLineEdit::tr("Cu&t")); + action->setShortcut(QKeySequence::Cut); + action->setEnabled(hasSelectedText()); + connect(action, SIGNAL(triggered()), this, SLOT(cut())); + + action = popup->addAction(QLineEdit::tr("&Copy")); + action->setShortcut(QKeySequence::Copy); + action->setEnabled(hasSelectedText()); + connect(action, SIGNAL(triggered()), this, SLOT(copy())); + + action = popup->addAction(QLineEdit::tr("&Paste")); + action->setShortcut(QKeySequence::Paste); + action->setEnabled(!QApplication::clipboard()->text().isEmpty()); + connect(action, SIGNAL(triggered()), this, SLOT(paste())); + + action = popup->addAction(QLineEdit::tr("Delete")); + action->setEnabled(!isEmpty() && hasSelectedText()); + connect(action, SIGNAL(triggered()), this, SLOT(deleteSelection())); + + if (!popup->isEmpty()) + popup->addSeparator(); + + action = popup->addAction(QLineEdit::tr("Select All")); + action->setShortcut(QKeySequence::SelectAll); + action->setEnabled(!isEmpty()); + connect(action, SIGNAL(triggered()), this, SLOT(selectAll())); + + return popup; +} + +/** + * FindWidget + */ + +FindWidget::FindWidget(QWidget *parent) + : QFrame(parent) +{ + installEventFilter(this); + QHBoxLayout *hboxLayout = new QHBoxLayout(this); + QString resourcePath = QLatin1String(":/images/"); + + hboxLayout->setMargin(5); + hboxLayout->setSpacing(5); + + toolClose = new QToolButton(this); + toolClose->setIcon(QIcon(resourcePath + QLatin1String("/cancel_gray.png"))); + toolClose->setToolTip(QString::fromUtf8(language[lsClose].c_str())); + connect(toolClose, SIGNAL(clicked()), SLOT(hide())); + hboxLayout->addWidget(toolClose); + + editFind = new LineEdit(this); + hboxLayout->addWidget(editFind); + editFind->setMinimumSize(QSize(150, 0)); + connect(editFind, SIGNAL(textChanged(QString)), this, + SLOT(textChanged(QString))); + connect(editFind, SIGNAL(returnPressed()), this, SIGNAL(findNext())); + connect(editFind, SIGNAL(textChanged(QString)), this, SLOT(updateButtons())); + + toolPrevious = new QToolButton(this); + toolPrevious->setIcon(QIcon(resourcePath + QLatin1String("/previous.png"))); + toolPrevious->setToolTip(QString::fromUtf8(language[lsPrevious].c_str())); + connect(toolPrevious, SIGNAL(clicked()), this, SIGNAL(findPrevious())); + hboxLayout->addWidget(toolPrevious); + + toolNext = new QToolButton(this); + toolNext->setIcon(QIcon(resourcePath + QLatin1String("/next.png"))); + toolNext->setToolTip(QString::fromUtf8(language[lsNext].c_str())); + connect(toolNext, SIGNAL(clicked()), this, SIGNAL(findNext())); + hboxLayout->addWidget(toolNext); + + checkCase = new QCheckBox(QString::fromUtf8(language[lsCaseSensitive].c_str()), this); + hboxLayout->addWidget(checkCase); + + labelWrapped = new QLabel(this); + labelWrapped->setScaledContents(true); + labelWrapped->setTextFormat(Qt::RichText); + labelWrapped->setMinimumSize(QSize(0, 20)); + labelWrapped->setMaximumSize(QSize(105, 20)); + labelWrapped->setAlignment(Qt::AlignLeading | Qt::AlignLeft | Qt::AlignVCenter); + labelWrapped->setText("<img src=\":/images/wrap.png\"" + "> " + QString::fromUtf8(language[lsSearchWrapped].c_str())); + hboxLayout->addWidget(labelWrapped); + + QSpacerItem *spacerItem = new QSpacerItem(20, 20, QSizePolicy::Expanding, + QSizePolicy::Minimum); + hboxLayout->addItem(spacerItem); + setMinimumWidth(minimumSizeHint().width()); + labelWrapped->hide(); + + updateButtons(); +} + +FindWidget::~FindWidget() +{ +} + +void FindWidget::show() +{ + QWidget::show(); + editFind->selectAll(); + editFind->setFocus(Qt::ShortcutFocusReason); +} + +void FindWidget::showAndClear(const QString &term) +{ + show(); + editFind->setText(term); +} + +QString FindWidget::text() const +{ + return editFind->text(); +} + +bool FindWidget::caseSensitive() const +{ + return checkCase->isChecked(); +} + +void FindWidget::setPalette(bool found) +{ + editFind->setStyleSheet(found ? "" : "QLineEdit{color: #ff3c08; background: #fff6f4;}"); +} + +void FindWidget::setTextWrappedVisible(bool visible) +{ + labelWrapped->setVisible(visible); +} + +void FindWidget::updateButtons() +{ + const bool enable = !editFind->text().isEmpty(); + toolNext->setEnabled(enable); + toolPrevious->setEnabled(enable); +} + +void FindWidget::textChanged(const QString &text) +{ + emit find(text, true, true); +} + +bool FindWidget::eventFilter(QObject *object, QEvent *e) +{ + if (e->type() == QEvent::KeyPress) { + if ((static_cast<QKeyEvent*>(e))->key() == Qt::Key_Escape) { + hide(); + emit escapePressed(); + } + } + return QWidget::eventFilter(object, e); +} + +/** + * TreeViewItemDelegate + */ + +TreeViewItemDelegate::TreeViewItemDelegate(QObject *parent) + : QStyledItemDelegate(parent) +{ + +} + +void TreeViewItemDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, + const QModelIndex &index) const +{ + QStyleOptionViewItemV4 opt = option; + opt.state &= ~QStyle::State_HasFocus; + initStyleOption(&opt, index); + const QWidget *widget = opt.widget; + QStyle *style = widget ? widget->style() : QApplication::style(); + assert(style); + if (style == NULL) return; + + style->drawControl(QStyle::CE_ItemViewItem, &opt, painter, widget); + QRect textRect = style->subElementRect(QStyle::SE_ItemViewItemText, &opt, widget); + + QVariant value = index.data(Qt::Vmp::StaticTextRole); + if (value.isValid()) { + QString text = value.toString(); + + painter->save(); + value = index.data(Qt::FontRole); + if (value.canConvert<QFont>()) + painter->setFont(qvariant_cast<QFont>(value)); + else + painter->setFont(opt.font); + + const QSize textMargin( + style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, widget) + 1, 1); + if (!opt.text.isEmpty()) + opt.text += " "; + textRect.adjust(painter->fontMetrics().width(opt.text) + textMargin.width(), 0, 0, 0); + + value = index.data(Qt::Vmp::StaticColorRole); + if (value.canConvert<QBrush>()) + painter->setPen(qvariant_cast<QBrush>(value).color()); + + if (text[0] < 5) { + // branch symbols + opt.text = QChar(0x2190 + text[0].unicode() - 1); + style->drawItemText(painter, textRect, opt.displayAlignment, opt.palette, true, opt.text); + textRect.adjust(painter->fontMetrics().width(opt.text), 0, 0, 0); + text = text.mid(1); + } + opt.text = text; + style->drawItemText(painter, textRect, opt.displayAlignment, opt.palette, true, elidedText(opt.fontMetrics, textRect.width(), Qt::ElideRight, opt.text)); + painter->restore(); + } +} + +QSize TreeViewItemDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + QStyleOptionViewItemV4 opt = option; + const int border = (opt.widget->objectName().startsWith("grid") ? 1 : 0); + const int min_height = 18 * Application::stylesheetScaleFactor() + border; + + QSize ret = QStyledItemDelegate::sizeHint(option, index) + QSize(0, 2); + if(ret.height() < min_height) + ret.setHeight(min_height); + return ret; +} + +void TreeViewItemDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const +{ + bool mac; +#ifdef __APPLE__ + mac = true; +#else + mac = false; +#endif + editor->setProperty("OSX", mac); + QStyledItemDelegate::updateEditorGeometry(editor, option, index); +} + +void TreeViewItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const +{ + ProjectNode *node = static_cast<ProjectNode *>(index.internalPointer()); + if (!node) + return; + + auto ed = qobject_cast<QLineEdit *>(editor); + assert(ed); + if (ed) + ed->setText(node->text()); +} + +/** + * LogTreeView + */ + +QStyleOptionViewItem LogTreeView::viewOptions() const +{ + QStyleOptionViewItem opt = TreeView::viewOptions(); + opt.decorationPosition = QStyleOptionViewItem::Right; + return opt; +} + +/** + * QElidedAction + */ + +void ElidedAction::setFullText(const QString &text) +{ + fullText_ = text; + int screenWidth = QApplication::desktop()->screenGeometry().width(); + QString elidedText = QApplication::fontMetrics().elidedText(text, Qt::ElideMiddle, screenWidth * 0.9); + setText(elidedText); +} + +/** + * Label + */ + +Label::Label(QWidget * parent) + : QLabel(parent) +{ + +} + +void Label::mouseDoubleClickEvent(QMouseEvent *event) +{ + if (event->button() == Qt::LeftButton) + emit doubleClicked(); +} + +/** +* ToolButtonElided +*/ + +void ToolButtonElided::resizeEvent(QResizeEvent *event) +{ + elideText(event->size()); + QToolButton::resizeEvent(event); +} + +void ToolButtonElided::elideText(const QSize &widgetSize) +{ + const int width = widgetSize.width(); + if (width == 0) + return; + const int iconWidth = icon().isNull() ? 0 : (iconSize().width() + 8); + + int left, top, right, bottom; + getContentsMargins(&left, &top, &right, &bottom); + int padding = left + right + 8; + int textWidth = width - (iconWidth + padding); + + QFontMetrics fm(font()); + QString elidedText = fm.elidedText(fullText_, Qt::ElideRight, textWidth); + QToolButton::setText(elidedText); +} + +void ToolButtonElided::setText(const QString &text) +{ + fullText_ = text; + QToolButton::setText(text); +} + +/** +* DisasmView +*/ + +DisasmView::DisasmView(QWidget * parent) + : TableView(parent) +{ + +} + +void DisasmView::scrollContentsBy(int dx, int dy) +{ + TableView::scrollContentsBy(dx, dy); + viewport()->update(); +}
\ No newline at end of file diff --git a/VMProtect/widgets.h b/VMProtect/widgets.h new file mode 100644 index 0000000..069fe36 --- /dev/null +++ b/VMProtect/widgets.h @@ -0,0 +1,544 @@ +#ifndef WIDGETS_H +#define WIDGETS_H + +class HelpContentsKeySequence : public QKeySequence +{ +public: + // HelpContents = Ctrl+? in mac os X, is not working http://www.qtcentre.org/threads/57829-Shortcut-QKeySequence-HelpContents-and-Modal-Dialog + HelpContentsKeySequence() : QKeySequence(QString("F1")) {} +}; + +class LineEditHelper : public QLineEdit +{ + Q_OBJECT +public: + LineEditHelper(QWidget * parent = 0); +signals: + void doubleClicked(); +protected: + void mouseDoubleClickEvent(QMouseEvent *event); +}; + +class EnumEdit : public QComboBox +{ + Q_OBJECT +public: + EnumEdit(QWidget * parent, const QStringList &items); +signals: + void dropDown(); +private slots: + void editDoubleClicked(); +protected: + virtual void keyPressEvent(QKeyEvent *event); + virtual void showPopup(); +}; + +class BoolEdit : public EnumEdit +{ + Q_OBJECT +public: + BoolEdit(QWidget * parent = 0); + void setChecked(bool value) { setCurrentIndex(value ? 1 : 0); } + bool checked() const { return currentIndex() == 1; } +signals: + void toggled(bool value); +private slots: + void slotCurrentIndexChanged(int value); +}; + +class StringListEdit : public QPlainTextEdit +{ + Q_OBJECT +public: + StringListEdit(QWidget * parent = 0); +private slots: + void slotTextChanged(); +signals: + void textChanged(const QString &string); +}; + +class LineEdit : public QLineEdit +{ +public: + LineEdit(QWidget *parent = NULL) + : QLineEdit(parent) + { +#ifdef __APPLE__ + setAttribute(Qt::WA_MacShowFocusRect, false); +#endif + } +}; + +class ButtonLineEdit : public LineEdit +{ + Q_OBJECT +public: + ButtonLineEdit(QWidget *parent = 0); +protected: + void resizeEvent(QResizeEvent *); + void mouseDoubleClickEvent(QMouseEvent *e); + QToolButton *button() const { return button_; } +protected slots: + virtual void buttonClicked() { } +private: + QToolButton *button_; +}; + +class SearchLineEdit : public ButtonLineEdit +{ + Q_OBJECT +public: + SearchLineEdit(QWidget *parent = 0); +protected: + void mouseDoubleClickEvent(QMouseEvent *e); +protected slots: + virtual void buttonClicked(); +private slots: + void updateButton(const QString &text); +}; + +class FileDialog +{ +public: + static QString getOpenFileName(QWidget *parent = 0, + const QString &caption = QString(), + const QString &dir = QString(), + const QString &filter = QString(), + QString *selectedFilter = 0, + QFileDialog::Options options = 0); + + static QString getSaveFileName(QWidget *parent = 0, + const QString &caption = QString(), + const QString &dir = QString(), + const QString &filter = QString(), + QString *selectedFilter = 0, + QFileDialog::Options options = 0); + + static QString defaultPath() { return defaultPath_; } +private: + static QString defaultPath_; +}; + +class FileNameEdit : public ButtonLineEdit +{ + Q_OBJECT +public: + FileNameEdit(QWidget *parent = 0); + void setFilter(const QString &filter) { filter_ = filter; } + void setRelativePath(const QString &relativePath) { relativePath_ = relativePath; } + void setSaveMode(bool value) { saveMode_ = value; } +signals: + void fileOpened(const QString &value); +protected slots: + virtual void buttonClicked(); + +private: + + virtual bool event(QEvent *e); + QString filter_; + QString relativePath_; + bool saveMode_; +}; + +class WatermarkEdit : public ButtonLineEdit +{ + Q_OBJECT +public: + WatermarkEdit(QWidget *parent = 0); +protected slots: + virtual void buttonClicked(); +}; + +class ScriptEdit : public Scintilla::ScintillaEditBase +{ + Q_OBJECT +public: + ScriptEdit(QWidget *parent = 0); + void setText(const QString &text); + QString text() const; + bool canUndo() const; + bool canRedo() const; + bool canPaste() const; + bool hasSelection() const; + void del(); + QPoint currentPos() const; + bool getOverType() const; + void setOverType(bool value) const; + void maintainIndentation(int ch); + void hilightView(); +signals: + void updateUI(); +public slots: + void undo(); + void redo(); + void copy(); + void cut(); + void paste(); +}; + +class TabWidget : public QTabWidget +{ + Q_OBJECT +public: + explicit TabWidget(QWidget *parent = 0) + : QTabWidget(parent) + { +#ifdef __APPLE__ + setAttribute(Qt::WA_LayoutUsesWidgetRect, false); +#endif + } + QTabBar* tabBar() const { return QTabWidget::tabBar(); } +signals: + void resized(); +protected: + virtual void resizeEvent(QResizeEvent *e) + { + QTabWidget::resizeEvent(e); + emit resized(); + } +}; + +#define MONOSPACE_FONT_FAMILY "Courier New" + +class BinEditor : public QAbstractScrollArea +{ + Q_OBJECT +public: + BinEditor(QWidget *parent = 0); + ~BinEditor(); + void setData(const QByteArray &data); + QByteArray data() const { return data_; } + QString value() const; + void setValue(const QString &value); + enum MoveMode { + MoveAnchor, + KeepAnchor + }; + void setCursorPosition(int pos, MoveMode moveMode = MoveAnchor); + void setOverwriteMode(bool value); + bool overwriteMode() { return overwriteMode_; } + int maxLength() const { return maxLength_; } + void setMaxLength(int value) { maxLength_ = value; } + void setMaskAllowed(bool value) { maskAllowed_ = value; } + bool isEmpty() const { return data_.isEmpty(); } + bool isUndoAvailable() const; + bool isRedoAvailable() const; + bool hasSelectedText() const; +public slots: + void selectAll(); + void copy(); + void cut(); + bool deleteSelection(); + void paste(); + void undo(); + void redo(); +signals: + void dataChanged(); +protected: + struct CheckPoint { + CheckPoint(int cp = 0, int ap = 0, const QString &t = "") : cursorPosition(cp), anchorPosition(ap), text(t) {} + int cursorPosition, anchorPosition; + QString text; + }; + CheckPoint CurrentCheckPoint() const { return CheckPoint(cursorPosition_, anchorPosition_, value()); } + class CheckPointMaker + { + public: + CheckPointMaker(BinEditor *obj) : obj_(obj), original_cp_(obj->CurrentCheckPoint()) {} + ~CheckPointMaker() + { + if (obj_->value() != original_cp_.text) + obj_->makeUndoCheckpoint(original_cp_); + } + private: + BinEditor *obj_; + CheckPoint original_cp_; + }; + friend class CheckPointMaker; + void makeUndoCheckpoint(const CheckPoint &cp); + void restoreUndoCheckpoint(const CheckPoint &cp); + + void paintEvent(QPaintEvent *e); + void resizeEvent(QResizeEvent *); + void mousePressEvent(QMouseEvent *e); + void mouseMoveEvent(QMouseEvent *e); + void focusInEvent(QFocusEvent *); + void focusOutEvent(QFocusEvent *); + void timerEvent(QTimerEvent *); + void keyPressEvent(QKeyEvent *e); + bool event(QEvent *e); + void contextMenuEvent(QContextMenuEvent *); +private: + void init(); + int posAt(const QPoint &pos) const; + void updateLines(); + void updateLines(int fromPosition, int toPosition); + void setBlinkingCursorEnabled(bool enable); + void ensureCursorVisible(); + QRect cursorRect() const; + void insert(int index, char c); + void insert(int index, const QString &str); + void replace(int index, char c, char mask = 0); + void remove(int index, int len = 1); + bool inTextArea(const QPoint &pos) const; + void changed(); + bool deleteSelectionInternal(); + QMenu *createStandardContextMenu(); + + int bytesPerLine_; + int numVisibleLines_; + int lineHeight_; + int charWidth_; + int numLines_; + QByteArray data_; + QByteArray mask_; + int margin_; + int addressWidth_; + int columnWidth_; + int textWidth_; + int cursorPosition_; + int anchorPosition_; + bool cursorVisible_; + QBasicTimer cursorBlinkTimer_; + bool overwriteMode_; + bool hexCursor_; + int maxLength_; + bool maskAllowed_; + + QStack<CheckPoint> m_undoStack, m_redoStack; +}; + +namespace Qt { + namespace Vmp { + enum ItemDataRole { StaticTextRole = Qt::UserRole + 1, StaticColorRole }; + }; +} + +class TreeViewItemDelegate : public QStyledItemDelegate +{ +public: + TreeViewItemDelegate(QObject *parent = NULL); + void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + void updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &index) const; + void setEditorData(QWidget *editor, const QModelIndex &index) const; +}; + +template<class T> +class TTemplateView : public T +{ +public: + TTemplateView(QWidget *parent = NULL); + void copy(); +private: + void getIndexTexts(const QModelIndex &idx, QString *selected_text_as_html, QString *selected_text); +}; + +template<class T> +TTemplateView<T>::TTemplateView(QWidget *parent) : T(parent) +{ +#ifdef __APPLE__ + T::setAttribute(Qt::WA_MacShowFocusRect, false); +#endif + T::setItemDelegate(new TreeViewItemDelegate(this)); +} + +template<class T> +void TTemplateView<T>::getIndexTexts(const QModelIndex &idx, QString *selected_text_as_html, QString *selected_text) +{ + QString text = idx.data().toString(); + QString staticText = idx.data(Qt::Vmp::StaticTextRole).toString().replace('\x1', QChar(0x2190)).replace('\x2', QChar(0x2191)).replace('\x3', QChar(0x2192)).replace('\x4', QChar(0x2193)); + /* + if (text[0] < 5) { + // branch symbols + opt.text = QChar(0x2190 + text[0].unicode() - 1); + */ + QColor foreColorOrBlack(Qt::black); + if (staticText.length() > 0) + { + auto mdl = T::model(); + assert(mdl); + if (!mdl) + return; + QVariant foreColor = mdl->data(idx, Qt::Vmp::StaticColorRole); + if (foreColor.canConvert<QColor>()) + { + foreColorOrBlack = qvariant_cast<QColor>(foreColor); + } + if (foreColorOrBlack != QColor(Qt::black)) + { + selected_text_as_html->append(QString("%1 <SPAN style='color: rgb(%2,%3,%4);'>%5</SPAN>").arg(text.toHtmlEscaped()).arg( + foreColorOrBlack.red()).arg(foreColorOrBlack.green()).arg(foreColorOrBlack.blue()).arg( + staticText.toHtmlEscaped())); + } + else + { + selected_text_as_html->append(QString("%1 %2").arg(text.toHtmlEscaped()).arg(staticText.toHtmlEscaped())); + } + text += QString(" %1").arg(staticText); + } + else + { + selected_text_as_html->append(text.toHtmlEscaped()); + } + selected_text->append(text); +} + +template<class T> +void TTemplateView<T>::copy() +{ + QModelIndexList indexes = T::selectionModel()->selectedIndexes(); + + if (indexes.size() < 1) + return; + + std::sort(indexes.begin(), indexes.end()); + QString selected_text_as_html; + QString selected_text; + selected_text_as_html.prepend("<html><style>br{mso-data-placement:same-cell;}</style><table>"); + + QModelIndex previous; + for (int i = 0; i < indexes.size(); i++) { + QModelIndex current = indexes[i]; + if (current.row() != previous.row()) { + if (previous.isValid()) { + selected_text_as_html.append("</tr>"); + selected_text.append(QLatin1Char('\n')); + } + selected_text_as_html.append("<tr>"); + } + else { + selected_text.append(QLatin1Char('\t')); + } + + selected_text_as_html.append("<td>"); + getIndexTexts(current, &selected_text_as_html, &selected_text); + selected_text_as_html.append("</td>"); + + previous = current; + } + + if (previous.isValid()) + selected_text_as_html.append("</tr>"); + selected_text_as_html.append("</table></html>"); + + QMimeData * md = new QMimeData; + md->setHtml(selected_text_as_html); + md->setText(selected_text); + QApplication::clipboard()->setMimeData(md); +} + +typedef TTemplateView<QTreeView> TreeView; +typedef TTemplateView<QTableView> TableView; + +class LogTreeView : public TreeView +{ +public: + LogTreeView(QWidget *parent = NULL) : TreeView(parent) {} + +private: + /*virtual*/ QStyleOptionViewItem viewOptions() const; +}; + +class PushButton : public QPushButton +{ +public: + PushButton(QWidget *parent = NULL) + : QPushButton(parent) + { +#ifdef __APPLE__ + setAttribute(Qt::WA_LayoutUsesWidgetRect, true); +#endif + } + PushButton(const QString &text, QWidget *parent = NULL) + : QPushButton(text, parent) + { +#ifdef __APPLE__ + setAttribute(Qt::WA_LayoutUsesWidgetRect, true); +#endif + } +}; + +class FindWidget : public QFrame +{ + Q_OBJECT +public: + FindWidget(QWidget *parent = 0); + ~FindWidget(); + + void show(); + void showAndClear(const QString &term); + + QString text() const; + bool caseSensitive() const; + + void setPalette(bool found); + void setTextWrappedVisible(bool visible); + +signals: + void findNext(); + void findPrevious(); + void escapePressed(); + void find(const QString &text, bool forward, bool incremental); + +private slots: + void updateButtons(); + void textChanged(const QString &text); + +private: + bool eventFilter(QObject *object, QEvent *e); + +private: + QLineEdit *editFind; + QCheckBox *checkCase; + QLabel *labelWrapped; + QToolButton *toolNext; + QToolButton *toolClose; + QToolButton *toolPrevious; +}; + +class ElidedAction : public QAction +{ +private: + QString fullText_; +public: + ElidedAction(const QString &text, QObject *parent) : QAction(text, parent) {} + ElidedAction(QObject *parent) : QAction(parent) {} + + void setFullText(const QString &text); + const QString &getFullText() { return fullText_; } +}; + +class ToolButtonElided : public QToolButton +{ +private: + QString fullText_; +public: + explicit ToolButtonElided(QWidget *parent = NULL) : QToolButton(parent) {} + void resizeEvent(QResizeEvent *event); + void setText(const QString &text); + + void elideText(const QSize &widgetSize); +}; + +class Label : public QLabel +{ + Q_OBJECT +public: + Label(QWidget * parent = 0); +signals: + void doubleClicked(); +protected: + void mouseDoubleClickEvent(QMouseEvent *event); +}; + +class DisasmView : public TableView +{ + Q_OBJECT +public: + DisasmView(QWidget * parent = 0); +protected: + void scrollContentsBy(int dx, int dy) override; +}; + +#endif
\ No newline at end of file |