File indexing completed on 2022-12-06 18:50:28

0001 /*
0002     SPDX-License-Identifier: GPL-2.0-or-later
0003     SPDX-FileCopyrightText: 2009 Alexander Rieder <alexanderrieder@gmail.com>
0004     SPDX-FileCopyrightText: 2012 Martin Kuettler <martin.kuettler@gmail.com>
0005     SPDX-FileCopyrightText: 2017-2021 Alexander Semke <alexander.semke@web.de>
0006 */
0007 
0008 #ifndef WORKSHEET_H
0009 #define WORKSHEET_H
0010 
0011 #include <QDomDocument>
0012 #include <QGraphicsScene>
0013 #include <QQueue>
0014 
0015 #include "lib/renderer.h"
0016 #include "mathrender.h"
0017 #include "worksheetcursor.h"
0018 
0019 namespace Cantor {
0020     class Backend;
0021     class Session;
0022     class Expression;
0023 }
0024 
0025 class WorksheetEntry;
0026 class WorksheetView;
0027 class HierarchyEntry;
0028 class PlaceHolderEntry;
0029 class WorksheetTextItem;
0030 
0031 class QAction;
0032 class QDrag;
0033 class QGraphicsObject;
0034 class QMenu;
0035 class QPrinter;
0036 class QSyntaxHighlighter;
0037 class KActionCollection;
0038 class KToggleAction;
0039 class KFontAction;
0040 class KFontSizeAction;
0041 class KZip;
0042 
0043 class Worksheet : public QGraphicsScene
0044 {
0045   Q_OBJECT
0046   public:
0047     enum Type {
0048       CantorWorksheet,
0049       JupyterNotebook
0050     };
0051 
0052     Worksheet(Cantor::Backend*, QWidget*, bool useDeafultWorksheetParameters = true);
0053     ~Worksheet() override;
0054 
0055     Cantor::Session* session();
0056 
0057     void loginToSession();
0058 
0059     bool isRunning();
0060     bool isReadOnly();
0061     bool showExpressionIds();
0062     bool animationsEnabled();
0063     bool embeddedMathEnabled();
0064 
0065     bool isPrinting();
0066 
0067     WorksheetView* worksheetView();
0068 
0069     void stopAnimations();
0070     void resumeAnimations();
0071 
0072     void makeVisible(WorksheetEntry*);
0073     void makeVisible(const WorksheetCursor&);
0074 
0075     void setModified();
0076 
0077     void startDrag(WorksheetEntry*, QDrag*);
0078     void startDragWithHierarchy(HierarchyEntry*, QDrag*, QSizeF responsibleZoneSize);
0079 
0080     void setActionCollection(KActionCollection*);
0081     QMenu* createContextMenu();
0082     void populateMenu(QMenu*, QPointF);
0083     Cantor::Renderer* renderer();
0084     MathRenderer* mathRenderer();
0085     bool isEmpty();
0086     bool isLoadingFromFile();
0087 
0088     WorksheetEntry* currentEntry();
0089     WorksheetEntry* firstEntry();
0090     WorksheetEntry* lastEntry();
0091     WorksheetTextItem* currentTextItem();
0092     WorksheetTextItem* lastFocusedTextItem();
0093 
0094     WorksheetEntry* cutSubentriesForHierarchy(HierarchyEntry*);
0095     void insertSubentriesForHierarchy(HierarchyEntry*, WorksheetEntry*);
0096 
0097     WorksheetCursor worksheetCursor();
0098     void setWorksheetCursor(const WorksheetCursor&);
0099 
0100     // For WorksheetEntry::startDrag
0101     void resetEntryCursor();
0102 
0103     /**
0104      * How it works:
0105      * There are two information streams
0106      * 1. WorksheetView -> Worksheet -> subelemenets (ex. entries) about view width
0107      *   View width used by some sub elements for better visual appearance (for example, entries with text often are fitted to width of view).
0108      * 2. Subelements -> Worksheet
0109      *   Sub elements notify Worksheet about their needed widths and worksheet, used this information, set proper scene size.
0110      */
0111     /// First information stream
0112     void setViewSize(qreal w, qreal h, qreal s, bool forceUpdate = false);
0113 
0114     /// Second information stream
0115     void setRequestedWidth(QGraphicsObject*, qreal width);
0116     void removeRequestedWidth(QGraphicsObject*);
0117 
0118     bool isShortcut(const QKeySequence&);
0119 
0120     void setType(Worksheet::Type);
0121     Worksheet::Type type() const;
0122 
0123     void notifyEntryFocus(WorksheetEntry*);
0124 
0125     // richtext
0126     struct RichTextInfo {
0127         bool bold;
0128         bool italic;
0129         bool underline;
0130         bool strikeOut;
0131         QString font;
0132         qreal fontSize;
0133         Qt::Alignment align;
0134     };
0135 
0136   public:
0137     static int typeForTagName(const QString&);
0138 
0139   public Q_SLOTS:
0140     WorksheetEntry* appendCommandEntry();
0141     void appendCommandEntry(const QString&);
0142     WorksheetEntry* appendTextEntry();
0143     WorksheetEntry* appendMarkdownEntry();
0144     WorksheetEntry* appendImageEntry();
0145     WorksheetEntry* appendPageBreakEntry();
0146     WorksheetEntry* appendLatexEntry();
0147     WorksheetEntry* appendHorizontalRuleEntry();
0148     WorksheetEntry* appendHierarchyEntry();
0149 
0150     WorksheetEntry* insertCommandEntry(WorksheetEntry* current = nullptr);
0151     WorksheetEntry* insertTextEntry(WorksheetEntry* current = nullptr);
0152     WorksheetEntry* insertMarkdownEntry(WorksheetEntry* current = nullptr);
0153     WorksheetEntry* insertImageEntry(WorksheetEntry* current = nullptr);
0154     WorksheetEntry* insertPageBreakEntry(WorksheetEntry* current = nullptr);
0155     WorksheetEntry* insertLatexEntry(WorksheetEntry* current = nullptr);
0156     WorksheetEntry* insertHorizontalRuleEntry(WorksheetEntry* current = nullptr);
0157     WorksheetEntry* insertHierarchyEntry(WorksheetEntry* current = nullptr);
0158 
0159     WorksheetEntry* insertCommandEntryBefore(WorksheetEntry* current = nullptr);
0160     WorksheetEntry* insertTextEntryBefore(WorksheetEntry* current = nullptr);
0161     WorksheetEntry* insertMarkdownEntryBefore(WorksheetEntry* current = nullptr);
0162     WorksheetEntry* insertImageEntryBefore(WorksheetEntry* current = nullptr);
0163     WorksheetEntry* insertPageBreakEntryBefore(WorksheetEntry* current = nullptr);
0164     WorksheetEntry* insertLatexEntryBefore(WorksheetEntry* current = nullptr);
0165     WorksheetEntry* insertHorizontalRuleEntryBefore(WorksheetEntry* current = nullptr);
0166     WorksheetEntry* insertHierarchyEntryBefore(WorksheetEntry* current = nullptr);
0167 
0168     void updateLayout();
0169     void updateHierarchyLayout();
0170     void updateHierarchyControlsLayout(WorksheetEntry* startEntry = nullptr);
0171     void updateEntrySize(WorksheetEntry*);
0172 
0173     void print(QPrinter*);
0174     void paste();
0175     void focusEntry(WorksheetEntry*);
0176 
0177     void evaluate();
0178     void evaluateCurrentEntry();
0179     void interrupt();
0180     void interruptCurrentEntryEvaluation();
0181 
0182     bool completionEnabled();
0183     void showCompletion();
0184 
0185     void highlightItem(WorksheetTextItem*);
0186     void rehighlight();
0187 
0188     void enableHighlighting(bool);
0189     void enableCompletion(bool);
0190     void enableExpressionNumbering(bool);
0191     void enableAnimations(bool);
0192     void enableEmbeddedMath(bool);
0193 
0194     QDomDocument toXML(KZip* archive = nullptr);
0195 
0196     void save(const QString&);
0197     void save(QIODevice*);
0198     QByteArray saveToByteArray();
0199     void savePlain(const QString&);
0200     void saveLatex(const QString&);
0201     bool load(QIODevice*);
0202     void load(QByteArray*);
0203     bool load(const QString&);
0204 
0205     void gotResult(Cantor::Expression* expr = nullptr);
0206 
0207     void removeCurrentEntry();
0208 
0209     void setFirstEntry(WorksheetEntry*);
0210     void setLastEntry(WorksheetEntry*);
0211     void invalidateFirstEntry();
0212     void invalidateLastEntry();
0213 
0214     void updateFocusedTextItem(WorksheetTextItem*);
0215 
0216     void updateDragScrollTimer();
0217 
0218     void registerShortcut(QAction*);
0219     void updateShortcut();
0220 
0221     // richtext
0222     void setRichTextInformation(const Worksheet::RichTextInfo&);
0223     void setAcceptRichText(bool b);
0224 
0225     void setTextForegroundColor();
0226     void setTextBackgroundColor();
0227     void setTextBold(bool b);
0228     void setTextItalic(bool b);
0229     void setTextUnderline(bool b);
0230     void setTextStrikeOut(bool b);
0231     void setAlignLeft();
0232     void setAlignRight();
0233     void setAlignCenter();
0234     void setAlignJustify();
0235     void setFontFamily(const QString&);
0236     void setFontSize(int size);
0237 
0238     void changeEntryType(WorksheetEntry* target, int newType);
0239 
0240     void collapseSelectionResults();
0241     void collapseAllResults();
0242     void uncollapseSelectionResults();
0243     void uncollapseAllResults();
0244     void removeSelectionResults();
0245     void removeAllResults();
0246     void addToExectuionSelection();
0247     void excludeFromExecutionSelection();
0248 
0249     void requestScrollToHierarchyEntry(QString);
0250     void handleSettingsChanges();
0251 
0252   Q_SIGNALS:
0253     void modified();
0254     void loaded();
0255     void showHelp(const QString&);
0256     void hierarchyChanged(QStringList, QStringList, QList<int>);
0257     void hierarhyEntryNameChange(QString name, QString searchName, int depth);
0258     void updatePrompt();
0259     void undoAvailable(bool);
0260     void redoAvailable(bool);
0261     void undo();
0262     void redo();
0263     void cutAvailable(bool);
0264     void copyAvailable(bool);
0265     void pasteAvailable(bool);
0266     void cut();
0267     void copy();
0268     void requestDocumentation(const QString&);
0269 
0270   protected:
0271     void contextMenuEvent(QGraphicsSceneContextMenuEvent*) override;
0272     void mousePressEvent(QGraphicsSceneMouseEvent*) override;
0273 
0274     void dragEnterEvent(QGraphicsSceneDragDropEvent*) override;
0275     void dragLeaveEvent(QGraphicsSceneDragDropEvent*) override;
0276     void dragMoveEvent(QGraphicsSceneDragDropEvent*) override;
0277     void dropEvent(QGraphicsSceneDragDropEvent*) override;
0278 
0279     void keyPressEvent(QKeyEvent*) override;
0280 
0281     QJsonDocument toJupyterJson();
0282 
0283     bool isValidEntry(WorksheetEntry*);
0284 
0285   private Q_SLOTS:
0286     //void checkEntriesForSanity();
0287 
0288     WorksheetEntry* appendEntry(int type, bool focus = true);
0289     WorksheetEntry* insertEntry(int type, WorksheetEntry* current = nullptr);
0290     WorksheetEntry* insertEntryBefore(int type, WorksheetEntry* current = nullptr);
0291 
0292     //Actions for selection
0293     void selectionRemove();
0294     void selectionEvaluate();
0295     void selectionMoveUp();
0296     void selectionMoveDown();
0297 
0298     void animateEntryCursor();
0299 
0300   private:
0301     WorksheetEntry* entryAt(qreal x, qreal y);
0302     WorksheetEntry* entryAt(QPointF);
0303     WorksheetEntry* entryAt(int row);
0304     void updateEntryCursor(QGraphicsSceneMouseEvent*);
0305     void addEntryFromEntryCursor();
0306     void drawEntryCursor();
0307     int entryCount();
0308     bool loadCantorWorksheet(const KZip& archive);
0309     bool loadJupyterNotebook(const QJsonDocument& doc);
0310     void showInvalidNotebookSchemeError(QString additionalInfo = QString());
0311     void initSession(Cantor::Backend*);
0312     void initActions();
0313     std::vector<WorksheetEntry*> hierarchySubelements(HierarchyEntry*) const;
0314 
0315     static const double LeftMargin;
0316     static const double RightMargin;
0317     static const double TopMargin;
0318     static const double EntryCursorLength;
0319     static const double EntryCursorWidth;
0320 
0321     Cantor::Session* m_session{nullptr};
0322     QSyntaxHighlighter* m_highlighter{nullptr};
0323     Cantor::Renderer m_epsRenderer;
0324     MathRenderer m_mathRenderer;
0325     WorksheetEntry* m_firstEntry{nullptr};
0326     WorksheetEntry* m_lastEntry{nullptr};
0327     WorksheetEntry* m_dragEntry{nullptr};
0328     std::vector<WorksheetEntry*> m_hierarchySubentriesDrag;
0329     QSizeF m_hierarchyDragSize;
0330     WorksheetEntry* m_choosenCursorEntry{nullptr};
0331     bool m_isCursorEntryAfterLastEntry{false};
0332     QTimer* m_cursorItemTimer;
0333     QGraphicsLineItem* m_entryCursorItem{nullptr};
0334     PlaceHolderEntry* m_placeholderEntry{nullptr};
0335     WorksheetTextItem* m_lastFocusedTextItem{nullptr};
0336     QTimer* m_dragScrollTimer{nullptr};
0337 
0338     qreal m_viewWidth{0};
0339     QMap<QGraphicsObject*, qreal> m_itemWidths;
0340     qreal m_maxWidth{0};
0341     qreal m_maxPromptWidth{0};
0342 
0343     QMap<QKeySequence, QAction*> m_shortcuts;
0344 
0345     KActionCollection* m_collection{nullptr};
0346     QList<QAction *> m_richTextActionList;
0347     KToggleAction* m_boldAction{nullptr};
0348     KToggleAction* m_italicAction{nullptr};
0349     KToggleAction* m_underlineAction{nullptr};
0350     KToggleAction* m_strikeOutAction{nullptr};
0351     KFontAction* m_fontAction{nullptr};
0352     KFontSizeAction* m_fontSizeAction{nullptr};
0353     KToggleAction* m_alignLeftAction{nullptr};
0354     KToggleAction* m_alignCenterAction{nullptr};
0355     KToggleAction* m_alignRightAction{nullptr};
0356     KToggleAction* m_alignJustifyAction{nullptr};
0357 
0358     bool m_useDefaultWorksheetParameters{true};
0359 
0360     bool m_completionEnabled{false};
0361     bool m_embeddedMathEnabled{false};
0362     bool m_showExpressionIds{false};
0363     bool m_animationsEnabled{false};
0364 
0365     bool m_isPrinting{false};
0366     bool m_isLoadingFromFile{false};
0367     bool m_isClosing{false};
0368     bool m_readOnly{false};
0369 
0370     Type m_type = CantorWorksheet;
0371 
0372     QString m_backendName;
0373     QJsonObject* m_jupyterMetadata{nullptr};
0374 
0375     QVector<WorksheetEntry*> m_selectedEntries;
0376     QQueue<WorksheetEntry*> m_circularFocusBuffer;
0377 
0378     size_t m_hierarchyMaxDepth{0};
0379 };
0380 
0381 #endif // WORKSHEET_H