49  , mMessageBar( messageBar )
 
   53  mEditor->installEventFilter( 
this );
 
   54  installEventFilter( 
this );
 
   56  QVBoxLayout *vl = 
new QVBoxLayout();
 
   57  vl->setContentsMargins( 0, 0, 0, 0 );
 
   59  vl->addWidget( 
editor, 1 );
 
   63    QGridLayout *layout = 
new QGridLayout( mEditor );
 
   64    layout->setContentsMargins( 0, 0, 0, 0 );
 
   65    layout->addItem( 
new QSpacerItem( 20, 40, QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Expanding ), 1, 0, 1, 1 );
 
   68    QSizePolicy sizePolicy = QSizePolicy( QSizePolicy::Policy::Minimum, QSizePolicy::Policy::Fixed );
 
   69    mMessageBar->setSizePolicy( sizePolicy );
 
   70    layout->addWidget( mMessageBar, 0, 0, 1, 1 );
 
   73  mFindWidget = 
new QWidget();
 
   74  QGridLayout *layoutFind = 
new QGridLayout();
 
   75  layoutFind->setContentsMargins( 0, 2, 0, 0 );
 
   76  layoutFind->setSpacing( 1 );
 
   78  if ( !mEditor->isReadOnly() )
 
   80    mShowReplaceBarButton = 
new QToolButton();
 
   81    mShowReplaceBarButton->setToolTip( tr( 
"Replace" ) );
 
   82    mShowReplaceBarButton->setCheckable( 
true );
 
   83    mShowReplaceBarButton->setAutoRaise( 
true );
 
   85    layoutFind->addWidget( mShowReplaceBarButton, 0, 0 );
 
   92  mLineEditFind->setPlaceholderText( tr( 
"Enter text to find…" ) );
 
   93  layoutFind->addWidget( mLineEditFind, 0, mShowReplaceBarButton ? 1 : 0 );
 
   97  mLineEditReplace->setPlaceholderText( tr( 
"Replace…" ) );
 
   98  layoutFind->addWidget( mLineEditReplace, 1, mShowReplaceBarButton ? 1 : 0 );
 
  100  QHBoxLayout *findButtonLayout = 
new QHBoxLayout();
 
  101  findButtonLayout->setContentsMargins( 0, 0, 0, 0 );
 
  102  findButtonLayout->setSpacing( 1 );
 
  103  mCaseSensitiveButton = 
new QToolButton();
 
  104  mCaseSensitiveButton->setToolTip( tr( 
"Case Sensitive" ) );
 
  105  mCaseSensitiveButton->setCheckable( 
true );
 
  106  mCaseSensitiveButton->setAutoRaise( 
true );
 
  108  findButtonLayout->addWidget( mCaseSensitiveButton );
 
  110  mWholeWordButton = 
new QToolButton();
 
  111  mWholeWordButton->setToolTip( tr( 
"Whole Word" ) );
 
  112  mWholeWordButton->setCheckable( 
true );
 
  113  mWholeWordButton->setAutoRaise( 
true );
 
  115  findButtonLayout->addWidget( mWholeWordButton );
 
  117  mRegexButton = 
new QToolButton();
 
  118  mRegexButton->setToolTip( tr( 
"Use Regular Expressions" ) );
 
  119  mRegexButton->setCheckable( 
true );
 
  120  mRegexButton->setAutoRaise( 
true );
 
  122  findButtonLayout->addWidget( mRegexButton );
 
  124  mWrapAroundButton = 
new QToolButton();
 
  125  mWrapAroundButton->setToolTip( tr( 
"Wrap Around" ) );
 
  126  mWrapAroundButton->setCheckable( 
true );
 
  127  mWrapAroundButton->setAutoRaise( 
true );
 
  129  findButtonLayout->addWidget( mWrapAroundButton );
 
  131  mFindPrevButton = 
new QToolButton();
 
  132  mFindPrevButton->setEnabled( 
false );
 
  133  mFindPrevButton->setToolTip( tr( 
"Find Previous" ) );
 
  135  mFindPrevButton->setAutoRaise( 
true );
 
  136  findButtonLayout->addWidget( mFindPrevButton );
 
  138  mFindNextButton = 
new QToolButton();
 
  139  mFindNextButton->setEnabled( 
false );
 
  140  mFindNextButton->setToolTip( tr( 
"Find Next" ) );
 
  142  mFindNextButton->setAutoRaise( 
true );
 
  143  findButtonLayout->addWidget( mFindNextButton );
 
  145  connect( mLineEditFind, &QLineEdit::returnPressed, 
this, &QgsCodeEditorWidget::findNext );
 
  146  connect( mLineEditFind, &QLineEdit::textChanged, 
this, &QgsCodeEditorWidget::textSearchChanged );
 
  147  connect( mFindNextButton, &QToolButton::clicked, 
this, &QgsCodeEditorWidget::findNext );
 
  148  connect( mFindPrevButton, &QToolButton::clicked, 
this, &QgsCodeEditorWidget::findPrevious );
 
  149  connect( mCaseSensitiveButton, &QToolButton::toggled, 
this, &QgsCodeEditorWidget::updateSearch );
 
  150  connect( mWholeWordButton, &QToolButton::toggled, 
this, &QgsCodeEditorWidget::updateSearch );
 
  151  connect( mRegexButton, &QToolButton::toggled, 
this, &QgsCodeEditorWidget::updateSearch );
 
  152  connect( mWrapAroundButton, &QCheckBox::toggled, 
this, &QgsCodeEditorWidget::updateSearch );
 
  154  QShortcut *findShortcut = 
new QShortcut( QKeySequence::StandardKey::Find, mEditor );
 
  155  findShortcut->setContext( Qt::ShortcutContext::WidgetWithChildrenShortcut );
 
  158  QShortcut *findNextShortcut = 
new QShortcut( QKeySequence::StandardKey::FindNext, 
this );
 
  159  findNextShortcut->setContext( Qt::ShortcutContext::WidgetWithChildrenShortcut );
 
  160  connect( findNextShortcut, &QShortcut::activated, 
this, &QgsCodeEditorWidget::findNext );
 
  162  QShortcut *findPreviousShortcut = 
new QShortcut( QKeySequence::StandardKey::FindPrevious, 
this );
 
  163  findPreviousShortcut->setContext( Qt::ShortcutContext::WidgetWithChildrenShortcut );
 
  164  connect( findPreviousShortcut, &QShortcut::activated, 
this, &QgsCodeEditorWidget::findPrevious );
 
  166  if ( !mEditor->isReadOnly() )
 
  168    QShortcut *replaceShortcut = 
new QShortcut( QKeySequence::StandardKey::Replace, 
this );
 
  169    replaceShortcut->setContext( Qt::ShortcutContext::WidgetWithChildrenShortcut );
 
  170    connect( replaceShortcut, &QShortcut::activated, 
this, [
this] {
 
  172      const bool show = mLineEditReplace->isHidden();
 
  182  QShortcut *closeFindShortcut = 
new QShortcut( Qt::Key::Key_Escape, 
this );
 
  183  closeFindShortcut->setContext( Qt::ShortcutContext::WidgetWithChildrenShortcut );
 
  184  connect( closeFindShortcut, &QShortcut::activated, 
this, [
this] {
 
  189  layoutFind->addLayout( findButtonLayout, 0, mShowReplaceBarButton ? 2 : 1 );
 
  191  QHBoxLayout *replaceButtonLayout = 
new QHBoxLayout();
 
  192  replaceButtonLayout->setContentsMargins( 0, 0, 0, 0 );
 
  193  replaceButtonLayout->setSpacing( 1 );
 
  195  mReplaceButton = 
new QToolButton();
 
  196  mReplaceButton->setText( tr( 
"Replace" ) );
 
  197  mReplaceButton->setEnabled( 
false );
 
  198  connect( mReplaceButton, &QToolButton::clicked, 
this, &QgsCodeEditorWidget::replace );
 
  199  replaceButtonLayout->addWidget( mReplaceButton );
 
  201  mReplaceAllButton = 
new QToolButton();
 
  202  mReplaceAllButton->setText( tr( 
"Replace All" ) );
 
  203  mReplaceAllButton->setEnabled( 
false );
 
  204  connect( mReplaceAllButton, &QToolButton::clicked, 
this, &QgsCodeEditorWidget::replaceAll );
 
  205  replaceButtonLayout->addWidget( mReplaceAllButton );
 
  207  layoutFind->addLayout( replaceButtonLayout, 1, mShowReplaceBarButton ? 2 : 1 );
 
  209  QToolButton *closeFindButton = 
new QToolButton( 
this );
 
  210  closeFindButton->setToolTip( tr( 
"Close" ) );
 
  212  closeFindButton->setStyleSheet(
 
  213    "QToolButton { border:none; background-color: rgba(0, 0, 0, 0); }" 
  214    "QToolButton::menu-button { border:none; background-color: rgba(0, 0, 0, 0); }" 
  216  closeFindButton->setCursor( Qt::PointingHandCursor );
 
  220  closeFindButton->setIconSize( QSize( iconSize, iconSize ) );
 
  221  closeFindButton->setFixedSize( QSize( iconSize, iconSize ) );
 
  222  connect( closeFindButton, &QAbstractButton::clicked, 
this, [
this] {
 
  226  layoutFind->addWidget( closeFindButton, 0, mShowReplaceBarButton ? 3 : 2 );
 
  228  layoutFind->setColumnStretch( mShowReplaceBarButton ? 1 : 0, 1 );
 
  230  mFindWidget->setLayout( layoutFind );
 
  231  vl->addWidget( mFindWidget );
 
  238  mHighlightController = std::make_unique<QgsScrollBarHighlightController>();
 
  239  mHighlightController->setScrollArea( mEditor );
 
 
  536  const QString accessToken = 
QgsSettings().
value( 
"pythonConsole/accessTokenGithub", QString() ).toString();
 
  537  if ( accessToken.isEmpty() )
 
  540      mMessageBar->
pushWarning( QString(), tr( 
"GitHub personal access token must be generated (see IDE Options)" ) );
 
  544  QString defaultFileName;
 
  548      defaultFileName = QStringLiteral( 
"pyqgis_snippet.py" );
 
  552      defaultFileName = QStringLiteral( 
"qgis_snippet.css" );
 
  556      defaultFileName = QStringLiteral( 
"qgis_snippet" );
 
  560      defaultFileName = QStringLiteral( 
"qgis_snippet.html" );
 
  564      defaultFileName = QStringLiteral( 
"qgis_snippet.js" );
 
  568      defaultFileName = QStringLiteral( 
"qgis_snippet.json" );
 
  572      defaultFileName = QStringLiteral( 
"qgis_snippet.r" );
 
  576      defaultFileName = QStringLiteral( 
"qgis_snippet.sql" );
 
  580      defaultFileName = QStringLiteral( 
"qgis_snippet.bat" );
 
  584      defaultFileName = QStringLiteral( 
"qgis_snippet.sh" );
 
  588      defaultFileName = QStringLiteral( 
"qgis_snippet.txt" );
 
  591  const QString filename = mFilePath.isEmpty() ? defaultFileName : QFileInfo( mFilePath ).fileName();
 
  593  const QString contents = mEditor->hasSelectedText() ? mEditor->selectedText() : mEditor->text();
 
  594  const QVariantMap data {
 
  595    { QStringLiteral( 
"description" ), 
"Gist created by PyQGIS Console" },
 
  596    { QStringLiteral( 
"public" ), isPublic },
 
  597    { QStringLiteral( 
"files" ), QVariantMap { { filename, QVariantMap { { QStringLiteral( 
"content" ), contents } } } } }
 
  600  QNetworkRequest request;
 
  601  request.setUrl( QUrl( QStringLiteral( 
"https://api.github.com/gists" ) ) );
 
  602  request.setRawHeader( 
"Authorization", QStringLiteral( 
"token %1" ).arg( accessToken ).toLocal8Bit() );
 
  603  request.setHeader( QNetworkRequest::ContentTypeHeader, QLatin1String( 
"application/json" ) );
 
  604  request.setAttribute( QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::RedirectPolicy::NoLessSafeRedirectPolicy );
 
  608  connect( reply, &QNetworkReply::finished, 
this, [
this, reply] {
 
  609    if ( reply->error() == QNetworkReply::NoError )
 
  611      const QVariantMap replyJson = QgsJsonUtils::parseJson( reply->readAll() ).toMap();
 
  612      const QString link = replyJson.value( QStringLiteral( 
"html_url" ) ).toString();
 
  613      QDesktopServices::openUrl( QUrl( link ) );
 
  618        mMessageBar->pushCritical( QString(), tr( 
"Connection error: %1" ).arg( reply->errorString() ) );
 
  620    reply->deleteLater();