File indexing completed on 2024-05-12 05:40:37

0001 /*
0002     Cahoots is a crossplatform real-time collaborative text editor.
0003 
0004     Copyright (C) 2010 Chris Dimpfl, Anandi Hira, David Vega
0005 
0006     This program is free software: you can redistribute it and/or modify
0007     it under the terms of the GNU General Public License as published by
0008     the Free Software Foundation, either version 3 of the License, or
0009     (at your option) any later version.
0010 
0011     This program is distributed in the hope that it will be useful,
0012     but WITHOUT ANY WARRANTY; without even the implied warranty of
0013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0014     GNU General Public License for more details.
0015 
0016     You should have received a copy of the GNU General Public License
0017     along with this program.  If not, see <http://www.gnu.org/licenses/>.
0018 */
0019 #include "document.h"
0020 
0021 #include <QDebug>
0022 #include <QDialog>
0023 #include <QFontMetrics>
0024 #include <QLayout>
0025 #include <QMessageBox>
0026 #include <QRegularExpression>
0027 #include <QTextDocumentFragment>
0028 
0029 #include "controller/view_controller/sharednotecontroller.h"
0030 #include "markdownhighlighter.h"
0031 #include "ui_document.h"
0032 
0033 #include "enu.h"
0034 #include "utilities.h"
0035 
0036 Document::Document(SharedNoteController* ctrl, QWidget* parent)
0037     : QWidget(parent), m_shareCtrl(ctrl), ui(new Ui::Document), m_highlighter(nullptr)
0038 {
0039     ui->setupUi(this);
0040 
0041     // Set up the editor
0042     delete ui->editorFrame;
0043     m_editor= new sharedNotes::CodeEditor(m_shareCtrl, this);
0044 
0045     if(!m_shareCtrl)
0046         return;
0047 
0048     setPlainText(m_shareCtrl->text());
0049 
0050     m_previewMarkdown= new QTextEdit();
0051     m_previewMarkdown->setReadOnly(true);
0052     QFontMetricsF fm(m_editor->font());
0053     m_editor->setTabStopDistance(fm.averageCharWidth() * 4.);
0054     ui->editorSplitter->insertWidget(0, m_editor);
0055 
0056     m_previewMarkdown->setVisible(m_shareCtrl->markdownVisible());
0057 
0058     m_participantPane.reset(new ParticipantsPane(m_shareCtrl));
0059     ui->participantSplitter->insertWidget(1, m_previewMarkdown);
0060     ui->participantSplitter->insertWidget(2, m_participantPane.get());
0061 
0062     connect(m_shareCtrl, &SharedNoteController::permissionChanged, this, [this](ParticipantModel::Permission perm) {
0063         m_editor->setReadOnly(ParticipantModel::Permission::readOnly == perm);
0064     });
0065 
0066     connect(m_shareCtrl, &SharedNoteController::markdownVisibleChanged, m_previewMarkdown, &QTextEdit::setVisible);
0067     connect(m_shareCtrl, &SharedNoteController::textChanged, m_previewMarkdown, &QTextEdit::setMarkdown);
0068 
0069     connect(m_editor, &sharedNotes::CodeEditor::textChanged, this, &Document::contentChanged);
0070 
0071     m_editor->setReadOnly(m_shareCtrl->permission() == ParticipantModel::Permission::readOnly);
0072 
0073     // delete ui->findAllFrame;
0074     findAllToolbar= new FindToolBar(this);
0075     ui->editorVerticalLayout->insertWidget(1, findAllToolbar);
0076     findAllToolbar->hide();
0077 
0078     connect(findAllToolbar, &FindToolBar::findAll, m_editor, &sharedNotes::CodeEditor::findAll);
0079     // connect(findAllToolbar, &FindToolBar::findNext, this, &Document::findNext);
0080     connect(findAllToolbar, &FindToolBar::findPrevious, this, &Document::findPrevious);
0081 
0082     // Emit signals to the mainwindow when redoability/undoability changes
0083     connect(m_editor, &sharedNotes::CodeEditor::undoAvailable, this, &Document::undoAvailable);
0084     connect(m_editor, &sharedNotes::CodeEditor::redoAvailable, this, &Document::redoAvailable);
0085 
0086     connect(m_shareCtrl, &SharedNoteController::highligthedSyntaxChanged, this, &Document::updateHighlighter);
0087 
0088     QList<int> sizeList;
0089     sizeList << 900 << 100 << 100;
0090     ui->codeChatSplitter->setSizes(sizeList);
0091     ui->participantSplitter->setSizes(sizeList);
0092 
0093     startedCollaborating= false;
0094 
0095     updateHighlighter();
0096     auto text= m_shareCtrl->text();
0097     if(!text.isEmpty())
0098         setPlainText(text);
0099 }
0100 
0101 Document::~Document()
0102 {
0103     delete ui;
0104 }
0105 /*
0106  *
0107  */
0108 
0109 void Document::displayParticipantPanel()
0110 {
0111     startedCollaborating= true;
0112     setParticipantsHidden(false);
0113 }
0114 
0115 void Document::setEditorFont(QFont font)
0116 {
0117     m_editor->setFont(font);
0118     QFontMetrics fm(m_editor->font());
0119     m_editor->setTabStopDistance(fm.averageCharWidth() * 4);
0120 }
0121 
0122 void Document::setParticipantsFont(QFont font)
0123 {
0124     m_participantPane->setFont(font);
0125 }
0126 
0127 void Document::undo()
0128 {
0129     if(m_editor->hasFocus())
0130     {
0131         m_editor->undo();
0132     }
0133 }
0134 
0135 void Document::redo()
0136 {
0137     if(m_editor->hasFocus())
0138     {
0139         m_editor->redo();
0140     }
0141 }
0142 
0143 void Document::cut()
0144 {
0145     if(m_editor->hasFocus())
0146     {
0147         m_editor->cut();
0148     }
0149     else if(m_participantPane->hasFocus())
0150     {
0151         // do nothing
0152     }
0153 }
0154 
0155 void Document::copy()
0156 {
0157     if(m_editor->hasFocus())
0158     {
0159         m_editor->copy();
0160     }
0161     else if(m_participantPane->hasFocus())
0162     {
0163         // do nothing
0164     }
0165 }
0166 
0167 void Document::paste()
0168 {
0169     if(m_editor->hasFocus())
0170     {
0171         m_editor->paste();
0172     }
0173     else if(m_participantPane->hasFocus())
0174     {
0175         // do nothing
0176     }
0177 }
0178 
0179 void Document::setParticipantsHidden(bool b)
0180 {
0181     if(b)
0182     {
0183         ui->participantSplitter->widget(2)->hide();
0184     }
0185     else
0186     {
0187         ui->participantSplitter->widget(2)->show();
0188         m_editor->resize(QSize(9000, 9000));
0189     }
0190 }
0191 
0192 void Document::shiftLeft()
0193 {
0194     m_editor->shiftLeft();
0195 }
0196 
0197 void Document::shiftRight()
0198 {
0199     m_editor->shiftRight();
0200 }
0201 
0202 void Document::unCommentSelection()
0203 {
0204     m_editor->unCommentSelection();
0205 }
0206 
0207 /*void Document::fill(NetworkMessageWriter* msg)
0208 {
0209     msg->string32(m_editor->toPlainText());
0210     m_participantPane->fill(msg);
0211 }
0212 void Document::readFromMsg(NetworkMessageReader* msg)
0213 {
0214     if(nullptr != msg)
0215     {
0216         if(msg->action() == NetMsg::updateTextAndPermission)
0217         {
0218             QString text= msg->string32();
0219             m_editor->setPlainText(text);
0220             m_participantPane->readFromMsg(msg);
0221         }
0222         else if(msg->action() == NetMsg::updatePermissionOneUser)
0223         {
0224             m_participantPane->readPermissionChanged(msg);
0225         }
0226     }
0227 }*/
0228 
0229 void Document::updateHighlighter()
0230 {
0231     using SNC= SharedNoteController::HighlightedSyntax;
0232     switch(m_shareCtrl->highligthedSyntax())
0233     {
0234     case SNC::None:
0235         m_highlighter.reset();
0236         break;
0237     case SNC::MarkDown:
0238         m_highlighter.reset(new MarkDownHighlighter(m_editor->document()));
0239         break;
0240     }
0241 }
0242 
0243 bool Document::isUndoable()
0244 {
0245     return m_editor->document()->isUndoAvailable();
0246 }
0247 
0248 bool Document::isRedoable()
0249 {
0250     return m_editor->document()->isRedoAvailable();
0251 }
0252 
0253 bool Document::isModified()
0254 {
0255     return m_editor->document()->isModified();
0256 }
0257 
0258 bool Document::isChatHidden()
0259 {
0260     return ui->codeChatSplitter->widget(1)->isHidden();
0261 }
0262 
0263 bool Document::isParticipantsHidden()
0264 {
0265     return ui->participantSplitter->widget(2)->isHidden();
0266 }
0267 
0268 void Document::findAll()
0269 {
0270     findAllToolbar->show();
0271     findAllToolbar->giveFocus();
0272 }
0273 
0274 void Document::findNext(QString searchString, Qt::CaseSensitivity sensitivity, bool wrapAround, Enu::FindMode mode)
0275 {
0276     if(!m_editor->findNext(searchString, sensitivity, wrapAround, mode))
0277     {
0278         emit notFound();
0279     }
0280 }
0281 
0282 void Document::findPrev(QString searchString, Qt::CaseSensitivity sensitivity, bool wrapAround, Enu::FindMode mode)
0283 {
0284     if(!m_editor->findPrev(searchString, sensitivity, wrapAround, mode))
0285     {
0286         emit notFound();
0287     }
0288 }
0289 
0290 void Document::replaceAll(QString searchString, QString replaceString, Qt::CaseSensitivity sensitivity,
0291                           Enu::FindMode mode)
0292 {
0293     if(!m_editor->replaceAll(searchString, replaceString, sensitivity, mode))
0294     {
0295         QMessageBox::information(m_editor, tr("Cahoots"), tr("The string was not found."));
0296     }
0297 }
0298 
0299 void Document::replace(QString replaceString)
0300 {
0301     if(!m_editor->replace(replaceString))
0302     {
0303         emit notFound();
0304     }
0305 }
0306 
0307 void Document::findReplace(QString searchString, QString replaceString, Qt::CaseSensitivity sensitivity,
0308                            bool wrapAround, Enu::FindMode mode)
0309 {
0310     if(!m_editor->findReplace(searchString, replaceString, sensitivity, wrapAround, mode))
0311     {
0312         emit notFound();
0313     }
0314 }
0315 QTextDocument* Document::getDocument()
0316 {
0317     if(nullptr != m_editor)
0318         return m_editor->document();
0319     else
0320         return nullptr;
0321 }
0322 
0323 QString Document::getPlainText()
0324 {
0325     return m_editor->toPlainText();
0326 }
0327 
0328 void Document::setPlainText(QString text)
0329 {
0330     m_editor->setPlainText(text);
0331 }
0332 
0333 void Document::toggleLineWrap()
0334 {
0335     if(m_editor->lineWrapMode() == QPlainTextEdit::NoWrap)
0336     {
0337         m_editor->setLineWrapMode(QPlainTextEdit::WidgetWidth);
0338     }
0339     else
0340     {
0341         m_editor->setLineWrapMode(QPlainTextEdit::NoWrap);
0342     }
0343 }
0344 
0345 void Document::setModified(bool b)
0346 {
0347     m_editor->document()->setModified(b);
0348 }
0349 
0350 void Document::renderMarkdown()
0351 {
0352     // todo
0353 }
0354 
0355 bool Document::docHasCollaborated()
0356 {
0357     return startedCollaborating;
0358 }
0359 
0360 void Document::findNext(QString string)
0361 {
0362     m_editor->findNext(string, Qt::CaseInsensitive, true, Enu::Contains);
0363 }
0364 
0365 void Document::findPrevious(QString string)
0366 {
0367     m_editor->findPrev(string, Qt::CaseInsensitive, true, Enu::Contains);
0368 }
0369 
0370 ParticipantsPane* Document::getParticipantPane() const
0371 {
0372     return m_participantPane.get();
0373 }
0374 
0375 void Document::setParticipantPane(ParticipantsPane* participantPane)
0376 {
0377     m_participantPane.reset(participantPane);
0378 }