|
39 | 39 | #include <QTextDocument> |
40 | 40 | #include <QMenu> |
41 | 41 | #include <QToolTip> |
| 42 | +#include <QClipboard> |
| 43 | +#include <QMimeData> |
42 | 44 | #include <QDebug> |
43 | 45 |
|
44 | 46 | #include <utility> |
@@ -2625,9 +2627,23 @@ QStringList QtSLiMScriptTextEdit::linesForRoundedSelection(QTextCursor &p_cursor |
2625 | 2627 | #endif |
2626 | 2628 | } |
2627 | 2629 |
|
| 2630 | +void QtSLiMScriptTextEdit::copyAsHTML(void) |
| 2631 | +{ |
| 2632 | + if (isEnabled()) |
| 2633 | + { |
| 2634 | + QString html = exportAsHtml(); |
| 2635 | + QClipboard *clipboard = QGuiApplication::clipboard(); |
| 2636 | + QMimeData *mimeData = new QMimeData; |
| 2637 | + |
| 2638 | + mimeData->setHtml(html); |
| 2639 | + mimeData->setText(html); |
| 2640 | + clipboard->setMimeData(mimeData); |
| 2641 | + } |
| 2642 | +} |
| 2643 | + |
2628 | 2644 | void QtSLiMScriptTextEdit::shiftSelectionLeft(void) |
2629 | 2645 | { |
2630 | | - if (isEnabled() && !isReadOnly()) |
| 2646 | + if (isEnabled() && !isReadOnly()) |
2631 | 2647 | { |
2632 | 2648 | QTextCursor &&edit_cursor = textCursor(); |
2633 | 2649 | bool movedBack; |
@@ -3303,6 +3319,77 @@ void QtSLiMScriptTextEdit::addScriptBlockColoring(int startPos, int endPos, Spec |
3303 | 3319 | blockSpecies.emplace_back(species); |
3304 | 3320 | } |
3305 | 3321 |
|
| 3322 | +// this method courtesy of SO user Larswad, https://stackoverflow.com/a/15808889/2752221 |
| 3323 | +QString QtSLiMScriptTextEdit::exportAsHtml(void) |
| 3324 | +{ |
| 3325 | + // Create a new document from the entire document |
| 3326 | + QTextCursor cursor(document()); |
| 3327 | + cursor.select(QTextCursor::Document); |
| 3328 | + QTextDocument *tempDocument = new QTextDocument; |
| 3329 | + QTextCursor tempCursor(tempDocument); |
| 3330 | + |
| 3331 | + tempCursor.insertFragment(cursor.selection()); |
| 3332 | + tempCursor.select(QTextCursor::Document); |
| 3333 | + |
| 3334 | + // Set the default foreground for the inserted characters |
| 3335 | + QTextCharFormat textfmt = tempCursor.charFormat(); |
| 3336 | + textfmt.setForeground(Qt::black); |
| 3337 | + tempCursor.setCharFormat(textfmt); |
| 3338 | + |
| 3339 | + // Apply the additional formats set by the syntax highlighter |
| 3340 | + QTextBlock start = document()->findBlock(cursor.selectionStart()); |
| 3341 | + QTextBlock end = document()->findBlock(cursor.selectionEnd()); |
| 3342 | + end = end.next(); |
| 3343 | + const int selectionStart = cursor.selectionStart(); |
| 3344 | + const int endOfDocument = tempDocument->characterCount() - 1; |
| 3345 | + for (QTextBlock current = start; current.isValid() and current not_eq end; current = current.next()) { |
| 3346 | + const QTextLayout* layout(current.layout()); |
| 3347 | + |
| 3348 | + foreach (const QTextLayout::FormatRange &range, layout->formats()) { |
| 3349 | + const int formatStart = current.position() + range.start - selectionStart; |
| 3350 | + const int formatEnd = formatStart + range.length; |
| 3351 | + if(formatEnd <= 0 or formatStart >= endOfDocument) |
| 3352 | + continue; |
| 3353 | + tempCursor.setPosition(qMax(formatStart, 0)); |
| 3354 | + tempCursor.setPosition(qMin(formatEnd, endOfDocument), QTextCursor::KeepAnchor); |
| 3355 | + tempCursor.setCharFormat(range.format); |
| 3356 | + } |
| 3357 | + } |
| 3358 | + |
| 3359 | + // Reset the user states since they are not interesting |
| 3360 | + for (QTextBlock block = tempDocument->begin(); block.isValid(); block = block.next()) |
| 3361 | + block.setUserState(-1); |
| 3362 | + |
| 3363 | + // Make sure the text appears pre-formatted, and set the background we want |
| 3364 | + tempCursor.select(QTextCursor::Document); |
| 3365 | + QTextBlockFormat blockFormat = tempCursor.blockFormat(); |
| 3366 | + blockFormat.setNonBreakableLines(true); |
| 3367 | + //blockFormat.setBackground(Qt::black); |
| 3368 | + tempCursor.setBlockFormat(blockFormat); |
| 3369 | + |
| 3370 | + // Select the same range with tempCursor as is selected in the original document |
| 3371 | + QTextCursor selectedRange = textCursor(); |
| 3372 | + tempCursor.setPosition(selectedRange.anchor(), QTextCursor::MoveAnchor); |
| 3373 | + tempCursor.setPosition(selectedRange.position(), QTextCursor::KeepAnchor); |
| 3374 | + |
| 3375 | + // Retrieve the syntax highlighted and formatted html |
| 3376 | + QString html = tempCursor.selection().toHtml(); |
| 3377 | + delete tempDocument; |
| 3378 | + |
| 3379 | + // There is a bug where the first line uses <p> instead of <pre>, because |
| 3380 | + // it is a fragment, I guess. We can fix that with a regex. |
| 3381 | + QRegularExpression pToPreRegex("<p style=(.*)</p>"); |
| 3382 | + pToPreRegex.setPatternOptions(QRegularExpression::CaseInsensitiveOption); |
| 3383 | + html.replace(pToPreRegex, "<pre style=\\1</pre>"); |
| 3384 | + |
| 3385 | + // Change new paragraphs to new lines, so we get one paragraph of text |
| 3386 | + // This doesn't work, you always get a new paragraph for each line; <BR> doesn't work either. |
| 3387 | + //QRegularExpression preRegex("</pre>.?.?<pre style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">"); |
| 3388 | + //preRegex.setPatternOptions(QRegularExpression::DotMatchesEverythingOption | QRegularExpression::CaseInsensitiveOption); |
| 3389 | + //html.replace(preRegex, "\n"); |
| 3390 | + |
| 3391 | + return html; |
| 3392 | +} |
3306 | 3393 |
|
3307 | 3394 |
|
3308 | 3395 |
|
|
0 commit comments