File indexing completed on 2024-03-24 17:24:36

0001 /**
0002  * SPDX-FileCopyrightText: (C) 2003 Sébastien Laoût <slaout@linux62.org>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef NOTE_H
0008 #define NOTE_H
0009 
0010 #include <QGraphicsItemGroup>
0011 #include <QtCore/QDateTime>
0012 #include <QtCore/QList>
0013 #include <QtCore/QSet>
0014 
0015 #include "basket_export.h"
0016 #include "tag.h"
0017 
0018 class BasketScene;
0019 struct FilterData;
0020 
0021 class NoteContent;
0022 class NoteSelection;
0023 
0024 class QPainter;
0025 class QPixmap;
0026 class QString;
0027 class QGraphicsItemAnimation;
0028 class QTimeLine;
0029 
0030 class NotePrivate;
0031 
0032 /** Handle basket notes and groups!\n
0033  * After creation, the note is a group. You should create a NoteContent with this Note
0034  * as constructor parameter to transform it to a note with content. eg:
0035  * @code
0036  * Note *note = new Note(basket);   // note is a group!
0037  * new TextContent(note, fileName); // note is now a note with a text content!
0038  * new ColorContent(note, Qt::red); // Should never be done!!!!! the old Content should be deleted...
0039  * @endcode
0040  * @author Sébastien Laoût
0041  */
0042 class BASKET_EXPORT Note : public QGraphicsItemGroup
0043 {
0044     /// CONSTRUCTOR AND DESTRUCTOR:
0045 public:
0046     explicit Note(BasketScene *parent = nullptr);
0047     ~Note() override;
0048 
0049 private:
0050     NotePrivate *d;
0051 
0052     /// DOUBLY LINKED LIST:
0053 public:
0054     void setNext(Note *next);
0055     void setPrev(Note *prev);
0056     Note *next() const;
0057     Note *prev() const;
0058 
0059 public:
0060     void setWidth(qreal width);
0061     void setWidthForceRelayout(qreal width);
0062     //! Do not use it unless you know what you do!
0063     void setInitialHeight(qreal height);
0064 
0065     void setXRecursively(qreal ax);
0066     void setYRecursively(qreal ay);
0067     void hideRecursively();
0068     qreal width() const;
0069     qreal height() const;
0070     qreal bottom() const;
0071     QRectF rect();
0072     QRectF resizerRect();
0073     QRectF visibleRect();
0074     QRectF boundingRect() const override;
0075     void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
0076     void relayoutAt(qreal ax, qreal ay);
0077     qreal contentX() const;
0078     qreal minWidth() const;
0079     qreal minRight();
0080     void unsetWidth();
0081     void requestRelayout();
0082     /** << DO NEVER USE IT!!! Only available when moving notes, groups should be recreated with the exact same state as before! */
0083     void setHeight(qreal height);
0084 
0085     /// FREE AND COLUMN LAYOUTS MANAGEMENT:
0086 private:
0087     qreal m_groupWidth;
0088 
0089 public:
0090     qreal groupWidth() const;
0091     void setGroupWidth(qreal width);
0092     qreal rightLimit() const;
0093     qreal finalRightLimit() const;
0094     bool isFree() const;
0095     bool isColumn() const;
0096     bool hasResizer() const;
0097     qreal resizerHeight() const;
0098 
0099     /// GROUPS MANAGEMENT:
0100 private:
0101     bool m_isFolded;
0102     Note *m_firstChild;
0103     Note *m_parentNote;
0104 
0105 public:
0106     inline bool isGroup() const
0107     {
0108         return m_content == nullptr;
0109     }
0110     inline bool isFolded()
0111     {
0112         return m_isFolded;
0113     }
0114     inline Note *firstChild()
0115     {
0116         return m_firstChild;
0117     }
0118     inline Note *parentNote() const
0119     {
0120         return m_parentNote;
0121     }
0122     /*inline*/ bool showSubNotes(); //            { return !m_isFolded || !m_collapseFinished; }
0123     inline void setParentNote(Note *note)
0124     {
0125         m_parentNote = note;
0126     }
0127     inline void setFirstChild(Note *note)
0128     {
0129         m_firstChild = note;
0130     }
0131     bool isShown();
0132     bool toggleFolded();
0133 
0134     Note *noteAt(QPointF pos);
0135     Note *firstRealChild();
0136     Note *lastRealChild();
0137     Note *lastChild();
0138     Note *lastSibling();
0139     qreal yExpander();
0140     bool isAfter(Note *note);
0141     bool containsNote(Note *note);
0142 
0143     /// NOTES VARIOUS PROPERTIES:       // CONTENT MANAGEMENT?
0144 private:
0145     BasketScene *m_basket;
0146     NoteContent *m_content;
0147     QDateTime m_addedDate;
0148     QDateTime m_lastModificationDate;
0149 
0150 public:
0151     inline BasketScene *basket() const
0152     {
0153         return m_basket;
0154     }
0155     inline NoteContent *content()
0156     {
0157         return m_content;
0158     }
0159     inline void setAddedDate(const QDateTime &dateTime)
0160     {
0161         m_addedDate = dateTime;
0162     }
0163     inline void setLastModificationDate(const QDateTime &dateTime)
0164     {
0165         m_lastModificationDate = dateTime;
0166     }
0167 
0168     void setParentBasket(BasketScene *basket);
0169 
0170     QDateTime addedDate()
0171     {
0172         return m_addedDate;
0173     }
0174     QDateTime lastModificationDate()
0175     {
0176         return m_lastModificationDate;
0177     }
0178     QString addedStringDate();
0179     QString lastModificationStringDate();
0180     QString toText(const QString &cuttedFullPath);
0181     bool saveAgain();
0182     void deleteChilds();
0183 
0184 protected:
0185     void setContent(NoteContent *content);
0186     friend class NoteContent;
0187     friend class AnimationContent;
0188 
0189     /// DRAWING:
0190 private:
0191     QPixmap m_bufferedPixmap;
0192     QPixmap m_bufferedSelectionPixmap;
0193 
0194 public:
0195     void draw(QPainter *painter, const QRectF &clipRect);
0196     void drawBufferOnScreen(QPainter *painter, const QPixmap &contentPixmap);
0197     static void getGradientColors(const QColor &originalBackground, QColor *colorTop, QColor *colorBottom);
0198     static void drawExpander(QPainter *painter, qreal x, qreal y, const QColor &background, bool expand, BasketScene *basket);
0199     void drawHandle(QPainter *painter, qreal x, qreal y, qreal width, qreal height, const QColor &background, const QColor &foreground, const QColor &lightForeground);
0200     void drawResizer(QPainter *painter, qreal x, qreal y, qreal width, qreal height, const QColor &background, const QColor &foreground, bool rounded);
0201     void drawRoundings(QPainter *painter, qreal x, qreal y, int type, qreal width = 0, qreal height = 0);
0202     void unbufferizeAll();
0203     inline void unbufferize()
0204     {
0205         m_bufferedPixmap = QPixmap();
0206         m_bufferedSelectionPixmap = QPixmap();
0207     }
0208     inline bool isBufferized()
0209     {
0210         return !m_bufferedPixmap.isNull();
0211     }
0212     void recomputeBlankRects(QList<QRectF> &blankAreas);
0213     static void drawInactiveResizer(QPainter *painter, qreal x, qreal y, qreal height, const QColor &background, bool column);
0214     QPalette palette() const;
0215 
0216     /// VISIBLE AREAS COMPUTATION:
0217 private:
0218     QList<QRectF> m_areas;
0219     bool m_computedAreas;
0220     bool m_onTop;
0221     void recomputeAreas();
0222     bool recomputeAreas(Note *note, bool noteIsAfterThis);
0223 
0224 public:
0225     void setOnTop(bool onTop);
0226     inline bool isOnTop()
0227     {
0228         return m_onTop;
0229     }
0230     bool isEditing();
0231 
0232     /// MANAGE ANIMATION:
0233 private:
0234     QGraphicsItemAnimation *m_animation;
0235 
0236 public:
0237     bool initAnimationLoad(QTimeLine *timeLine);
0238     void animationFinished();
0239 
0240     /// USER INTERACTION:
0241 public:
0242     enum Zone {
0243         None = 0,
0244         Handle,
0245         TagsArrow,
0246         Custom0,
0247         /*CustomContent1, CustomContent2, */ Content,
0248         Link,
0249         TopInsert,
0250         TopGroup,
0251         BottomInsert,
0252         BottomGroup,
0253         BottomColumn,
0254         Resizer,
0255         Group,
0256         GroupExpander,
0257         Emblem0
0258     }; // Emblem0 should be at end, because we add 1 to get Emblem1, 2 to get Emblem2...
0259     inline void setHovered(bool hovered)
0260     {
0261         m_hovered = hovered;
0262         unbufferize();
0263     }
0264     void setHoveredZone(Zone zone);
0265     inline bool hovered()
0266     {
0267         return m_hovered;
0268     }
0269     inline Zone hoveredZone()
0270     {
0271         return m_hoveredZone;
0272     }
0273     Zone zoneAt(const QPointF &pos, bool toAdd = false);
0274     QRectF zoneRect(Zone zone, const QPointF &pos);
0275     Qt::CursorShape cursorFromZone(Zone zone) const;
0276     QString linkAt(const QPointF &pos);
0277 
0278 private:
0279     bool m_hovered;
0280     Zone m_hoveredZone;
0281 
0282     /// SELECTION:
0283 public:
0284     NoteSelection *selectedNotes();
0285     void setSelected(bool selected);
0286     void setSelectedRecursively(bool selected);
0287     void invertSelectionRecursively();
0288     void selectIn(const QRectF &rect, bool invertSelection, bool unselectOthers = true);
0289     void setFocused(bool focused);
0290     inline bool isFocused()
0291     {
0292         return m_focused;
0293     }
0294     inline bool isSelected()
0295     {
0296         return m_selected;
0297     }
0298     bool allSelected();
0299     void resetWasInLastSelectionRect();
0300     void unselectAllBut(Note *toSelect);
0301     void invertSelectionOf(Note *toSelect);
0302     Note *theSelectedNote();
0303 
0304 private:
0305     bool m_focused;
0306     bool m_selected;
0307     bool m_wasInLastSelectionRect;
0308 
0309     /// TAGS:
0310 private:
0311     State::List m_states;
0312     State m_computedState;
0313     int m_emblemsCount;
0314     bool m_haveInvisibleTags;
0315 
0316 public:
0317     /*const */ State::List &states() const;
0318     inline int emblemsCount()
0319     {
0320         return m_emblemsCount;
0321     }
0322     void addState(State *state, bool orReplace = true);
0323     void addTag(Tag *tag);
0324     void removeState(State *state);
0325     void removeTag(Tag *tag);
0326     void removeAllTags();
0327     void addTagToSelectedNotes(Tag *tag);
0328     void removeTagFromSelectedNotes(Tag *tag);
0329     void removeAllTagsFromSelectedNotes();
0330     void addStateToSelectedNotes(State *state, bool orReplace = true);
0331     void changeStateOfSelectedNotes(State *state);
0332     bool selectedNotesHaveTags();
0333     void inheritTagsOf(Note *note);
0334     bool hasTag(Tag *tag);
0335     bool hasState(State *state);
0336     State *stateOfTag(Tag *tag);
0337     State *stateForEmblemNumber(int number) const;
0338     bool stateForTagFromSelectedNotes(Tag *tag, State **state);
0339     void recomputeStyle();
0340     void recomputeAllStyles();
0341     bool removedStates(const QList<State *> &deletedStates);
0342     QFont font();             // Computed!
0343     QColor backgroundColor(); // Computed!
0344     QColor textColor();       // Computed!
0345     bool allowCrossReferences();
0346 
0347     /// FILTERING:
0348 private:
0349     bool m_matching;
0350 
0351 public:
0352     bool computeMatching(const FilterData &data);
0353     int newFilter(const FilterData &data);
0354     bool matching()
0355     {
0356         return m_matching;
0357     }
0358 
0359     /// ADDED:
0360 public:
0361     /**
0362      * @return true if this note could be deleted
0363      **/
0364     void deleteSelectedNotes(bool deleteFilesToo = true, QSet<Note *> *notesToBeDeleted = nullptr);
0365     int count();
0366     int countDirectChilds();
0367 
0368     QString fullPath();
0369     Note *noteForFullPath(const QString &path);
0370 
0371     // void update();
0372     void linkLookChanged();
0373 
0374     void usedStates(QList<State *> &states);
0375 
0376     void listUsedTags(QList<Tag *> &list);
0377 
0378     Note *nextInStack();
0379     Note *prevInStack();
0380     Note *nextShownInStack();
0381     Note *prevShownInStack();
0382 
0383     Note *parentPrimaryNote(); // TODO: There are places in the code where this methods is hand-copied / hand-inlined instead of called.
0384 
0385     Note *firstSelected();
0386     Note *lastSelected();
0387     Note *selectedGroup();
0388     void groupIn(Note *group);
0389 
0390     bool tryExpandParent();
0391     bool tryFoldParent();
0392 
0393     qreal distanceOnLeftRight(Note *note, int side);
0394     qreal distanceOnTopBottom(Note *note, int side);
0395 
0396     bool convertTexts();
0397 
0398     void debug();
0399 
0400     /// SPEED OPTIMIZATION
0401 public:
0402     void finishLazyLoad();
0403 
0404 public:
0405     // Values are provided here as info:
0406     // Please see Settings::setBigNotes() to know whats values are assigned.
0407     static qreal NOTE_MARGIN /*= 2*/;
0408     static qreal INSERTION_HEIGHT /*= 5*/;
0409     static qreal EXPANDER_WIDTH /*= 9*/;
0410     static qreal EXPANDER_HEIGHT /*= 9*/;
0411     static qreal GROUP_WIDTH /*= 2*NOTE_MARGIN + EXPANDER_WIDTH*/;
0412     static qreal HANDLE_WIDTH /*= GROUP_WIDTH*/;
0413     static qreal RESIZER_WIDTH /*= GROUP_WIDTH*/;
0414     static qreal TAG_ARROW_WIDTH /*= 5*/;
0415     static qreal EMBLEM_SIZE /*= 16*/;
0416     static qreal MIN_HEIGHT /*= 2*NOTE_MARGIN + EMBLEM_SIZE*/;
0417 };
0418 
0419 /*
0420  * Convenience functions:
0421  */
0422 
0423 extern void substractRectOnAreas(const QRectF &rectToSubstract, QList<QRectF> &areas, bool andRemove = true);
0424 
0425 #endif // NOTE_H