1 /*************************************************************************** 2 * Copyright (C) 2003 by Sébastien Laoût * 3 * slaout@linux62.org * 4 * * 5 * This program is free software; you can redistribute it and/or modify * 6 * it under the terms of the GNU General Public License as published by * 7 * the Free Software Foundation; either version 2 of the License, or * 8 * (at your option) any later version. * 9 * * 10 * This program is distributed in the hope that it will be useful, * 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 13 * GNU General Public License for more details. * 14 * * 15 * You should have received a copy of the GNU General Public License * 16 * along with this program; if not, write to the * 17 * Free Software Foundation, Inc., * 18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * 19 ***************************************************************************/ 20 21 #ifndef BASKET_H 22 #define BASKET_H 23 24 #include <QtCore/QList> 25 #include <QtCore/QSet> 26 #include <QtCore/QTimer> 27 #include <QXmlStreamWriter> 28 #include <QtGui/QTextCursor> 29 #include <QtGui/QClipboard> 30 #include <QGraphicsScene> 31 32 #include "note.h" // For Note::Zone 33 #include "config.h" 34 35 class QFrame; 36 class QPixmap; 37 class QPushButton; 38 39 class QDomDocument; 40 class QDomElement; 41 42 class QContextMenuEvent; 43 class QDragLeaveEvent; 44 class QDragEnterEvent; 45 class QDragMoveEvent; 46 class QDropEvent; 47 class QEvent; 48 class QFocusEvent; 49 class QHelpEvent; 50 class QKeyEvent; 51 class QMouseEvent; 52 class QResizeEvent; 53 class QWheelEvent; 54 55 class QAction; 56 class KDirWatch; 57 class QKeySequence; 58 class QUrl; 59 60 namespace KIO { 61 class Job; 62 } 63 64 class DecoratedBasket; 65 class Note; 66 class NoteEditor; 67 class Tag; 68 class TransparentWidget; 69 70 #ifdef HAVE_LIBGPGME 71 class KGpgMe; 72 #endif 73 74 /** 75 * @author Sébastien Laoût 76 */ 77 class BasketScene : public QGraphicsScene 78 { 79 Q_OBJECT 80 public: 81 enum EncryptionTypes { 82 NoEncryption = 0, 83 PasswordEncryption = 1, 84 PrivateKeyEncryption = 2 85 }; 86 87 public: 88 /// CONSTRUCTOR AND DESTRUCTOR: 89 BasketScene(QWidget *parent, const QString &folderName); 90 ~BasketScene(); 91 92 /// USER INTERACTION: 93 private: 94 bool m_noActionOnMouseRelease; 95 bool m_ignoreCloseEditorOnNextMouseRelease; 96 QPointF m_pressPos; 97 bool m_canDrag; 98 99 public: 100 void drawBackground ( QPainter * painter, const QRectF & rect ); 101 void drawForeground ( QPainter * painter, const QRectF & rect ); 102 103 void enterEvent(QEvent *); 104 void leaveEvent(QEvent *); 105 void mouseMoveEvent(QGraphicsSceneMouseEvent *event); 106 void mousePressEvent(QGraphicsSceneMouseEvent *event); 107 void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); 108 void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); 109 void contextMenuEvent(QGraphicsSceneContextMenuEvent *event); 110 void clickedToInsert(QGraphicsSceneMouseEvent *event, Note *clicked = 0, int zone = 0); 111 private slots: 112 void setFocusIfNotInPopupMenu(); 113 signals: 114 void crossReference(QString link); 115 116 /// LAYOUT: 117 private: 118 Note *m_firstNote; 119 int m_columnsCount; 120 bool m_mindMap; 121 Note *m_resizingNote; 122 int m_pickedResizer; 123 Note *m_movingNote; 124 QPoint m_pickedHandle; 125 QSet<Note*> m_notesToBeDeleted; 126 127 public: 128 qreal tmpWidth; 129 qreal tmpHeight; 130 public: 131 void unsetNotesWidth(); 132 void relayoutNotes(bool animate); 133 Note* noteAt(QPointF pos); firstNote()134 inline Note* firstNote() { 135 return m_firstNote; 136 } columnsCount()137 inline int columnsCount() { 138 return m_columnsCount; 139 } isColumnsLayout()140 inline bool isColumnsLayout() { 141 return m_columnsCount > 0; 142 } isFreeLayout()143 inline bool isFreeLayout() { 144 return m_columnsCount <= 0; 145 } isMindMap()146 inline bool isMindMap() { 147 return isFreeLayout() && m_mindMap; 148 } resizingNote()149 Note* resizingNote() { 150 return m_resizingNote; 151 } 152 void deleteNotes(); 153 Note* lastNote(); 154 void setDisposition(int disposition, int columnCount); 155 void equalizeColumnSizes(); 156 157 /// NOTES INSERTION AND REMOVAL: 158 public: 159 /// The following methods assume that the note(s) to insert already all have 'this' as the parent basket: 160 void prependNoteIn(Note *note, Note *in); /// << Add @p note (and the next linked notes) as the first note(s) of the group @p in. 161 void appendNoteIn(Note *note, Note *in); /// << Add @p note (and the next linked notes) as the last note(s) of the group @p in. 162 void appendNoteAfter(Note *note, Note *after); /// << Add @p note (and the next linked notes) just after (just below) the note @p after. 163 void appendNoteBefore(Note *note, Note *before); /// << Add @p note (and the next linked notes) just before (just above) the note @p before. 164 void groupNoteAfter(Note *note, Note *with); /// << Add a group at @p with place, move @p with in it, and add @p note (and the next linked notes) just after the group. 165 void groupNoteBefore(Note *note, Note *with); /// << Add a group at @p with place, move @p with in it, and add @p note (and the next linked notes) just before the group. 166 void unplugNote(Note *note); /// << Unplug @p note (and its child notes) from the basket (and also decrease counts...). 167 /// << After that, you should delete the notes yourself. Do not call prepend/append/group... functions two times: unplug and ok 168 void ungroupNote(Note *group); /// << Unplug @p group but put child notes at its place. 169 /// And this one do almost all the above methods depending on the context: 170 void insertNote(Note *note, Note *clicked, int zone, const QPointF &pos = QPointF(), bool animateNewPosition = false); 171 void insertCreatedNote(Note *note); 172 /// And working with selections: 173 void unplugSelection(NoteSelection *selection); 174 void insertSelection(NoteSelection *selection, Note *after); 175 void selectSelection(NoteSelection *selection); 176 protected slots: 177 void doCleanUp(); 178 179 private: 180 void preparePlug(Note *note); 181 private: 182 Note *m_clickedToInsert; 183 int m_zoneToInsert; 184 QPointF m_posToInsert; 185 Note *m_savedClickedToInsert; 186 int m_savedZoneToInsert; 187 QPointF m_savedPosToInsert; 188 bool m_isInsertPopupMenu; 189 QAction *m_insertMenuTitle; 190 public: 191 void saveInsertionData(); 192 void restoreInsertionData(); 193 void resetInsertionData(); 194 public slots: 195 void insertEmptyNote(int type); 196 void insertWizard(int type); 197 void insertColor(const QColor &color); 198 void insertImage(const QPixmap &image); 199 void pasteNote(QClipboard::Mode mode = QClipboard::Clipboard); 200 void delayedCancelInsertPopupMenu(); setInsertPopupMenu()201 void setInsertPopupMenu() { 202 m_isInsertPopupMenu = true; 203 } cancelInsertPopupMenu()204 void cancelInsertPopupMenu() { 205 m_isInsertPopupMenu = false; 206 } 207 private slots: 208 void hideInsertPopupMenu(); 209 void timeoutHideInsertPopupMenu(); 210 211 /// TOOL TIPS: 212 protected: 213 void helpEvent(QGraphicsSceneHelpEvent* event); 214 215 /// ANIMATIONS: 216 private: 217 QTimeLine *m_animationTimeLine; 218 static const int ANIMATION_DELAY; 219 220 public slots: 221 void animationFrameChanged(int); 222 void animateLoad(); 223 void finishAnimation(); 224 225 /// LOAD AND SAVE: 226 private: 227 bool m_loaded; 228 bool m_loadingLaunched; 229 bool m_locked; 230 bool m_shouldConvertPlainTextNotes; 231 QFrame* m_decryptBox; 232 QPushButton* m_button; 233 int m_encryptionType; 234 QString m_encryptionKey; 235 #ifdef HAVE_LIBGPGME 236 KGpgMe* m_gpg; 237 #endif 238 QTimer m_inactivityAutoLockTimer; 239 QTimer m_commitdelay; 240 void enableActions(); 241 242 243 private slots: 244 void loadNotes(const QDomElement ¬es, Note *parent); 245 void saveNotes(QXmlStreamWriter &stream, Note *parent); 246 void unlock(); 247 protected slots: 248 void inactivityAutoLockTimeout(); 249 public slots: 250 void load(); 251 void loadProperties(const QDomElement &properties); 252 void saveProperties(QXmlStreamWriter &stream); 253 bool save(); 254 void commitEdit(); 255 void reload(); 256 public: 257 bool isEncrypted(); 258 bool isFileEncrypted(); isLocked()259 bool isLocked() { 260 return m_locked; 261 }; 262 void lock(); isLoaded()263 bool isLoaded() { 264 return m_loaded; 265 }; loadingLaunched()266 bool loadingLaunched() { 267 return m_loadingLaunched; 268 }; 269 bool loadFromFile(const QString &fullPath, QString* string); 270 bool loadFromFile(const QString &fullPath, QByteArray* array); 271 bool saveToFile(const QString& fullPath, const QString& string); 272 bool saveToFile(const QString& fullPath, const QByteArray& array); //[Encrypt and] save binary content 273 static bool safelySaveToFile(const QString& fullPath, const QByteArray& array, unsigned long length); 274 static bool safelySaveToFile(const QString& fullPath, const QString& string); 275 bool setProtection(int type, QString key); encryptionType()276 int encryptionType() { 277 return m_encryptionType; 278 }; encryptionKey()279 QString encryptionKey() { 280 return m_encryptionKey; 281 }; 282 bool saveAgain(); 283 284 /// BACKGROUND: 285 private: 286 QColor m_backgroundColorSetting; 287 QString m_backgroundImageName; 288 QPixmap *m_backgroundPixmap; 289 QPixmap *m_opaqueBackgroundPixmap; 290 QPixmap *m_selectedBackgroundPixmap; 291 bool m_backgroundTiled; 292 QColor m_textColorSetting; 293 public: hasBackgroundImage()294 inline bool hasBackgroundImage() { 295 return m_backgroundPixmap != 0; 296 } backgroundPixmap()297 inline const QPixmap* backgroundPixmap() { 298 return m_backgroundPixmap; 299 } isTiledBackground()300 inline bool isTiledBackground() { 301 return m_backgroundTiled; 302 } backgroundImageName()303 inline QString backgroundImageName() { 304 return m_backgroundImageName; 305 } backgroundColorSetting()306 inline QColor backgroundColorSetting() { 307 return m_backgroundColorSetting; 308 } textColorSetting()309 inline QColor textColorSetting() { 310 return m_textColorSetting; 311 } 312 QColor backgroundColor() const; 313 QColor textColor() const; 314 void setAppearance(const QString &icon, const QString &name, const QString &backgroundImage, const QColor &backgroundColor, const QColor &textColor); 315 void blendBackground(QPainter &painter, const QRectF &rect, qreal xPainter = -1, qreal yPainter = -1, bool opaque = false, QPixmap *bg = 0); 316 void blendBackground(QPainter &painter, const QRectF &rect, bool opaque, QPixmap *bg ); 317 void unbufferizeAll(); 318 void subscribeBackgroundImages(); 319 void unsubscribeBackgroundImages(); 320 321 /// KEYBOARD SHORTCUT: 322 public: 323 QAction *m_action; 324 private: 325 int m_shortcutAction; 326 private slots: 327 void activatedShortcut(); 328 public: shortcut()329 QKeySequence shortcut() { 330 return m_action->shortcut(); 331 } shortcutAction()332 int shortcutAction() { 333 return m_shortcutAction; 334 } 335 void setShortcut(QKeySequence shortcut, int action); 336 337 /// USER INTERACTION: 338 private: 339 Note *m_hoveredNote; 340 int m_hoveredZone; 341 bool m_lockedHovering; 342 bool m_underMouse; 343 QRectF m_inserterRect; 344 bool m_inserterShown; 345 bool m_inserterSplit; 346 bool m_inserterTop; 347 bool m_inserterGroup; 348 void placeInserter(Note *note, int zone); 349 void removeInserter(); 350 public: 351 // bool inserterShown() { return m_inserterShown; } inserterSplit()352 bool inserterSplit() { 353 return m_inserterSplit; 354 } inserterGroup()355 bool inserterGroup() { 356 return m_inserterGroup; 357 } 358 public slots: 359 void doHoverEffects(Note *note, Note::Zone zone, const QPointF &pos = QPointF(0, 0)); /// << @p pos is optionnal and only used to show the link target in the statusbar 360 void doHoverEffects(const QPointF &pos); 361 void doHoverEffects(); // The same, but using the current cursor position 362 void mouseEnteredEditorWidget(); 363 public: 364 void popupTagsMenu(Note *note); 365 void popupEmblemMenu(Note *note, int emblemNumber); 366 void addTagToSelectedNotes(Tag *tag); 367 void removeTagFromSelectedNotes(Tag *tag); 368 void removeAllTagsFromSelectedNotes(); 369 void addStateToSelectedNotes(State *state); 370 void changeStateOfSelectedNotes(State *state); 371 bool selectedNotesHaveTags(); inserterRect()372 const QRectF& inserterRect() { 373 return m_inserterRect; 374 } inserterShown()375 bool inserterShown() { 376 return m_inserterShown; 377 } 378 void drawInserter(QPainter &painter, qreal xPainter, qreal yPainter); 379 DecoratedBasket* decoration(); 380 State *stateForTagFromSelectedNotes(Tag *tag); 381 public slots: 382 void activatedTagShortcut(Tag *tag); 383 void recomputeAllStyles(); 384 void removedStates(const QList<State*> &deletedStates); 385 private slots: 386 void toggledTagInMenu(QAction *act); 387 void toggledStateInMenu(QAction *act); 388 void unlockHovering(); 389 void disableNextClick(); 390 public: 391 Note *m_tagPopupNote; 392 private: 393 Tag *m_tagPopup; 394 QTime m_lastDisableClick; 395 396 /// SELECTION: 397 private: 398 bool m_isSelecting; 399 bool m_selectionStarted; 400 bool m_selectionInvert; 401 QPointF m_selectionBeginPoint; 402 QPointF m_selectionEndPoint; 403 QRectF m_selectionRect; 404 QTimer m_autoScrollSelectionTimer; 405 void stopAutoScrollSelection(); 406 private slots: 407 void doAutoScrollSelection(); 408 public: isSelecting()409 inline bool isSelecting() { 410 return m_isSelecting; 411 } selectionRect()412 inline const QRectF& selectionRect() { 413 return m_selectionRect; 414 } 415 void selectNotesIn(const QRectF &rect, bool invertSelection, bool unselectOthers = true); 416 void resetWasInLastSelectionRect(); 417 void selectAll(); 418 void unselectAll(); 419 void invertSelection(); 420 void unselectAllBut(Note *toSelect); 421 void invertSelectionOf(Note *toSelect); 422 QColor selectionRectInsideColor(); 423 Note* theSelectedNote(); 424 NoteSelection* selectedNotes(); 425 426 /// BLANK SPACES DRAWING: 427 private: 428 QList<QRectF> m_blankAreas; 429 void recomputeBlankRects(); 430 QWidget *m_cornerWidget; 431 432 /// COMMUNICATION WITH ITS CONTAINER: 433 signals: 434 void postMessage(const QString &message); /// << Post a temporar message in the statusBar. 435 void setStatusBarText(const QString &message); /// << Set the permanent statusBar text or reset it if message isEmpty(). 436 void resetStatusBarText(); /// << Equivalent to setStatusBarText(""). 437 void propertiesChanged(BasketScene *basket); 438 void countsChanged(BasketScene *basket); 439 public slots: 440 void linkLookChanged(); 441 void signalCountsChanged(); 442 private: 443 QTimer m_timerCountsChanged; 444 private slots: 445 void countsChangedTimeOut(); 446 447 /// NOTES COUNTING: 448 public: addSelectedNote()449 void addSelectedNote() { 450 ++m_countSelecteds; signalCountsChanged(); 451 } removeSelectedNote()452 void removeSelectedNote() { 453 --m_countSelecteds; signalCountsChanged(); 454 } resetSelectedNote()455 void resetSelectedNote() { 456 m_countSelecteds = 0; signalCountsChanged(); 457 } // FIXME: Useful ??? count()458 int count() { 459 return m_count; 460 } countFounds()461 int countFounds() { 462 return m_countFounds; 463 } countSelecteds()464 int countSelecteds() { 465 return m_countSelecteds; 466 } 467 private: 468 int m_count; 469 int m_countFounds; 470 int m_countSelecteds; 471 472 /// PROPERTIES: 473 public: basketName()474 QString basketName() { 475 return m_basketName; 476 } icon()477 QString icon() { 478 return m_icon; 479 } folderName()480 QString folderName() { 481 return m_folderName; 482 } 483 QString fullPath(); 484 QString fullPathForFileName(const QString &fileName); // Full path of an [existing or not] note in this basket 485 static QString fullPathForFolderName(const QString &folderName); 486 private: 487 QString m_basketName; 488 QString m_icon; 489 QString m_folderName; 490 491 /// ACTIONS ON SELECTED NOTES FROM THE INTERFACE: 492 public slots: 493 void noteEdit(Note *note = 0L, bool justAdded = false, const QPointF &clickedPoint = QPointF()); 494 void showEditedNoteWhileFiltering(); 495 void noteDelete(); 496 void noteDeleteWithoutConfirmation(bool deleteFilesToo = true); 497 void noteCopy(); 498 void noteCut(); 499 void noteOpen(Note *note = 0L); 500 void noteOpenWith(Note *note = 0L); 501 void noteSaveAs(); 502 void noteGroup(); 503 void noteUngroup(); 504 void noteMoveOnTop(); 505 void noteMoveOnBottom(); 506 void noteMoveNoteUp(); 507 void noteMoveNoteDown(); 508 void moveSelectionTo(Note *here, bool below); 509 public: 510 enum CopyMode { CopyToClipboard, CopyToSelection, CutToClipboard }; 511 void doCopy(CopyMode copyMode); 512 bool selectionIsOneGroup(); 513 Note* selectedGroup(); 514 Note* firstSelected(); 515 Note* lastSelected(); 516 517 /// NOTES EDITION: 518 private: 519 NoteEditor *m_editor; 520 //QWidget *m_rightEditorBorder; 521 TransparentWidget *m_leftEditorBorder; 522 TransparentWidget *m_rightEditorBorder; 523 bool m_redirectEditActions; 524 bool m_editorTrackMouseEvent; 525 qreal m_editorWidth; 526 qreal m_editorHeight; 527 QTimer m_inactivityAutoSaveTimer; 528 bool m_doNotCloseEditor; 529 QTextCursor m_textCursor; 530 public: isDuringEdit()531 bool isDuringEdit() { 532 return m_editor; 533 } redirectEditActions()534 bool redirectEditActions() { 535 return m_redirectEditActions; 536 } 537 bool hasTextInEditor(); 538 bool hasSelectedTextInEditor(); 539 bool selectedAllTextInEditor(); 540 Note* editedNote(); 541 protected slots: 542 void selectionChangedInEditor(); 543 void contentChangedInEditor(); 544 void inactivityAutoSaveTimeout(); 545 public slots: 546 void editorCursorPositionChanged(); 547 private: 548 qreal m_editorX; 549 qreal m_editorY; 550 public slots: 551 void placeEditor(bool andEnsureVisible = false); 552 void placeEditorAndEnsureVisible(); 553 bool closeEditor(bool deleteEmptyNote = true); 554 void closeEditorDelayed(); 555 void updateEditorAppearance(); 556 void editorPropertiesChanged(); 557 void openBasket(); 558 void closeBasket(); 559 560 /// FILTERING: 561 public slots: 562 void newFilter(const FilterData &data, bool andEnsureVisible = true); 563 void filterAgain(bool andEnsureVisible = true); 564 void filterAgainDelayed(); 565 bool isFiltering(); 566 567 /// DRAG AND DROP: 568 private: 569 bool m_isDuringDrag; 570 QList<Note*> m_draggedNotes; 571 public: 572 static void acceptDropEvent(QGraphicsSceneDragDropEvent *event, bool preCond = true); 573 void dropEvent(QGraphicsSceneDragDropEvent *event); 574 void blindDrop(QGraphicsSceneDragDropEvent * event); 575 void blindDrop(const QMimeData *mimeData, Qt::DropAction dropAction, QObject *source); isDuringDrag()576 bool isDuringDrag() { 577 return m_isDuringDrag; 578 } draggedNotes()579 QList<Note*> draggedNotes() { 580 return m_draggedNotes; 581 } 582 protected: 583 void dragEnterEvent(QGraphicsSceneDragDropEvent *); 584 void dragMoveEvent(QGraphicsSceneDragDropEvent *event); 585 void dragLeaveEvent(QGraphicsSceneDragDropEvent *); 586 public slots: 587 void slotCopyingDone2(KIO::Job *job, const QUrl &from, const QUrl &to); 588 public: 589 Note* noteForFullPath(const QString &path); 590 591 /// EXPORTATION: 592 public: 593 QList<State*> usedStates(); 594 static QString saveGradientBackground(const QColor &color, const QFont &font, const QString &folder); 595 596 public: 597 void listUsedTags(QList<Tag*> &list); 598 599 /// MANAGE FOCUS: 600 private: 601 Note *m_focusedNote; 602 public: 603 void setFocusedNote(Note *note); 604 void focusANote(); 605 void focusANonSelectedNoteAbove(bool inSameColumn); 606 void focusANonSelectedNoteBelow(bool inSameColumn); 607 void focusANonSelectedNoteBelowOrThenAbove(); 608 void focusANonSelectedNoteAboveOrThenBelow(); focusedNote()609 Note* focusedNote() { 610 return m_focusedNote; 611 } 612 Note* firstNoteInStack(); 613 Note* lastNoteInStack(); 614 Note* firstNoteShownInStack(); 615 Note* lastNoteShownInStack(); 616 void selectRange(Note *start, Note *end, bool unselectOthers = true); /// FIXME: Not really a focus related method! 617 void ensureNoteVisible(Note *note); 618 virtual void keyPressEvent(QKeyEvent *event); 619 virtual void focusInEvent(QFocusEvent*); 620 virtual void focusOutEvent(QFocusEvent*); 621 QRectF noteVisibleRect(Note *note); // clipped global (desktop as origin) rectangle 622 Note* firstNoteInGroup(); 623 Note *noteOnHome(); 624 Note *noteOnEnd(); 625 626 enum NoteOn { LEFT_SIDE = 1, RIGHT_SIDE, TOP_SIDE, BOTTOM_SIDE }; 627 Note* noteOn(NoteOn side); 628 629 /// REIMPLEMENTED: 630 public: 631 void deleteFiles(); 632 bool convertTexts(); 633 634 635 public: 636 void wheelEvent(QGraphicsSceneWheelEvent *event); 637 638 639 640 public: 641 Note *m_startOfShiftSelectionNote; 642 643 644 /// THE NEW FILE WATCHER: 645 private: 646 KDirWatch *m_watcher; 647 QTimer m_watcherTimer; 648 QList<QString> m_modifiedFiles; 649 public: 650 void addWatchedFile(const QString &fullPath); 651 void removeWatchedFile(const QString &fullPath); 652 private slots: 653 void watchedFileModified(const QString &fullPath); 654 void watchedFileDeleted(const QString &fullPath); 655 void updateModifiedNotes(); 656 657 658 /// FROM OLD ARCHITECTURE ********************** 659 660 public slots: 661 showFrameInsertTo()662 void showFrameInsertTo() {} resetInsertTo()663 void resetInsertTo() {} 664 computeInsertPlace(const QPointF &)665 void computeInsertPlace(const QPointF &/*cursorPosition*/) { } 666 public: 667 668 friend class SystemTray; 669 670 /// SPEED OPTIMIZATION 671 private: 672 bool m_finishLoadOnFirstShow; 673 bool m_relayoutOnNextShow; 674 public: 675 void aboutToBeActivated(); 676 677 graphicsView()678 QGraphicsView *graphicsView() { return m_view; } 679 private: 680 QGraphicsView *m_view; 681 }; 682 683 #endif // BASKET_H 684