vinsertimagedialog.cpp 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. #include <QtWidgets>
  2. #include <QValidator>
  3. #include <QRegExp>
  4. #include "vinsertimagedialog.h"
  5. #include "utils/vutils.h"
  6. #include "vmetawordlineedit.h"
  7. #include "vdownloader.h"
  8. #include "vlineedit.h"
  9. VInsertImageDialog::VInsertImageDialog(const QString &p_title,
  10. const QString &p_imageTitle,
  11. const QString &p_imagePath,
  12. bool p_browsable,
  13. QWidget *p_parent)
  14. : QDialog(p_parent),
  15. m_browsable(p_browsable)
  16. {
  17. setupUI(p_title, p_imageTitle, p_imagePath);
  18. connect(m_imageTitleEdit, &VMetaWordLineEdit::textChanged,
  19. this, &VInsertImageDialog::handleInputChanged);
  20. if (m_browsable) {
  21. connect(m_pathEdit, &VLineEdit::editingFinished,
  22. this, &VInsertImageDialog::handlePathEditChanged);
  23. connect(browseBtn, &QPushButton::clicked,
  24. this, &VInsertImageDialog::handleBrowseBtnClicked);
  25. fetchImageFromClipboard();
  26. }
  27. handleInputChanged();
  28. }
  29. void VInsertImageDialog::setupUI(const QString &p_title,
  30. const QString &p_imageTitle,
  31. const QString &p_imagePath)
  32. {
  33. // Path.
  34. m_pathEdit = new VLineEdit(p_imagePath);
  35. m_pathEdit->setReadOnly(!m_browsable);
  36. browseBtn = new QPushButton(tr("&Browse"));
  37. browseBtn->setEnabled(m_browsable);
  38. // Title.
  39. m_imageTitleEdit = new VMetaWordLineEdit(p_imageTitle);
  40. m_imageTitleEdit->selectAll();
  41. QValidator *validator = new QRegExpValidator(QRegExp(VUtils::c_imageTitleRegExp),
  42. m_imageTitleEdit);
  43. m_imageTitleEdit->setValidator(validator);
  44. // Scale.
  45. m_widthSpin = new QSpinBox();
  46. m_widthSpin->setMinimum(1);
  47. m_widthSpin->setSingleStep(10);
  48. m_widthSpin->setSuffix(" px");
  49. connect(m_widthSpin, static_cast<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),
  50. this, [this](int p_val) {
  51. if (!m_image) {
  52. return;
  53. }
  54. int height = m_image->height() * (1.0 * p_val / m_image->width());
  55. m_imageLabel->resize(p_val, height);
  56. });
  57. // 0.1 to 2.0 -> 1 to 20.
  58. m_scaleSlider = new QSlider();
  59. m_scaleSlider->setOrientation(Qt::Horizontal);
  60. m_scaleSlider->setMinimum(1);
  61. m_scaleSlider->setMaximum(20);
  62. m_scaleSlider->setValue(10);
  63. m_scaleSlider->setSingleStep(1);
  64. m_scaleSlider->setPageStep(5);
  65. connect(m_scaleSlider, &QSlider::valueChanged,
  66. this, [this](int p_val) {
  67. if (!m_image) {
  68. return;
  69. }
  70. int width = m_image->width();
  71. qreal factor = 1.0;
  72. if (p_val != 10) {
  73. factor = p_val / 10.0;
  74. width = m_image->width() * factor;
  75. }
  76. m_widthSpin->setValue(width);
  77. m_sliderLabel->setText(QString::number(factor) + "x");
  78. });
  79. m_sliderLabel = new QLabel("1x");
  80. QGridLayout *topLayout = new QGridLayout();
  81. topLayout->addWidget(new QLabel(tr("From:")), 0, 0, 1, 1);
  82. topLayout->addWidget(m_pathEdit, 0, 1, 1, 3);
  83. topLayout->addWidget(browseBtn, 0, 4, 1, 1);
  84. topLayout->addWidget(new QLabel(tr("Title:")), 1, 0, 1, 1);
  85. topLayout->addWidget(m_imageTitleEdit, 1, 1, 1, 4);
  86. topLayout->addWidget(new QLabel(tr("Scaling width:")), 2, 0, 1, 1);
  87. topLayout->addWidget(m_widthSpin, 2, 1, 1, 1);
  88. topLayout->addWidget(m_scaleSlider, 2, 2, 1, 2);
  89. topLayout->addWidget(m_sliderLabel, 2, 4, 1, 1);
  90. topLayout->setColumnStretch(0, 0);
  91. topLayout->setColumnStretch(1, 0);
  92. topLayout->setColumnStretch(2, 1);
  93. topLayout->setColumnStretch(3, 1);
  94. topLayout->setColumnStretch(4, 0);
  95. // Ok is the default button.
  96. m_btnBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
  97. connect(m_btnBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
  98. connect(m_btnBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
  99. m_btnBox->button(QDialogButtonBox::Ok)->setProperty("SpecialBtn", true);
  100. m_imageLabel = new QLabel();
  101. m_imageLabel->setScaledContents(true);
  102. m_previewArea = new QScrollArea();
  103. m_previewArea->setBackgroundRole(QPalette::Dark);
  104. m_previewArea->setWidget(m_imageLabel);
  105. int minWidth = 512 * VUtils::calculateScaleFactor();
  106. m_previewArea->setMinimumSize(minWidth, minWidth);
  107. setImageControlsVisible(false);
  108. QVBoxLayout *mainLayout = new QVBoxLayout();
  109. mainLayout->addLayout(topLayout);
  110. mainLayout->addWidget(m_btnBox);
  111. mainLayout->addWidget(m_previewArea);
  112. setLayout(mainLayout);
  113. setWindowTitle(p_title);
  114. m_imageTitleEdit->setFocus();
  115. }
  116. void VInsertImageDialog::handleInputChanged()
  117. {
  118. QString title = m_imageTitleEdit->getEvaluatedText();
  119. QRegExp reg(VUtils::c_imageTitleRegExp);
  120. bool titleOk = reg.exactMatch(title);
  121. QPushButton *okBtn = m_btnBox->button(QDialogButtonBox::Ok);
  122. okBtn->setEnabled(titleOk && m_image);
  123. }
  124. QString VInsertImageDialog::getImageTitleInput() const
  125. {
  126. return m_imageTitleEdit->getEvaluatedText();
  127. }
  128. QString VInsertImageDialog::getPathInput() const
  129. {
  130. if (m_tempFile.isNull()) {
  131. return m_pathEdit->text();
  132. } else {
  133. return m_tempFile->fileName();
  134. }
  135. }
  136. void VInsertImageDialog::handleBrowseBtnClicked()
  137. {
  138. static QString lastPath = QDir::homePath();
  139. QString filePath = QFileDialog::getOpenFileName(this, tr("Select The Image To Be Inserted"),
  140. lastPath, tr("Images (*.png *.xpm *.jpg *.bmp *.gif *.svg)"));
  141. if (filePath.isEmpty()) {
  142. return;
  143. }
  144. // Update lastPath
  145. lastPath = QFileInfo(filePath).path();
  146. m_imageType = ImageType::LocalFile;
  147. setPath(filePath);
  148. m_imageTitleEdit->setFocus();
  149. }
  150. void VInsertImageDialog::setImage(const QImage &p_image)
  151. {
  152. if (p_image.isNull()) {
  153. m_image.clear();
  154. m_imageLabel->clear();
  155. setImageControlsVisible(false);
  156. } else {
  157. m_image.reset(new QImage(p_image));
  158. m_imageLabel->setPixmap(QPixmap::fromImage(*m_image));
  159. m_imageLabel->adjustSize();
  160. // Set the scaling widgets.
  161. m_scaleSlider->setValue(10);
  162. int width = m_image->width();
  163. m_widthSpin->setMaximum(width * 5);
  164. m_widthSpin->setValue(width);
  165. setImageControlsVisible(true);
  166. }
  167. handleInputChanged();
  168. }
  169. void VInsertImageDialog::imageDownloaded(const QByteArray &data)
  170. {
  171. setImage(QImage::fromData(data));
  172. // Try to save it to a temp file.
  173. {
  174. if (data.isEmpty()) {
  175. goto image_data;
  176. }
  177. QString format = QFileInfo(VUtils::purifyUrl(getPathInput())).suffix();
  178. if (format.isEmpty()) {
  179. goto image_data;
  180. }
  181. m_tempFile.reset(VUtils::createTemporaryFile(format));
  182. if (!m_tempFile->open()) {
  183. goto image_data;
  184. }
  185. if (m_tempFile->write(data) == -1) {
  186. goto image_data;
  187. }
  188. m_imageType = ImageType::LocalFile;
  189. m_tempFile->close();
  190. return;
  191. }
  192. image_data:
  193. m_tempFile.clear();
  194. m_imageType = ImageType::ImageData;
  195. }
  196. QImage VInsertImageDialog::getImage() const
  197. {
  198. if (!m_image) {
  199. return QImage();
  200. } else return *m_image;
  201. }
  202. void VInsertImageDialog::fetchImageFromClipboard()
  203. {
  204. if (!m_browsable || !m_pathEdit->text().isEmpty()) {
  205. return;
  206. }
  207. Q_ASSERT(!m_image);
  208. QClipboard *clipboard = QApplication::clipboard();
  209. const QMimeData *mimeData = clipboard->mimeData();
  210. QUrl url;
  211. if (mimeData->hasImage()) {
  212. QImage im = qvariant_cast<QImage>(mimeData->imageData());
  213. if (im.isNull()) {
  214. return;
  215. }
  216. setImage(im);
  217. m_imageType = ImageType::ImageData;
  218. return;
  219. } else if (mimeData->hasUrls()) {
  220. QList<QUrl> urls = mimeData->urls();
  221. if (urls.size() != 1) {
  222. return;
  223. }
  224. url = urls[0];
  225. } else if (mimeData->hasText()) {
  226. url = QUrl(mimeData->text());
  227. }
  228. if (url.isValid()) {
  229. if (url.isLocalFile()) {
  230. setPath(url.toLocalFile());
  231. } else {
  232. setPath(url.toString());
  233. }
  234. }
  235. }
  236. void VInsertImageDialog::handlePathEditChanged()
  237. {
  238. QString text = m_pathEdit->text();
  239. QUrl url = QUrl::fromUserInput(text);
  240. if (text.isEmpty() || !url.isValid()) {
  241. setImage(QImage());
  242. return;
  243. }
  244. QImage image;
  245. if (url.isLocalFile()) {
  246. image = VUtils::imageFromFile(url.toLocalFile());
  247. setImage(image);
  248. m_imageType = ImageType::LocalFile;
  249. } else {
  250. setImage(QImage());
  251. m_imageType = ImageType::ImageData;
  252. VDownloader *downloader = new VDownloader(this);
  253. connect(downloader, &VDownloader::downloadFinished,
  254. this, &VInsertImageDialog::imageDownloaded);
  255. downloader->download(url.toString());
  256. }
  257. handleInputChanged();
  258. }
  259. void VInsertImageDialog::setPath(const QString &p_path)
  260. {
  261. m_pathEdit->setText(p_path);
  262. handlePathEditChanged();
  263. }
  264. void VInsertImageDialog::setImageControlsVisible(bool p_visible)
  265. {
  266. m_widthSpin->setEnabled(p_visible);
  267. m_scaleSlider->setEnabled(p_visible);
  268. m_sliderLabel->setEnabled(p_visible);
  269. m_previewArea->setVisible(p_visible);
  270. }
  271. int VInsertImageDialog::getOverridenWidth() const
  272. {
  273. int width = m_widthSpin->value();
  274. if (m_image && m_image->width() != width) {
  275. return width;
  276. }
  277. return 0;
  278. }