├── .gitignore
├── .gitmodules
├── LICENSE
├── NOTES.txt
├── Plotline.pro
├── README.markdown
├── config
└── config.xml
├── doc
├── .gitignore
├── doc.pro
├── images
│ └── qt-run-button.png
├── index.markdown
└── user
│ ├── character.markdown
│ ├── images
│ └── plotline-novel.png
│ ├── index.markdown
│ ├── novel.markdown
│ └── plotline.markdown
├── packages
└── me.rngr.plotline
│ └── meta
│ ├── installscript.qs
│ ├── license.txt
│ ├── package.xml
│ └── page.ui
├── plotline.sh
├── src
├── 3rdparty
│ └── 3rdparty.pro
├── Plotline.pro.user
├── app
│ ├── app.pro
│ ├── chapterfilter.cpp
│ ├── chapterfilter.h
│ ├── chaptermodel.cpp
│ ├── chaptermodel.h
│ ├── chapterreorderdialog.cpp
│ ├── chapterreorderdialog.h
│ ├── chapterreorderdialog.ui
│ ├── chaptersframe.cpp
│ ├── chaptersframe.h
│ ├── chaptersframe.ui
│ ├── characterframe.cpp
│ ├── characterframe.h
│ ├── characterframe.ui
│ ├── characterhighlighter.cpp
│ ├── characterhighlighter.h
│ ├── characteritemmodel.cpp
│ ├── characteritemmodel.h
│ ├── fullscreeneditor.cpp
│ ├── fullscreeneditor.h
│ ├── fullscreeneditor.ui
│ ├── main.cpp
│ ├── mainwindow.cpp
│ ├── mainwindow.h
│ ├── mainwindow.ui
│ ├── markuphighlighter.cpp
│ ├── markuphighlighter.h
│ ├── modelcheckbox.cpp
│ ├── modelcheckbox.h
│ ├── novelframe.cpp
│ ├── novelframe.h
│ ├── novelframe.ui
│ ├── plotframe.cpp
│ ├── plotframe.h
│ ├── plotframe.ui
│ ├── plotlineappframe.cpp
│ ├── plotlineappframe.h
│ ├── plotlinedialog.cpp
│ ├── plotlinedialog.h
│ ├── plotlinedialog.ui
│ ├── plotlineitemdelegate.cpp
│ ├── plotlineitemdelegate.h
│ ├── plotlineitemmodel.cpp
│ ├── plotlineitemmodel.h
│ ├── preferencesdialog.cpp
│ ├── preferencesdialog.h
│ ├── preferencesdialog.ui
│ ├── publisherdialog.cpp
│ ├── publisherdialog.h
│ ├── publisherdialog.ui
│ ├── revisiondialog.cpp
│ ├── revisiondialog.h
│ ├── revisiondialog.ui
│ ├── savethread.cpp
│ ├── savethread.h
│ ├── scenefilter.cpp
│ ├── scenefilter.h
│ ├── sceneframe.cpp
│ ├── sceneframe.h
│ ├── sceneframe.ui
│ ├── sceneitemmodel.cpp
│ ├── sceneitemmodel.h
│ ├── scenelistdialog.cpp
│ ├── scenelistdialog.h
│ ├── scenelistdialog.ui
│ ├── styleproxy.cpp
│ ├── styleproxy.h
│ ├── styleproxyparser.cpp
│ └── styleproxyparser.h
├── data
│ ├── character-worthiness.json
│ ├── novel-overview.json
│ ├── novel-part-1.json
│ ├── novel-part-2.json
│ └── novel-part-3.json
├── lib
│ ├── author.cpp
│ ├── author.h
│ ├── chapter.cpp
│ ├── chapter.h
│ ├── character.cpp
│ ├── character.h
│ ├── characterparser.cpp
│ ├── characterparser.h
│ ├── completable.cpp
│ ├── completable.h
│ ├── lib.pro
│ ├── novel.cpp
│ ├── novel.h
│ ├── plotline.cpp
│ ├── plotline.h
│ ├── revision.cpp
│ ├── revision.h
│ ├── scene.cpp
│ ├── scene.h
│ ├── serializable.cpp
│ ├── serializable.h
│ ├── utils.cpp
│ └── utils.h
├── res
│ ├── images
│ │ ├── .directory
│ │ ├── 45834457236.svg
│ │ ├── ATTRIBUTIONS.txt
│ │ ├── application-exit.png
│ │ ├── book.png
│ │ ├── document-new.png
│ │ ├── document-open-folder.png
│ │ ├── document-open.png
│ │ ├── document-save-as.png
│ │ ├── document-save.png
│ │ ├── edit-clear-locationbar-rtl.png
│ │ ├── emblem-favorite.png
│ │ ├── fill-color.png
│ │ ├── format-list-ordered.png
│ │ ├── gtk-edit.svg
│ │ ├── list-add-plotline.png
│ │ ├── list-add-user.png
│ │ ├── list-add.png
│ │ ├── list-remove-plotline.png
│ │ ├── list-remove-user.png
│ │ ├── list-remove.png
│ │ ├── plotline-launcher.svg
│ │ ├── revision.svg
│ │ ├── user-archive.png
│ │ ├── user-identity.png
│ │ ├── user-properties.png
│ │ └── utilities-file-archiver.png
│ ├── plotline.qrc
│ └── styles
│ │ ├── default-dark.json
│ │ └── default.json
└── src.pro
└── test
├── test.pro
└── unit
├── fixtures
├── chapter-deserialize.json
├── character-deserialize.json
├── novel-deserialize.json
├── revision-bug-test.json
└── revision-deserialize.json
├── main.cpp
├── testcharacterparser.cpp
├── testcharacterparser.h
├── tst_chapter.cpp
├── tst_chapter.h
├── tst_character.cpp
├── tst_character.h
├── tst_novel.cpp
├── tst_novel.h
├── tst_plotline.cpp
├── tst_plotline.h
├── tst_revision.cpp
├── tst_revision.h
├── tst_scene.cpp
├── tst_scene.h
├── tst_utils.cpp
├── tst_utils.h
└── unit.pro
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pro.user
2 | *.o
3 | test/test
4 | *.autosave
5 | qt.conf
6 | moc_*
7 | ui_*.[chp]*
8 | *~
9 | Makefile*
10 |
--------------------------------------------------------------------------------
/.gitmodules:
--------------------------------------------------------------------------------
1 | [submodule "src/3rdparty/hunspell"]
2 | path = src/3rdparty/hunspell
3 | url = https://github.com/hunspell/hunspell.git
4 | [submodule "src/3rdparty/discount"]
5 | path = src/3rdparty/discount
6 | url = https://github.com/Orc/discount.git
7 |
--------------------------------------------------------------------------------
/NOTES.txt:
--------------------------------------------------------------------------------
1 |
2 | To-Do List for v. 0.1a
3 | =======================
4 |
5 | Bugs
6 | ----
7 | ! drag & drop feature for character list can't drop.
8 | ! Sometimes adding a plotline will override another.
9 | ! FIXED Adding a scene with a plotline selected will not assign the scene
10 | to the plotline (in fact, the scene won't even be selected!).
11 | ! Plotline dialog character list doesn't filter as expected.
12 | ! FIXED Opening a novel will result in the save state automatically set to
13 | false. possibly has to do with signals being emitted.
14 | ! chapter editor doesn't break on a word.
15 | !! CRITICAL Saving before exit: mainWindow is destroyed before thread
16 | can save.
17 |
18 | Features
19 | --------
20 | + Delete functionality for
21 | + DONE Characcter
22 | + DONE Scene
23 | + Chapter
24 | + Archive functionality (might need different list structure) for...
25 | + Character
26 | + Scene
27 | + Plotline
28 | + Chapter
29 | + DONE Publish novel to flat markdown (other formats will come later).
30 | + Character name dropdown for scene frame
31 |
--------------------------------------------------------------------------------
/Plotline.pro:
--------------------------------------------------------------------------------
1 | ######################################################################
2 | # Automatically generated by qmake (3.0) Tue Jan 19 19:04:32 2016
3 | ######################################################################
4 |
5 | TEMPLATE = subdirs
6 |
7 | CONFIG += ordered
8 |
9 | SUBDIRS = src \
10 | doc
11 |
12 | CONFIG(debug, debug|release): SUBDIRS += test
13 |
14 | OTHER_FILES = \
15 | README.markdown
16 |
17 | # Copy the bash executable.
18 |
19 | unix {
20 | copydata.commands = $(COPY_DIR) "$$PWD/plotline.sh" "$$OUT_PWD"
21 | first.depends = $(first) copydata
22 | export(first.depends)
23 | export(copydata.commands)
24 | QMAKE_EXTRA_TARGETS += first copydata
25 | }
26 |
--------------------------------------------------------------------------------
/README.markdown:
--------------------------------------------------------------------------------
1 | # Plotline
2 |
3 | Plotline is an application to assist in the creation of a novel. While this does
4 | not fully replace the old-school P&P (pencil & paper) method, it is nice to have
5 | everything in one place. Some of the [planned] features include:
6 |
7 | - Planning the novel plot arc, form inciting incident to the climax.
8 | - Adding characters, with prompts for character biographies.
9 | - Creating plotlines for the novel, and assigning characters as part of the
10 | plotlines.
11 | - Adding scenes to the novel to plan out exactly how the novel will work out.
12 | - Best feature: a full-fleged editor, with markdown syntax highlighting support
13 | and a distraction-free mode.
14 | - Better feature: binding the novel content into a various format, ebook or
15 | otherwise.
16 |
17 | ## Current State
18 |
19 | The back-end works fine and passes all tests. If someone wants to go for more
20 | test coverage I wouldn't complain.
21 |
22 | After a revamp to refactor the code into the seperate tab frames I've been
23 | reconnecting the signals. The basic theory looks like this:
24 |
25 | [Main App, *novel]
26 | |
27 | +---------+--------+-----------+-----------+
28 | | | | | |
29 | Novel Character Plotline Scene Chapter
30 | Frame Frame Frame frame frame
31 | [*novel] [*novel] [*novel] [*novel] [*novel]
32 |
33 | Each frame will contain a pointer to the currently-opened novel stored in the
34 | pointer `novel`. Each frame corresponds to the named backend class, so
35 | `NovelFrame` is the view for the `Novel` class, `CharacterFrame` is the view for
36 | the `Character` class and so-on.
37 |
38 | Each frame is a subclass `PlotlineAppFrame`, which inherits the signal
39 | `novelModified()` (which will notify the `MainWindow` when a change occurs)
40 | and the slots `noNovelLoad()` (which will update the frame fields when a new
41 | novel is loaded) and `onNovelNew()` (which will clear the frame's fields).
42 |
43 | ## Getting a Development Environment Set Up
44 |
45 | ### Getting Qt
46 |
47 | Plotline was developed in Qt, a C++ applicaiton framework. If you're new to Qt,
48 | now is the best time to learn!
49 |
50 | Side note: if you're new to Qt, Qt doesn't use a conventional build system like
51 | CMake or Make. Instead, it uses QMake, which generates the Make files and meta
52 | objects. So if you try to load the project in KDevelop or Eclipse or try to
53 | compile on the command line it might get kind of frustrating. QtCreator was used
54 | to develop this application, and that's what I would recommend.
55 |
56 | Okay, back to set-up.
57 |
58 | First thing's first, you'll need to install Qt5. Either install it with your
59 | distribution's package manager (in the case of Linux) or download from
60 | [Qt.io](http://www.qt.io/) and install that way.
61 |
62 | ### Getting the source.
63 |
64 | Installing Qt should have also installed QtCreator. Open QtCreator and go to
65 | **File > New File or Project > Import Project > Git Clone**. In *Repository*
66 | enter `https://github.com/freckles-the-pirate/plotline.git`. Check
67 | **Recursive** --this will import submodules. If the current version doesn't
68 | have submodules, most likely others will.
69 |
70 | #### Command line
71 |
72 | Alternatively, if you're a command-line mastro, you can git clone the
73 | repository:
74 |
75 | $ git clone https://github.com/freckles-the-pirate/plotline.git
76 | $ cd plotline
77 | $ git submodule init
78 | $ git submdoule sync
79 |
80 | And then open the project with **File > Open File or Project**, and open the
81 | Project (`.pro`) file.
82 |
83 |
84 | ### Important!!! Set the Library path
85 |
86 | One more thing needs to be attended to. The core application code (in **lib** )
87 | is a static library in order to allow linking with either the **test**
88 | subproject or the **app** subproject.
89 |
90 | To add this path to the library, go to the **Projects** tab along the lefthand
91 | side of QtDesigner. Up at the top click on the **Run** tab. Expand the
92 | **Environment** section and modify the `LD_LIBRARY_PATH` variable to append the
93 | path `../lib/`. For example, if the original value was
94 |
95 | /usr/lib/x86_64-linux-gnu/
96 |
97 | Modify the value to look like this:
98 |
99 | /usr/lib/x86_64-linux-gnu/:../lib/
100 |
101 | Remember, `:` means "append" in BASH. ;-)
102 |
103 | Do the same for the other subprojects by selecting the run button (that looks
104 | like this:  )
105 |
--------------------------------------------------------------------------------
/config/config.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Plotline
4 | 0.0.1a
5 | Plotline Installer
6 | Renegade Engineer
7 | Authoring
8 | @HomeDir@/Plotline
9 |
10 |
--------------------------------------------------------------------------------
/doc/.gitignore:
--------------------------------------------------------------------------------
1 | # This file is used to ignore files which are generated
2 | # ----------------------------------------------------------------------------
3 |
4 | *~
5 | *.autosave
6 | *.a
7 | *.core
8 | *.moc
9 | *.o
10 | *.obj
11 | *.orig
12 | *.rej
13 | *.so
14 | *.so.*
15 | *_pch.h.cpp
16 | *_resource.rc
17 | *.qm
18 | .#*
19 | *.*#
20 | core
21 | !core/
22 | tags
23 | .DS_Store
24 | *.debug
25 | Makefile*
26 | *.prl
27 | *.app
28 | moc_*.cpp
29 | ui_*.h
30 | qrc_*.cpp
31 | Thumbs.db
32 | *.res
33 | *.rc
34 | /.qmake.cache
35 | /.qmake.stash
36 |
37 | # qtcreator generated files
38 | *.pro.user*
39 |
40 | # xemacs temporary files
41 | *.flc
42 |
43 | # Vim temporary files
44 | .*.swp
45 |
46 | # Visual Studio generated files
47 | *.ib_pdb_index
48 | *.idb
49 | *.ilk
50 | *.pdb
51 | *.sln
52 | *.suo
53 | *.vcproj
54 | *vcproj.*.*.user
55 | *.ncb
56 | *.sdf
57 | *.opensdf
58 | *.vcxproj
59 | *vcxproj.*
60 |
61 | # MinGW generated files
62 | *.Debug
63 | *.Release
64 |
65 | # Python byte code
66 | *.pyc
67 |
68 | # Binaries
69 | # --------
70 | *.dll
71 | *.exe
72 |
73 |
74 |
--------------------------------------------------------------------------------
/doc/doc.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = aux
2 |
3 | DISTFILES += \
4 | index.markdown \
5 | user/index.markdown \
6 | user/novel.markdown \
7 | user/plotline.markdown \
8 | user/scene.markdown \
9 | user/character.markdown
10 |
--------------------------------------------------------------------------------
/doc/images/qt-run-button.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/doc/images/qt-run-button.png
--------------------------------------------------------------------------------
/doc/index.markdown:
--------------------------------------------------------------------------------
1 | # Plotline
2 |
3 | ## Setting Up for Development
4 |
5 | Plotline is written in Qt, and, therefore, it's really easy to set up in
6 | QtCreator. If you're new to QtCreator, now's the perfect time to get yourself
7 | acquainted! Head over to [qt.io](https://qt.io) to get set up with Qt and
8 | QtCreator.
9 |
10 | Once you're set up, clone the repository...
11 |
12 | $ git clone {{ plotline-repository }}
13 |
14 | ...and initialize the submodules:
15 |
16 | $ git submodule init
17 |
18 | Three other submodules will be cloned:
19 |
20 | - CuteMarkEd: heavily used for the Markdown editor.
21 | - discount: library used to Markdown parsing (dependency of CuteMarkEd)
22 | - hunspell: spell-checker library.
23 |
24 | ## IMPORTANT!! BUILD EACH SUBMODULE!!
25 |
26 | I'll be working on automatically building each submodule by using QMake. Until
27 | then each submodule should be built before building Plotline.
28 |
29 | $ cd src/3rdparty/discount/
30 | $ ./configure && make; # don't run install (you can, but there's no point)
31 | $ cd ../hunspell/
32 | $ ./configure && make
33 |
34 | Since CuteMarkEd uses the QMake build system it will be handled by Plotline's
35 | QMake.
36 |
--------------------------------------------------------------------------------
/doc/user/character.markdown:
--------------------------------------------------------------------------------
1 | # Characters
2 |
3 | ## Character List
4 |
5 | The character list can be used for listing characters used in your novel. The
6 | overall name is used as the list entry. Characters can be added, removed,
7 | archived, or edited.
8 |
9 | ## Character Details
10 |
11 | To the right of the character list is the character. The following fields are
12 | used to add details to the character:
13 |
14 | ### Name
15 |
16 | Name of your character. This will be the display name throughout the rest of
17 | your novel.
18 |
19 | ### Label
20 |
21 | The label is used to easily identify your characters in writing scenes or
22 | plotlines. The label will be automatically filled in based on the **Name** and
23 | is calculated based on the first two letters of each character's name. For
24 | example, for the name `John Doe` Plotline will fill in the **Label** as `JoDo`.
25 | Of course, this can always be changed.
26 |
27 | To refer to the character by label (the preferred method), precede the label
28 | with an "at" (`@`) character. So to refer to the character *John Doe* in the
29 | [Scenes](./scene.markdown) or [Plotlines](./plotline.markdown) type `@JoDo`.
30 | See the [Scenes](./scene.markdown) documentation for more information.
31 |
32 | ### Nick Name
33 |
34 | Every character has a nick name now, right? This is for your records only.
35 |
36 | ### Color
37 |
38 | The developer of Plotline believes everything is better in color! That's why
39 | you have the ability to choose a color for your character.
40 |
41 | To choose a color, click the **Choose Color** button. If you do not want a
42 | color for your character, click the **Clear Color** button.
43 |
44 | Besides being the
45 | background color for the character in the **Character List** the color will
46 | also be the background color when a *character label* is detected in the
47 | [Scenes](./scene.markdown) or [Plotlines](./plotline.markdown).
48 |
49 | ### Headshot
50 |
51 | A headshot is useful to help visualize a person and make the character more
52 | believable.
53 |
54 | A headshot can be selected from your hard drive. To select a headshot, click
55 | the **Choose Headshot** button to select a headhshot. The headshot is saved
56 | within the `.pln` file itself and cannot be exported from the application.
57 |
58 | ### Add Character
59 |
60 | To add a character, click the **Add Character** button. A new entry will be
61 | displayed in the list and the **Character Details** on the right will be
62 | enabled, allowing you to modify the character's details.
63 |
64 | ### Remove Character
65 |
66 | To remove a character, select the character and click **Remove Character**. A
67 | dialog will open asking if you would like to really remove the character
68 | (annoying, I know, but we don't want any lawsuits). Click **Delete** to remove
69 | the character or **Cancel** to keep the character.
--------------------------------------------------------------------------------
/doc/user/images/plotline-novel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/doc/user/images/plotline-novel.png
--------------------------------------------------------------------------------
/doc/user/index.markdown:
--------------------------------------------------------------------------------
1 | # Plotline Usage
2 |
3 | ## Why use all these tabs, anyway? Can't I just write?
4 |
5 | I know what it's like. It's really tempting to skip all the steps in writing a
6 | novel. "I have the most epic climax in mind! I just want to get it on paper!"
7 |
8 | Alright, I understand. All writers do. However, I'd highly recommend going
9 | through each aspect of your novel and flesh out exactly how it's going to work
10 | out. This is especially handy if you're writing something with a non-linear
11 | plot or complex storylines.
12 |
13 | In fact I'd even recommend using the old pencil-and-paper method before you
14 | even open Plotline! Plotline isn't intended to be a replacement for the work
15 | … It's only indended to be a digital conversion.
16 |
17 | But, assuming you've been a good little writer and done everything correctly,
18 | here's how to use plotline.
19 |
20 | ## The Overall View
21 |
22 | ### Novel
23 |
24 | For the app's intents and purposes, the project you're working on is called a
25 | **novel** (for obvious reasons).
26 |
27 | The first tab in the notebook is used to get (you) the author thinking of what
28 | novel you're going to write. Of course, the title is important, but other
29 | aspects are just as important to think about, such as point of view and tense.
30 |
31 | ### Characters
32 |
33 | Have you ever read a novel only to find you couldn't get emotionally-invested
34 | in characters? One big reason this happens is because authors fail to flesh out
35 | characters--namely, the major characters.
36 |
37 | The *Characters* tab provides prompts to develop these deep characters.
38 |
39 | ### Plotline
40 |
41 | For novels that have a non-linear plotline (meaning 2 or more plotlines
42 | involved in the storyline), this view is helpful for getting an idea what will
43 | happen with teach plotline, and which characters are involved.
44 |
45 | ### Scene
46 |
47 | A scene is an event that occurs within a plotline. The scene tab allows you to
48 | specify the headline (a quick description of what's going on) and the action
49 | (a more detailed, step-by-step description of what's going on).
50 |
51 | ### Chapter
52 |
53 | Here you can actually write your novel.
54 |
55 | ## The Menu
56 |
57 | ### Novel > Revisions
58 |
59 | Add revisions to your novel. Each revision is exactly
--------------------------------------------------------------------------------
/doc/user/novel.markdown:
--------------------------------------------------------------------------------
1 | # Novel Frame
2 |
3 | The *Novel Frame* is the place to store overall details on the novel being
4 | written. When [binding a novel](./binding.markdown), Plotline will pull details
5 | from this page. Here is a detailed look at each of the pages for the novel frame.
6 |
7 | The components to this frame are based heavily off
8 | [Annie Neugebauer's Novel Plotting Prompts](http://annieneugebauer.com/the-organized-writer-2/novel-plotting-worksheets/).
9 |
10 | ## Overview
11 |
12 | The overview is for the novel title, point of view (POV), and tense. Only the
13 | title will be used when publishing the novel; the POV, tense, and setting will
14 | not be published.
15 |
16 | ## Author
17 |
18 | Information on the author of the novel. While not required, highly recommended.
19 | All this information will be published when the novel is bound and can be added
20 | or omitted as desired.
21 |
--------------------------------------------------------------------------------
/doc/user/plotline.markdown:
--------------------------------------------------------------------------------
1 | # Plotline
2 |
3 | This will mainly be used for non-linear stories (meaning, stories with more
4 | than one plotline), but can be useful for any type of story.
5 |
6 | ## Plotline Table
7 |
8 | Compared to the [Character Tab](./character.markdown) the plotline tab includes
9 | a table where the details are listed. Three fields--or columns--are displayed
10 | within the table and are available within the **Plotline Dialog**
11 |
12 | ### Brief
13 |
14 | A one-liner describing what happens with this plotline. Used for displaying in
15 | subsequent tabs.
16 |
17 | ### Synopsis
18 |
19 | A more detailed description of this scene. Used more for your reference.
20 |
21 | ### Characters Involved.
22 |
23 | Characters created in the [Character Tab](./character.markdown) will be
24 | displayed here in a comma-separated list.
25 |
26 | ## Actions
27 |
28 | The following actions can be performed on plotlines.
29 |
30 | ### Add Plotline
31 |
32 | On adding a plotline, the plotline dialog will be displayed to enter initial
33 | values. Upon clicking **OK** the dialog will be closed and the new plotline
34 | will be added to the plotline table.
35 |
36 | ### Edit Plotline
37 |
38 | To edit a plotline, either double-click on the plotline to edit, or select the
39 | plotline and click the **Edit Plotline** button. A **Plotline Dialog** will be
40 | displayed with the plotline to be edited.
41 |
42 | ### Delete Plotline.
43 |
44 | To delete a plotline select the plotline you'd like to delete and click the
45 | **Delete Plotline** button. A dialog will be displayed confirming you'd like to
46 | delete the plotline. Click **OK** to delete the plotline, **Cancel** if you do
47 | not want to delete it. The plotline will be removed from the table.
48 |
49 | ## Plotline Dialog
50 |
51 | This dialog will be displayed when either creating or modifying a plotline. The
52 | fields listed above will be displayed in the dialog in addition to two more
53 | fields:
54 |
55 | ### Color
56 |
57 | The plotline can be given a color. This color will be used for the background
58 | color in the **Plotline Table** as well as the background color for the scenes
59 | in the [Scenes Tab](./scenes.markdown).
60 |
61 | To assign a color click on the **Choose Color** button. To clear the color
62 | click the **Clear Color** button.
63 |
64 | ### Character Search Field
65 |
66 | Directly above the **Characters Involved** is a search field. To search by name
67 | simply type in the character's name. The checkboxes will be filtered
68 | dynamically. Users can also be filtered by label. Simply start the search with
69 | an "at sign" (`@`) to display results with that character label. To display all
70 | the characters again empty the search field.
--------------------------------------------------------------------------------
/packages/me.rngr.plotline/meta/installscript.qs:
--------------------------------------------------------------------------------
1 | function Controller()
2 | {
3 | }
4 |
--------------------------------------------------------------------------------
/packages/me.rngr.plotline/meta/package.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Plotline
4 |
5 | Application to create, manage, and publish a novel.
6 |
7 | 1.0
8 | 2016-03-04
9 | me.rngr.plotline
10 |
11 |
12 |
13 | script
14 |
15 |
16 | page.ui
17 |
18 |
19 |
--------------------------------------------------------------------------------
/packages/me.rngr.plotline/meta/page.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | Page
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 300
11 |
12 |
13 |
14 | Dynamic page example
15 |
16 |
17 | -
18 |
19 |
20 | Qt::AlignCenter
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/plotline.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | # Thanks to https://stackoverflow.com/a/246128
4 | DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
5 |
6 | LD_LIBRARY_PATH=$LD_LIBRARY_PATH:src/lib $DIR/src/app/plotline
7 |
--------------------------------------------------------------------------------
/src/3rdparty/3rdparty.pro:
--------------------------------------------------------------------------------
1 | TEMPLATE = subdirs
2 |
3 | SUBDIRS += CuteMarkEd/3rdparty/
4 |
5 | SOURCES += CuteMarkEd/app/markdowneditor.cpp \
6 | CuteMarkEd/app/markdownhighlighter.cpp \
7 | CuteMarkEd/app/highlightworkerthread.cpp
8 |
9 | HEADERS += CuteMarkEd/app/markdowneditor.h \
10 | CuteMarkEd/app/markdownhighlighter.h \
11 | CuteMarkEd/app/highlightworkerthread.h
12 |
13 | INCLUDEPATH += CuteMarkEd/3rdparty/hunspell/src/
14 |
15 | # build order: 3rdparty -> libs -> app-static -> app & test
16 | libs.depends = 3rdparty
17 | app.depends = libs app-static
18 |
--------------------------------------------------------------------------------
/src/app/app.pro:
--------------------------------------------------------------------------------
1 |
2 | TEMPLATE = app
3 |
4 | TARGET = Plotline
5 |
6 | QT += core gui webkitwidgets printsupport
7 |
8 | # greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
9 |
10 | INCLUDEPATH += \
11 | ../lib
12 |
13 | HEADERS += mainwindow.h \
14 | characteritemmodel.h \
15 | sceneitemmodel.h \
16 | preferencesdialog.h \
17 | plotlineitemmodel.h \
18 | plotlineitemdelegate.h \
19 | plotlinedialog.h \
20 | characterframe.h \
21 | plotframe.h \
22 | sceneframe.h \
23 | chaptersframe.h \
24 | novelframe.h \
25 | plotlineappframe.h \
26 | modelcheckbox.h \
27 | characterhighlighter.h \
28 | chaptermodel.h \
29 | revisiondialog.h \
30 | markuphighlighter.h \
31 | styleproxy.h \
32 | styleproxyparser.h \
33 | scenelistdialog.h \
34 | fullscreeneditor.h \
35 | chapterfilter.h \
36 | chapterreorderdialog.h \
37 | publisherdialog.h \
38 | scenefilter.h \
39 | savethread.h
40 |
41 | SOURCES += main.cpp \
42 | mainwindow.cpp \
43 | characteritemmodel.cpp \
44 | sceneitemmodel.cpp \
45 | preferencesdialog.cpp \
46 | plotlineitemmodel.cpp \
47 | plotlineitemdelegate.cpp \
48 | plotlinedialog.cpp \
49 | characterframe.cpp \
50 | plotframe.cpp \
51 | sceneframe.cpp \
52 | chaptersframe.cpp \
53 | novelframe.cpp \
54 | plotlineappframe.cpp \
55 | modelcheckbox.cpp \
56 | characterhighlighter.cpp \
57 | chaptermodel.cpp \
58 | revisiondialog.cpp \
59 | markuphighlighter.cpp \
60 | styleproxy.cpp \
61 | styleproxyparser.cpp \
62 | scenelistdialog.cpp \
63 | fullscreeneditor.cpp \
64 | chapterfilter.cpp \
65 | chapterreorderdialog.cpp \
66 | publisherdialog.cpp \
67 | scenefilter.cpp \
68 | savethread.cpp
69 |
70 | ##
71 | # Depending on whether we're building the libraries statically or dynamically,
72 | # Either the .so will be found or the .a will be found.
73 | # There is probably a more elegant solution.
74 | ##
75 |
76 | FORMS += mainwindow.ui \
77 | preferencesdialog.ui \
78 | plotlinedialog.ui \
79 | characterframe.ui \
80 | plotframe.ui \
81 | sceneframe.ui \
82 | chaptersframe.ui \
83 | novelframe.ui \
84 | revisiondialog.ui \
85 | scenelistdialog.ui \
86 | fullscreeneditor.ui \
87 | chapterreorderdialog.ui \
88 | publisherdialog.ui
89 |
90 | RESOURCES += ../res/plotline.qrc
91 |
92 | styles.path = $$DESTDIR/styles
93 | styles.files = $$PWD/styles/*.json
94 |
95 | INSTALLS += styles
96 |
97 | CONFIG += c++11
98 |
99 | #REQUIRES += $$PWD/../lib
100 | #LIBS += $$PWD/../lib
101 |
102 | win32:CONFIG(release, debug|release): LIBS += -L$$OUT_PWD/../lib/release/ -lplotline
103 | else:win32:CONFIG(debug, debug|release): LIBS += -L$$OUT_PWD/../lib/debug/ -lplotline
104 | else:unix: LIBS += -L$$OUT_PWD/../lib/ -lplotline
105 |
106 | INCLUDEPATH += $$PWD/../lib
107 | DEPENDPATH += $$PWD/../lib
108 |
--------------------------------------------------------------------------------
/src/app/chapterfilter.cpp:
--------------------------------------------------------------------------------
1 | #include "chapterfilter.h"
2 |
3 | ChapterFilter::ChapterFilter(Plotline *plotline, QObject *parent) : QSortFilterProxyModel(parent)
4 | {
5 | mPlotline = plotline;
6 | }
7 |
8 | bool ChapterFilter::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
9 | {
10 | if (0 == mPlotline)
11 | return true;
12 | ChapterModel *model = (ChapterModel *) sourceModel();
13 | QJsonArray sceneIds = model->data(model->index(source_row, 0),
14 | ChapterModel::SceneRole).toJsonArray();
15 |
16 | Scene *scene = 0;
17 | bool found = false;
18 | for (QJsonValue v : sceneIds){
19 | scene = mPlotline->novel()->scene(v.toVariant().toUuid());
20 | if (scene == 0){
21 | qWarning() << "chapter filter: Could not find scene with id"
22 | << v.toInt();
23 | }
24 | if (scene->plotline() == mPlotline)
25 | found = true;
26 | }
27 | return found;
28 | }
29 |
30 | //bool ChapterFilter::filterAcceptsColumn(int source_column, const QModelIndex &source_parent) const
31 | //{
32 | // return true; //we're row-dependent, not column-dependent
33 | //}
34 |
35 | Plotline *ChapterFilter::plotline() const
36 | {
37 | return mPlotline;
38 | }
39 |
40 | void ChapterFilter::setPlotline(Plotline *plotline)
41 | {
42 | mPlotline = plotline;
43 | emit this->filterChanged();
44 | }
45 |
--------------------------------------------------------------------------------
/src/app/chapterfilter.h:
--------------------------------------------------------------------------------
1 | #ifndef CHAPTERFILTER_H
2 | #define CHAPTERFILTER_H
3 |
4 | #include "plotline.h"
5 | #include "chaptermodel.h"
6 |
7 | class ChapterFilter : public QSortFilterProxyModel
8 | {
9 | Q_OBJECT
10 | public:
11 | explicit ChapterFilter(Plotline *plotline = 0, QObject *parent = 0);
12 |
13 | Plotline *plotline() const;
14 | void setPlotline(Plotline *plotline);
15 |
16 | // bool insertRows(int row, int count, const QModelIndex &parent);
17 | // bool removeRows(int row, int count, const QModelIndex &parent);
18 |
19 | protected:
20 | bool filterAcceptsRow(int source_row, const QModelIndex & source_parent) const;
21 | // bool filterAcceptsColumn(int source_column, const QModelIndex & source_parent) const;
22 |
23 | private:
24 | Plotline *mPlotline;
25 |
26 | signals:
27 |
28 | public slots:
29 | };
30 |
31 | #endif // CHAPTERFILTER_H
32 |
--------------------------------------------------------------------------------
/src/app/chaptermodel.h:
--------------------------------------------------------------------------------
1 | #ifndef CHAPTERMODEL_H
2 | #define CHAPTERMODEL_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include "chapter.h"
13 |
14 | class ChapterModel : public QAbstractTableModel
15 | {
16 | Q_OBJECT
17 | public:
18 | explicit ChapterModel(Novel *novel, QObject *parent = 0);
19 |
20 |
21 | // Overrides
22 | int rowCount(const QModelIndex &parent = QModelIndex()) const;
23 | int columnCount(const QModelIndex & parent = QModelIndex()) const;
24 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
25 | QVariant headerData(int section, Qt::Orientation orientation,
26 | int role = Qt::DisplayRole) const;
27 | bool setData(const QModelIndex &index, const QVariant &value,
28 | int role = Qt::DisplayRole);
29 |
30 | bool insertRows(int row, int count,
31 | const QModelIndex & parent = QModelIndex());
32 | bool removeRows(int row, int count,
33 | const QModelIndex & parent = QModelIndex());
34 | bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
35 | const QModelIndex &destinationParent, int destinationChild);
36 |
37 |
38 | Qt::ItemFlags flags(const QModelIndex & index) const;
39 | Qt::DropActions supportedDropActions() const;
40 |
41 | // QMimeData *dropMimeData(const QMimeData *data, Qt::DropAction action,
42 | // int row, int column, const QModelIndex &parent);
43 |
44 | Novel *novel() const;
45 | void setNovel(Novel *novel);
46 |
47 | // Custom roles
48 | static const int IdRole = Qt::UserRole,
49 | NumberRole = Qt::UserRole + 1,
50 | TitleRole = Qt::UserRole + 2,
51 | ContentRole = Qt::UserRole + 3,
52 | RevisionRole = Qt::UserRole + 4,
53 | RevisionMarkableRole = Qt::UserRole + 5,
54 | CompleteRole = Qt::UserRole + 6,
55 | SceneRole = Qt::UserRole + 7,
56 | AddSceneRole = Qt::UserRole + 8,
57 | RemoveSceneRole = Qt::UserRole + 9;
58 | // Column numbers
59 | static const int NUMBER = 0,
60 | TITLE = 1;
61 |
62 | private:
63 | Novel *mNovel = 0;
64 | int mRowCount, mColCount;
65 |
66 | signals:
67 |
68 | public slots:
69 | // void rowsMoved(const QModelIndex & parent, int start,
70 | // int end, const QModelIndex & destination,
71 | // int row);
72 | };
73 |
74 | #endif // CHAPTERMODEL_H
75 |
--------------------------------------------------------------------------------
/src/app/chapterreorderdialog.cpp:
--------------------------------------------------------------------------------
1 | #include "chapterreorderdialog.h"
2 | #include "ui_chapterreorderdialog.h"
3 |
4 | ChapterReorderDialog::ChapterReorderDialog(QTableView *tableView,
5 | QWidget *parent) :
6 | QDialog(parent),
7 | ui(new Ui::ChapterReorderDialog)
8 | {
9 | ui->setupUi(this);
10 |
11 | mTableView = tableView;
12 |
13 | ChapterModel *model = (ChapterModel *) tableView->model();
14 | QModelIndex index, selected = tableView->currentIndex();
15 | QString label, number, title;
16 |
17 | for (int row = 0; row < model->rowCount(); ++row){
18 | index = model->index(row, 0);
19 | if (selected != index){
20 | number = model->data(index, ChapterModel::NumberRole).toString();
21 | title = model->data(index, ChapterModel::TitleRole).toString();
22 | label = QString("Chapter ") + number;
23 |
24 | if (!title.isNull())
25 | label += QString(": ") + title;
26 | ui->chapterList->addItem(label, QVariant(row));
27 | }
28 | }
29 | }
30 |
31 | ChapterReorderDialog::~ChapterReorderDialog()
32 | {
33 | delete ui;
34 | }
35 |
36 | void ChapterReorderDialog::on_ChapterReorderDialog_accepted()
37 | {
38 | ChapterModel *model = (ChapterModel *) mTableView->model();
39 | QModelIndex selected = mTableView->currentIndex();
40 |
41 | model->moveRows(QModelIndex(), selected.row(), 1,
42 | QModelIndex(),
43 | ui->chapterList->currentData().toInt());
44 | }
45 |
--------------------------------------------------------------------------------
/src/app/chapterreorderdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef CHAPTERREORDERDIALOG_H
2 | #define CHAPTERREORDERDIALOG_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "chapter.h"
9 | #include "chaptermodel.h"
10 |
11 | namespace Ui {
12 | class ChapterReorderDialog;
13 | }
14 |
15 | class ChapterReorderDialog : public QDialog
16 | {
17 | Q_OBJECT
18 |
19 | public:
20 | explicit ChapterReorderDialog(QTableView *chapter = 0, QWidget *parent = 0);
21 | ~ChapterReorderDialog();
22 |
23 | private slots:
24 | void on_ChapterReorderDialog_accepted();
25 |
26 | private:
27 | Ui::ChapterReorderDialog *ui;
28 |
29 | QTableView *mTableView;
30 | };
31 |
32 | #endif // CHAPTERREORDERDIALOG_H
33 |
--------------------------------------------------------------------------------
/src/app/chapterreorderdialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | ChapterReorderDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 103
11 |
12 |
13 |
14 |
15 | 0
16 | 0
17 |
18 |
19 |
20 |
21 | 16777215
22 | 286
23 |
24 |
25 |
26 | Dialog
27 |
28 |
29 | -
30 |
31 |
32 | QLayout::SetMaximumSize
33 |
34 |
-
35 |
36 |
37 | Place before chapter:
38 |
39 |
40 |
41 | -
42 |
43 |
44 | -
45 |
46 |
47 | Qt::Horizontal
48 |
49 |
50 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 | buttonBox
62 | accepted()
63 | ChapterReorderDialog
64 | accept()
65 |
66 |
67 | 248
68 | 254
69 |
70 |
71 | 157
72 | 274
73 |
74 |
75 |
76 |
77 | buttonBox
78 | rejected()
79 | ChapterReorderDialog
80 | reject()
81 |
82 |
83 | 316
84 | 260
85 |
86 |
87 | 286
88 | 274
89 |
90 |
91 |
92 |
93 |
94 |
--------------------------------------------------------------------------------
/src/app/chaptersframe.h:
--------------------------------------------------------------------------------
1 | #ifndef CHAPTERSFRAME_H
2 | #define CHAPTERSFRAME_H
3 |
4 | #include
5 | #include
6 | #include "plotlineappframe.h"
7 | #include "chaptermodel.h"
8 | #include "markuphighlighter.h"
9 | #include "scenelistdialog.h"
10 | #include "fullscreeneditor.h"
11 | #include "chapterfilter.h"
12 | #include "chapterreorderdialog.h"
13 |
14 | class PlotlineAppFrame;
15 |
16 | namespace Ui {
17 | class ChaptersFrame;
18 | }
19 |
20 | class ChaptersFrame : public PlotlineAppFrame
21 | {
22 | Q_OBJECT
23 |
24 | public:
25 | explicit ChaptersFrame(MainWindow *mainWindow, QWidget *parent = 0);
26 | ~ChaptersFrame();
27 |
28 | private:
29 | Ui::ChaptersFrame *ui;
30 |
31 | Chapter *mSelectedChapter;
32 | ChapterModel *mModel;
33 | ChapterFilter *mFilter;
34 |
35 | bool mHasDistractions = true;
36 |
37 | QWidgetList mDistractions;
38 | QTimer *mDistractionTimer;
39 | MarkupHighlighter *mHighlighter;
40 |
41 | static const int PlotlineRole = Qt::UserRole+1;
42 |
43 | void connectSlots();
44 | void disconnectSlots();
45 | void blockEditableSignals();
46 | void unblockEditableSignals();
47 |
48 | signals:
49 | void chapterSelected();
50 | void revisionChanged();
51 | void revisionSet();
52 | void chapterModified();
53 |
54 | void hideDistractions();
55 | void showDistractions();
56 |
57 | public slots:
58 | void onNovelLoad();
59 | void onNovelNew();
60 |
61 | void onChapterModified();
62 | void onChapterSelected();
63 | void onRevisionChanged();
64 | void onRevisionSet();
65 | void onHideDistractions();
66 | void onShowDistractions();
67 |
68 | protected:
69 | void mouseMoveEvent(QMouseEvent *event);
70 |
71 | private slots:
72 | void on_chapterFilter_activated(int index);
73 | void on_addChapter_clicked();
74 | void on_archiveChapter_clicked();
75 | void on_deleteChapter_clicked();
76 | void on_assignScenes_clicked();
77 | void on_chapterTitle_textEdited(const QString &arg1);
78 | void on_chapterTable_activated(const QModelIndex &index);
79 | void on_chapterTable_clicked(const QModelIndex &index);
80 | void on_chapterComplete_toggled(bool checked);
81 | void on_chapterRevision_valueChanged(int arg1);
82 | // void on_chapterContent_textChanged();
83 | void on_chapterDistractionFree_clicked();
84 | void onFullscreenEditorDestroyed(QObject *object);
85 |
86 | void clearLayout(bool enabled, bool clear);
87 | void onDistractionTimeout(void);
88 | void onChapterContentModified(int from, int charsAdded, int charsRemoved);
89 | void on_reorderChapter_clicked();
90 | };
91 |
92 | #endif // CHAPTERSFRAME_H
93 |
--------------------------------------------------------------------------------
/src/app/characterframe.h:
--------------------------------------------------------------------------------
1 | #ifndef CHARACTERFRAME_H
2 | #define CHARACTERFRAME_H
3 |
4 | #include
5 | #include "plotlineappframe.h"
6 | #include "characteritemmodel.h"
7 |
8 | namespace Ui {
9 | class CharacterFrame;
10 | }
11 |
12 | class CharacterFrame : public PlotlineAppFrame
13 | {
14 | Q_OBJECT
15 |
16 | public:
17 | explicit CharacterFrame(MainWindow *mainWindow, QWidget *parent = 0);
18 | ~CharacterFrame();
19 |
20 | signals:
21 | void characterModified();
22 | void characterListModified();
23 |
24 | public slots:
25 | void onNovelLoad();
26 | void onNovelNew();
27 |
28 | void on_addCharacter_clicked();
29 |
30 | void onCharacterModified();
31 | void onCharacterListModified();
32 |
33 | void on_characterList_activated(const QModelIndex &index);
34 |
35 | void on_characterList_clicked(const QModelIndex &index);
36 |
37 | void on_characterName_textChanged(const QString &arg1);
38 |
39 | private slots:
40 |
41 | void on_characterColor_clicked();
42 | void on_chooseHeadshot_clicked();
43 | void on_characterLabel_textChanged(const QString &arg1);
44 |
45 | void on_archiveCharacter_clicked();
46 |
47 | void on_deleteCharacter_clicked();
48 |
49 | private:
50 | Ui::CharacterFrame *ui;
51 |
52 | CharacterModel *mModel;
53 | Character *mSelectedCharacter;
54 |
55 | // methods
56 | void setCharacterHeadshot();
57 | void clearCharacterHeadshot();
58 |
59 | void setButtonColor(const QColor &color);
60 | void clearButtonColor();
61 | };
62 |
63 | #endif // CHARACTERFRAME_H
64 |
--------------------------------------------------------------------------------
/src/app/characterhighlighter.cpp:
--------------------------------------------------------------------------------
1 | #include "characterhighlighter.h"
2 | #include
3 |
4 | CharacterHighlighter::CharacterHighlighter(Novel *novel, QTextDocument *parent)
5 | : QSyntaxHighlighter(parent)
6 | {
7 | mNovel = novel;
8 | }
9 |
10 | CharacterHighlighter::CharacterHighlighter(Novel *novel, QObject *parent)
11 | : QSyntaxHighlighter(parent)
12 | {
13 | mNovel = novel;
14 | }
15 |
16 | void CharacterHighlighter::highlightBlock(const QString &text)
17 | {
18 |
19 | ParsedCharacterSet set = ParsedCharacterSet::parse(mNovel, text);
20 |
21 | for (int i : set.keys()){
22 | QTextCharFormat format;
23 | QColor bgColor = set.value(i)->color();
24 | QColor textColor = QColor(0, 0, 0); // Black text.
25 | if ((255 / 2) > bgColor.value())
26 | textColor = QColor(255, 255, 255); // White text.
27 | format.setFontWeight(QFont::Bold);
28 | format.setBackground(QBrush(bgColor));
29 | format.setForeground(QBrush(textColor));
30 |
31 | qDebug() << "Formating @" << i << ":" << text;
32 |
33 | setFormat(i, set.value(i)->label().count()+1, format);
34 | }
35 | }
36 |
37 | Novel *CharacterHighlighter::novel() const
38 | {
39 | return mNovel;
40 | }
41 |
42 | void CharacterHighlighter::setNovel(Novel *novel)
43 | {
44 | mNovel = novel;
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/src/app/characterhighlighter.h:
--------------------------------------------------------------------------------
1 | #ifndef CHARACTERHIGHLIGHTER_H
2 | #define CHARACTERHIGHLIGHTER_H
3 |
4 | #include
5 | #include
6 |
7 | #include "novel.h"
8 | #include "characterparser.h"
9 |
10 | class CharacterHighlighter : public QSyntaxHighlighter
11 | {
12 | Q_OBJECT
13 | public:
14 | CharacterHighlighter(Novel *novel, QTextDocument *parent = 0);
15 | CharacterHighlighter(Novel *novel, QObject *parent = 0);
16 |
17 | Novel *novel() const;
18 | void setNovel(Novel *novel);
19 |
20 | protected:
21 | void highlightBlock(const QString &text) Q_DECL_OVERRIDE;
22 |
23 | signals:
24 |
25 | public slots:
26 |
27 | private:
28 | Novel *mNovel;
29 | };
30 |
31 | #endif // CHARACTERHIGHLIGHTER_H
32 |
--------------------------------------------------------------------------------
/src/app/characteritemmodel.h:
--------------------------------------------------------------------------------
1 | #ifndef CHARACTERITEMMODEL_H
2 | #define CHARACTERITEMMODEL_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "scene.h"
9 |
10 | class CharacterModel : public QAbstractListModel
11 | {
12 | public:
13 | CharacterModel(Novel *novel, QObject *parent = 0);
14 |
15 | const static int CharacterIdRole = Qt::UserRole;
16 |
17 | void addCharacter();
18 |
19 | int rowCount(const QModelIndex & parent = QModelIndex()) const;
20 | bool insertRows(int row, int count, const QModelIndex & parent = QModelIndex());
21 | bool removeRows(int row, int count, const QModelIndex & parent = QModelIndex());
22 | bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
23 | const QModelIndex &destinationParent, int destinationChild);
24 |
25 | QVariant data(const QModelIndex & index,
26 | int role = Qt::DisplayRole) const;
27 | QVariant headerData(int section, Qt::Orientation orientation,
28 | int role = Qt::DisplayRole) const;
29 | bool setData(const QModelIndex & index, const QVariant & value,
30 | int role = Qt::EditRole);
31 | Qt::ItemFlags flags(const QModelIndex & index) const;
32 | Qt::DropActions supportedDropActions();
33 |
34 | QModelIndex lastRow() const;
35 |
36 | // roles
37 | static const int NameRole = Qt::UserRole + 1,
38 | NicknameRole = Qt::UserRole + 2,
39 | LabelRole = Qt::UserRole + 4,
40 | HeadshotRole = Qt::UserRole + 8,
41 | ColorRole = Qt::UserRole + 16,
42 | ArchivedRole = Qt::UserRole + 32;
43 |
44 | private:
45 |
46 | signals:
47 | CharacterModel *mParent;
48 | Novel *mNovel;
49 |
50 | public slots:
51 | };
52 |
53 | #endif // CHARACTERITEMMODEL_H
54 |
--------------------------------------------------------------------------------
/src/app/fullscreeneditor.h:
--------------------------------------------------------------------------------
1 | #ifndef FULLSCREENEDITOR_H
2 | #define FULLSCREENEDITOR_H
3 |
4 | #include
5 | #include "revision.h"
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "markuphighlighter.h"
11 | #include
12 | #include
13 |
14 | namespace Ui {
15 | class FullScreenEditor;
16 | }
17 |
18 | class FullScreenEditor : public QMainWindow
19 | {
20 | Q_OBJECT
21 |
22 | public:
23 | explicit FullScreenEditor(QWidget *parent = 0);
24 | explicit FullScreenEditor(QTextEdit *mEditor, QWidget *parent=0);
25 | ~FullScreenEditor();
26 |
27 | bool isFullScreen();
28 |
29 | public slots:
30 |
31 | signals:
32 | void contentChanged();
33 |
34 | private slots:
35 | void on_chapterContent_textChanged();
36 | void onEscapeTriggered(bool triggered);
37 |
38 | void on_chapterContent_cursorPositionChanged();
39 |
40 | private:
41 | Ui::FullScreenEditor *ui;
42 |
43 | QTextEdit *mEditor;
44 | MarkupHighlighter *mHighlighter;
45 |
46 | static const QString DEFAULT_STYLE_FILE;
47 | };
48 |
49 | #endif // FULLSCREENEDITOR_H
50 |
--------------------------------------------------------------------------------
/src/app/fullscreeneditor.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | FullScreenEditor
4 |
5 |
6 | Qt::WindowModal
7 |
8 |
9 |
10 | 0
11 | 0
12 | 800
13 | 600
14 |
15 |
16 |
17 | MainWindow
18 |
19 |
20 |
21 | -
22 |
23 |
-
24 |
25 |
26 |
27 | 0
28 | 0
29 |
30 |
31 |
32 | QFrame::NoFrame
33 |
34 |
35 | QFrame::Plain
36 |
37 |
38 |
-
39 |
40 |
41 |
42 | 0
43 | 0
44 |
45 |
46 |
47 | QFrame::NoFrame
48 |
49 |
50 | QTextEdit::NoWrap
51 |
52 |
53 |
54 |
55 |
56 |
57 | -
58 |
59 |
60 | QLayout::SetDefaultConstraint
61 |
62 |
-
63 |
64 |
65 | Qt::Horizontal
66 |
67 |
68 | QSizePolicy::Expanding
69 |
70 |
71 |
72 | 400
73 | 5
74 |
75 |
76 |
77 |
78 | -
79 |
80 |
81 |
82 | 0
83 | 0
84 |
85 |
86 |
87 | Exit
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | exitFullscreenEditor
102 | clicked()
103 | FullScreenEditor
104 | close()
105 |
106 |
107 | 734
108 | 576
109 |
110 |
111 | 597
112 | 570
113 |
114 |
115 |
116 |
117 |
118 |
--------------------------------------------------------------------------------
/src/app/main.cpp:
--------------------------------------------------------------------------------
1 | #include "mainwindow.h"
2 |
3 | #include
4 | #include
5 | #include
6 | #include
7 |
8 | int main(int argc, char *argv[])
9 | {
10 |
11 | static const QString APP_DESCRIPTION = QString("Application to help plan,")
12 | + QString(" organize, and write a novel."),
13 | ARG_NOVEL = "novel",
14 | DESC_NOVEL = "Path to a Plotline novel project.",
15 |
16 | T_NOVEL="novel",
17 | T_CHARACTER="character",
18 | T_PLOTLINE="plotline",
19 | T_SCENE="scene",
20 | T_CHAPTER="chapter";
21 |
22 | static const QStringList TABS({T_NOVEL, T_CHARACTER, T_PLOTLINE, T_SCENE,
23 | T_CHAPTER});
24 |
25 | static int POS_NOVEL = 0;
26 |
27 | QApplication a(argc, argv);
28 |
29 | // Set the parser.
30 | QCommandLineParser parser;
31 | parser.setApplicationDescription(APP_DESCRIPTION);
32 | parser.addHelpOption();
33 | parser.addVersionOption();
34 | parser.addPositionalArgument(ARG_NOVEL, DESC_NOVEL, "[novel]");
35 |
36 | QCommandLineOption tab = QCommandLineOption(
37 | {"t", "tab"},
38 | "Open selected tab (novel, character, plotline, scene, chapter)",
39 | T_NOVEL
40 | );
41 | parser.addOption(tab);
42 |
43 | parser.process(a);
44 |
45 | // Set app information for settings.
46 | QCoreApplication::setOrganizationName("Renegade Engineer");
47 | QCoreApplication::setOrganizationDomain("rngr.me");
48 | QCoreApplication::setApplicationName("Plotline");
49 |
50 | // Get the positional arguments
51 |
52 | QStringList posArgs = parser.positionalArguments();
53 | QString novelPath;
54 | if (POS_NOVEL < posArgs.length())
55 | novelPath = posArgs[POS_NOVEL];
56 |
57 | QString tabName = parser.value("tab");
58 | if (tabName.isEmpty()) tabName = parser.value("t");
59 | if (tabName.isEmpty()) tabName = T_NOVEL;
60 |
61 | // Get the correct tab.
62 | if (0 > TABS.indexOf(tabName)){
63 | qCritical() << "Invalid tab name:" << tabName;
64 | return 1;
65 | }
66 |
67 | MainWindow w;
68 | w.show();
69 |
70 | if (!novelPath.isNull()){
71 | w.openNovel(novelPath);
72 | }
73 |
74 | w.openTab(TABS.indexOf(tabName));
75 | return a.exec();
76 | }
77 |
--------------------------------------------------------------------------------
/src/app/mainwindow.h:
--------------------------------------------------------------------------------
1 | #ifndef MAINWINDOW_H
2 | #define MAINWINDOW_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 | #include
14 | #include
15 | #include
16 | #include "savethread.h"
17 |
18 | #include "novel.h"
19 | #include "characteritemmodel.h"
20 | #include "plotlineitemmodel.h"
21 | #include "plotlineitemdelegate.h"
22 | #include "plotlinedialog.h"
23 | #include "preferencesdialog.h"
24 | #include "revisiondialog.h"
25 |
26 | #include "novelframe.h"
27 | #include "characterframe.h"
28 | #include "plotframe.h"
29 | #include "sceneframe.h"
30 | #include "chaptersframe.h"
31 |
32 | class PlotlineAppFrame;
33 | class CharacterFrame;
34 | class PlotFrame;
35 | class SceneFrame;
36 | class ChaptersFrame;
37 | class NovelFrame;
38 |
39 | namespace Ui {
40 | class MainWindow;
41 | }
42 |
43 | class MainWindow : public QMainWindow
44 | {
45 | Q_OBJECT
46 |
47 | public:
48 | explicit MainWindow(QWidget *parent = 0);
49 | ~MainWindow();
50 |
51 | static const int TENSE_PAST = 0,
52 | TENSE_PRESENT = 1,
53 | TENSE_FUTURE = 2,
54 | TENSE_OTHER = 3,
55 |
56 | POV_1_1 = 0,
57 | POV_2_1 = 1,
58 | POV_3_1 = 2,
59 | POV_1_P = 3,
60 | POV_2_P = 4,
61 | POV_3_P = 5,
62 | POV_OTHER = 6;
63 |
64 | Novel *novel() const;
65 | void setNovel(Novel *novel);
66 | void openNovel(const QString &path);
67 |
68 | void openTab(const int index);
69 |
70 | virtual void closeEvent(QCloseEvent *event);
71 |
72 | signals:
73 | void saveNovel();
74 | void novelChanged();
75 | void novelLoaded();
76 | void novelNew();
77 |
78 | public slots:
79 |
80 | void show();
81 |
82 | private slots:
83 |
84 | void onVersionWarningChecked(bool checked);
85 |
86 | void onNovelModified();
87 | void onSaveNovel();
88 | void onSaveNovel_started();
89 | void onSaveNovel_finished();
90 | void onNovelNew();
91 | void onNovelLoaded();
92 | void onHideDistractions();
93 | void onShowDistractions();
94 |
95 | void on_actionPreferences_triggered();
96 | void on_actionNovelNew_triggered();
97 | void on_actionNovelOpen_triggered();
98 | void on_actionNovelSave_triggered();
99 | void on_actionNovelRevisions_triggered();
100 | void on_actionNovelExport_triggered();
101 | void on_actionNovelBind_triggered();
102 | void on_actionNovelSaveAs_triggered();
103 | void on_actionNovelClose_triggered();
104 |
105 | protected:
106 |
107 | void mouseMoveEvent(QMouseEvent *event);
108 |
109 | private:
110 |
111 | static const QStringList frameTitles;
112 | static const QString ShowWarning;
113 |
114 | void showWarningMessage();
115 |
116 | // Frames
117 | NovelFrame *mNovelFrame;
118 | CharacterFrame *mCharacterFrame;
119 | PlotFrame *mPlotFrame;
120 | SceneFrame *mSceneFrame;
121 | ChaptersFrame *mChapterFrame;
122 | QList frames;
123 |
124 | // Window & Dialogs
125 | Ui::MainWindow *ui;
126 | PreferencesDialog *mPrefDialog;
127 |
128 | Novel *mNovel;
129 | bool mIsSaved;
130 | QString mOpenedFile;
131 | QWidgetList mDistractions;
132 |
133 | // widgets
134 | QCheckBox *mShowVersionWarning;
135 |
136 | // Threads
137 | SaveThread *mSaveThread;
138 |
139 | void disconnectAll();
140 | void connectAll();
141 |
142 | };
143 |
144 | #endif // MAINWINDOW_H
145 |
--------------------------------------------------------------------------------
/src/app/markuphighlighter.h:
--------------------------------------------------------------------------------
1 | #ifndef MARKDOWNHIGHLIGHTER_H
2 | #define MARKDOWNHIGHLIGHTER_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 |
10 | #include "styleproxy.h"
11 | #include "styleproxyparser.h"
12 | #include "preferencesdialog.h"
13 |
14 | class MarkupHighlighter : public QSyntaxHighlighter
15 | {
16 | Q_OBJECT
17 | public:
18 |
19 | enum MarkupLanguage {
20 | NoLanguage = 0,
21 | MarkDown,
22 | ReStructuredText
23 | };
24 |
25 | enum MarkupToken {
26 | Document = 0, // only used for styling/parsing style file.
27 | HtmlEscape,
28 | Header,
29 | BlockQuote,
30 | List,
31 | CodeBlock,
32 | HorizontalRule,
33 | InlineLink,
34 | LinkSource,
35 | LinkTarget,
36 | Emphasis,
37 | Strong,
38 | InlineCode,
39 | Image,
40 | AutomaticLink,
41 | BackslashEscape
42 | };
43 |
44 | explicit MarkupHighlighter(QObject *parent = 0);
45 | explicit MarkupHighlighter(QTextDocument *parent);
46 | explicit MarkupHighlighter(const MarkupLanguage language, QTextDocument *parent=0);
47 |
48 | virtual void highlightBlock(const QString & text);
49 |
50 | MarkupLanguage getLanguage() const;
51 | void setLanguage(const MarkupLanguage &value);
52 |
53 | private:
54 |
55 | static const QString DEFAULT_STYLE_FILE;
56 |
57 | static const QMap TOKENS;
58 | static const QMap FORMATTING;
59 | MarkupLanguage mLanguage;
60 |
61 | static QMap tokens();
62 | static QMap formatting();
63 | QTextCharFormat parseFormat(const QTextCharFormat &baseFormat,
64 | const QJsonObject &obj);
65 |
66 | static MarkupLanguage detectLanguage(const QSettings &settings);
67 |
68 | signals:
69 |
70 | public slots:
71 | };
72 |
73 | #endif // MARKDOWNHIGHLIGHTER_H
74 |
--------------------------------------------------------------------------------
/src/app/modelcheckbox.cpp:
--------------------------------------------------------------------------------
1 | #include "modelcheckbox.h"
2 |
3 | ModelCheckbox::ModelCheckbox(const QString &label, const QVariant &value,
4 | QWidget *parent) : QCheckBox(label, parent)
5 | {
6 | mValue = value;
7 | connect(this, SIGNAL(toggled(bool)),
8 | this, SLOT(onToggled(bool)));
9 | }
10 |
11 | QVariant ModelCheckbox::value() const
12 | {
13 | return mValue;
14 | }
15 |
16 | void ModelCheckbox::setValue(const QVariant &value)
17 | {
18 | mValue = value;
19 | }
20 |
21 | void ModelCheckbox::onToggled(bool checked)
22 | {
23 | emit toggled(checked, mValue);
24 | }
25 |
26 |
--------------------------------------------------------------------------------
/src/app/modelcheckbox.h:
--------------------------------------------------------------------------------
1 | #ifndef MODELCHECKBOX_H
2 | #define MODELCHECKBOX_H
3 |
4 | #include
5 | #include
6 |
7 | class ModelCheckbox : public QCheckBox
8 | {
9 | Q_OBJECT
10 | public:
11 | explicit ModelCheckbox(const QString &label, const QVariant &value,
12 | QWidget *parent = 0);
13 |
14 | QVariant value() const;
15 | void setValue(const QVariant &value);
16 |
17 | signals:
18 |
19 | void toggled(bool checked, QVariant value);
20 |
21 | public slots:
22 |
23 | private:
24 | QVariant mValue;
25 |
26 | private slots:
27 | void onToggled(bool checked);
28 | };
29 |
30 | #endif // MODELCHECKBOX_H
31 |
--------------------------------------------------------------------------------
/src/app/novelframe.cpp:
--------------------------------------------------------------------------------
1 | #include "novelframe.h"
2 | #include "ui_novelframe.h"
3 |
4 | NovelFrame::NovelFrame(MainWindow *mainWindow, QWidget *parent) :
5 | PlotlineAppFrame(mainWindow, parent),
6 | ui(new Ui::NovelFrame)
7 | {
8 | ui->setupUi(this);
9 |
10 | ui->novelPartsList->setCurrentRow(0);
11 | }
12 |
13 | NovelFrame::~NovelFrame()
14 | {
15 | delete ui;
16 | }
17 |
18 | void NovelFrame::onNovelLoad()
19 | {
20 | Novel *novel = mainWindow()->novel();
21 | ui->workingTitle->setText(novel->getWorkingTitle());
22 | ui->genre->setText(novel->getGenre());
23 | ui->setting->setText(novel->getSetting());
24 | ui->pointofView->setCurrentIndex((int) novel->getPointOfView());
25 | ui->tense->setCurrentIndex((int) novel->getTense());
26 |
27 | // Author page
28 | Author *author = novel->author();
29 | ui->authorName->setText(author->name());
30 | ui->authorPenName->setText(author->penName());
31 | ui->authorEmail->setText(author->email());
32 | ui->authorPhone->setText(author->phone());
33 | // ui->authorAddress->document()->setPlainText(author->address());
34 | ui->authorAddress->blockSignals(true);
35 | ui->authorAddress->setPlainText(author->address());
36 | ui->authorAddress->blockSignals(false);
37 | }
38 |
39 | void NovelFrame::onNovelNew()
40 | {
41 | ui->workingTitle->clear();
42 | ui->genre->clear();
43 | ui->setting->clear();
44 | ui->pointofView->clear();
45 | ui->tense->clear();
46 |
47 | // Author page
48 | ui->authorAddress->clear();
49 | ui->authorEmail->clear();
50 | ui->authorName->clear();
51 | ui->authorPenName->clear();
52 | ui->authorPhone->clear();
53 | }
54 |
55 | void NovelFrame::on_workingTitle_textEdited(const QString &arg1)
56 | {
57 | mMainWindow->novel()->setWorkingTitle(arg1);
58 | emit novelModified();
59 | }
60 |
61 | void NovelFrame::on_genre_textEdited(const QString &arg1)
62 | {
63 | mMainWindow->novel()->setGenre(arg1);
64 | emit novelModified();
65 | }
66 |
67 | void NovelFrame::on_setting_textEdited(const QString &arg1)
68 | {
69 | mMainWindow->novel()->setSetting(arg1);
70 | emit novelModified();
71 | }
72 |
73 | void NovelFrame::on_pointofView_activated(int index)
74 | {
75 | mMainWindow->novel()->setPointOfView((Novel::PointOfView) index);
76 | emit novelModified();
77 | }
78 |
79 | void NovelFrame::on_tense_activated(int index)
80 | {
81 | mMainWindow->novel()->setTense((Novel::Tense) index);
82 | emit novelModified();
83 | }
84 |
85 | void NovelFrame::on_authorName_textEdited(const QString &arg1)
86 | {
87 | mainWindow()->novel()->author()->setName(arg1);
88 | emit novelModified();
89 | }
90 |
91 | void NovelFrame::on_authorPenName_textEdited(const QString &arg1)
92 | {
93 | mainWindow()->novel()->author()->setPenName(arg1);
94 | emit novelModified();
95 | }
96 |
97 | void NovelFrame::on_authorPhone_textEdited(const QString &arg1)
98 | {
99 | mainWindow()->novel()->author()->setPhone(arg1);
100 | emit novelModified();
101 | }
102 |
103 | void NovelFrame::on_authorEmail_textEdited(const QString &arg1)
104 | {
105 | mainWindow()->novel()->author()->setEmail(arg1);
106 | emit novelModified();
107 | }
108 |
109 | void NovelFrame::on_authorAddress_textChanged()
110 | {
111 | mainWindow()->novel()->author()->setAddress(ui->authorAddress->toPlainText());
112 | emit novelModified();
113 | }
114 |
--------------------------------------------------------------------------------
/src/app/novelframe.h:
--------------------------------------------------------------------------------
1 | #ifndef NOVELFRAME_H
2 | #define NOVELFRAME_H
3 |
4 | #include "plotlineappframe.h"
5 |
6 | namespace Ui {
7 | class NovelFrame;
8 | }
9 |
10 | //class PlotlineAppFrame;
11 |
12 | class NovelFrame : public PlotlineAppFrame
13 | {
14 | Q_OBJECT
15 |
16 | public:
17 | explicit NovelFrame(MainWindow *novel, QWidget *parent = 0);
18 | ~NovelFrame();
19 |
20 | private slots:
21 | void on_tense_activated(int index);
22 | void on_pointofView_activated(int index);
23 | void on_workingTitle_textEdited(const QString &arg1);
24 | void on_genre_textEdited(const QString &arg1);
25 | void on_setting_textEdited(const QString &arg1);
26 | void on_authorName_textEdited(const QString &arg1);
27 |
28 | void on_authorPenName_textEdited(const QString &arg1);
29 |
30 | void on_authorPhone_textEdited(const QString &arg1);
31 |
32 | void on_authorEmail_textEdited(const QString &arg1);
33 |
34 | void on_authorAddress_textChanged();
35 |
36 | public slots:
37 | void onNovelLoad();
38 | void onNovelNew();
39 |
40 | private:
41 | Ui::NovelFrame *ui;
42 | };
43 |
44 | #endif // NOVELFRAME_H
45 |
--------------------------------------------------------------------------------
/src/app/plotframe.cpp:
--------------------------------------------------------------------------------
1 | #include "plotframe.h"
2 | #include "ui_plotframe.h"
3 |
4 | PlotFrame::PlotFrame(MainWindow *mainWindow, QWidget *parent) :
5 | PlotlineAppFrame(mainWindow, parent),
6 | ui(new Ui::PlotFrame)
7 | {
8 | ui->setupUi(this);
9 |
10 | // Models
11 | mModel = new PlotlineItemModel(mMainWindow->novel());
12 | ui->plotlineTable->setModel(mModel);
13 |
14 | // Signals
15 | connect(ui->plotlineTable, SIGNAL(doubleClicked(QModelIndex)),
16 | this, SLOT(onPlotlineDoubleClicked(QModelIndex)));
17 | connect(this, SIGNAL(plotlineListModified()),
18 | this, SLOT(onPlotlineListModified()));
19 |
20 | // Properties for table headers.
21 | ui->plotlineTable->setColumnWidth(PlotlineItemModel::BRIEF,
22 | PlotlineItemModel::BRIEF_WIDTH);
23 | ui->plotlineTable->setColumnWidth(PlotlineItemModel::SYNOPSIS,
24 | PlotlineItemModel::SYNOPSIS_WIDTH);
25 | ui->plotlineTable->horizontalHeader()->setStretchLastSection(true);
26 | ui->plotlineTable->setSelectionBehavior(QAbstractItemView::SelectRows);
27 | ui->plotlineTable->setSelectionMode(QAbstractItemView::SingleSelection);
28 | }
29 |
30 | PlotFrame::~PlotFrame()
31 | {
32 | delete ui;
33 | }
34 |
35 | void PlotFrame::onNovelLoad()
36 | {
37 | mModel = new PlotlineItemModel(mainWindow()->novel());
38 | ui->plotlineTable->setModel(mModel);
39 | }
40 |
41 | void PlotFrame::onNovelNew()
42 | {
43 | mModel = new PlotlineItemModel(mainWindow()->novel());
44 | }
45 |
46 |
47 |
48 | void PlotFrame::onPlotlineDoubleClicked(QModelIndex index)
49 | {
50 | Q_UNUSED(index);
51 | showPlotlineDialog();
52 | }
53 |
54 | void PlotFrame::onPlotlineListModified()
55 | {
56 | mModel->removeRows(0, mModel->rowCount());
57 | // fillPlotlineList();
58 | }
59 |
60 | void PlotFrame::on_addPlotline_clicked()
61 | {
62 | showPlotlineDialog(true);
63 | }
64 |
65 | void PlotFrame::on_editPlotline_clicked()
66 | {
67 | showPlotlineDialog();
68 | }
69 |
70 | void PlotFrame::on_archivePlotline_clicked()
71 | {
72 | }
73 |
74 | void PlotFrame::on_deletePlotline_clicked()
75 | {
76 | QString expl = tr("If you delete, it's lost forever. However, archiving")
77 | + tr(" will make it retreivable.");
78 | QMessageBox *messageBox = new QMessageBox(tr("Delete this plotline?"),
79 | expl, QMessageBox::Warning,
80 | QMessageBox::Ok,
81 | QMessageBox::Save,
82 | QMessageBox::Cancel);
83 | messageBox->setButtonText(QMessageBox::Ok, tr("Delete"));
84 | messageBox->setButtonText(QMessageBox::Save, tr("Archive"));
85 |
86 | int res = messageBox->exec();
87 | if (res == QMessageBox::Ok){
88 | QModelIndex current = ui->plotlineTable->currentIndex();
89 | mModel->removeRows(current.row(), 1);
90 | } else if (res == QMessageBox::Save){
91 | // TODO: archiving.
92 | }
93 |
94 | if (mModel->rowCount() == 0){
95 | ui->deletePlotline->setEnabled(false);
96 | ui->archivePlotline->setEnabled(false);
97 | ui->editPlotline->setEnabled(false);
98 | }
99 | }
100 |
101 | void PlotFrame::on_searchPlotlines_textChanged(const QString &arg1)
102 | {
103 | Q_UNUSED(arg1);
104 | }
105 |
106 | void PlotFrame::on_filterPlotlines_activated(int index)
107 | {
108 | Q_UNUSED(index);
109 | }
110 |
111 | PlotlineItemModel *PlotFrame::model() const
112 | {
113 | return mModel;
114 | }
115 |
116 | void PlotFrame::setModel(PlotlineItemModel *model)
117 | {
118 | mModel = model;
119 | }
120 |
121 | void PlotFrame::on_plotlineTable_activated(const QModelIndex &index)
122 | {
123 | bool enable = index.isValid();
124 | ui->deletePlotline->setEnabled(enable);
125 | ui->archivePlotline->setEnabled(enable);
126 | ui->editPlotline->setEnabled(enable);
127 | }
128 |
129 | void PlotFrame::onPlotlineAdded(const QModelIndex &index)
130 | {
131 | ui->plotlineTable->setCurrentIndex(index);
132 | }
133 |
134 | void PlotFrame::showPlotlineDialog(bool isNew)
135 | {
136 | PlotlineDialog *dialog = new PlotlineDialog(ui->plotlineTable,
137 | mainWindow()->novel(),
138 | isNew);
139 | connect(dialog, SIGNAL(plotlineAdded(QModelIndex)),
140 | this, SLOT(onPlotlineAdded(QModelIndex)));
141 | dialog->exec();
142 | }
143 |
144 | void PlotFrame::on_plotlineTable_clicked(const QModelIndex &index)
145 | {
146 | on_plotlineTable_activated(index);
147 | }
148 |
--------------------------------------------------------------------------------
/src/app/plotframe.h:
--------------------------------------------------------------------------------
1 | #ifndef PLOTFRAME_H
2 | #define PLOTFRAME_H
3 |
4 | #include "plotlineappframe.h"
5 | #include "plotlineitemmodel.h"
6 |
7 | class PlotlineAppFrame;
8 |
9 | namespace Ui {
10 | class PlotFrame;
11 | }
12 |
13 | class PlotFrame : public PlotlineAppFrame
14 | {
15 | Q_OBJECT
16 |
17 | public:
18 | explicit PlotFrame(MainWindow *mainWindow, QWidget *parent = 0);
19 | ~PlotFrame();
20 |
21 | PlotlineItemModel *model() const;
22 | void setModel(PlotlineItemModel *model);
23 |
24 | signals:
25 | void plotlineListModified();
26 |
27 | public slots:
28 | void onNovelLoad();
29 | void onNovelNew();
30 |
31 | void onPlotlineDoubleClicked(QModelIndex index);
32 | void onPlotlineListModified();
33 |
34 | private slots:
35 | void on_addPlotline_clicked();
36 | void on_editPlotline_clicked();
37 | void on_archivePlotline_clicked();
38 | void on_deletePlotline_clicked();
39 | void on_searchPlotlines_textChanged(const QString &arg1);
40 | void on_filterPlotlines_activated(int index);
41 |
42 | void on_plotlineTable_activated(const QModelIndex &index);
43 |
44 | void onPlotlineAdded(const QModelIndex &index);
45 |
46 | void on_plotlineTable_clicked(const QModelIndex &index);
47 |
48 | private:
49 | Ui::PlotFrame *ui;
50 |
51 | PlotlineItemModel *mModel;
52 | Plotline *mSelectedPlotline;
53 | void showPlotlineDialog(bool isNew=false);
54 | };
55 |
56 | #endif // PLOTFRAME_H
57 |
--------------------------------------------------------------------------------
/src/app/plotlineappframe.cpp:
--------------------------------------------------------------------------------
1 | #include "plotlineappframe.h"
2 |
3 | #include "novel.h"
4 |
5 | PlotlineAppFrame::PlotlineAppFrame(MainWindow *mainWindow, QWidget *parent) : QFrame(parent)
6 | {
7 | mMainWindow = mainWindow;
8 | }
9 |
10 | MainWindow *PlotlineAppFrame::mainWindow() const
11 | {
12 | return mMainWindow;
13 | }
14 |
15 | void PlotlineAppFrame::setMainWindow(MainWindow *mainWindow)
16 | {
17 | mMainWindow = mainWindow;
18 | }
19 |
--------------------------------------------------------------------------------
/src/app/plotlineappframe.h:
--------------------------------------------------------------------------------
1 | #ifndef PLOTLINEAPPFRAME_H
2 | #define PLOTLINEAPPFRAME_H
3 |
4 | #include
5 | #include
6 | #include "novel.h"
7 |
8 | class MainWindow;
9 |
10 | class PlotlineAppFrame : public QFrame
11 | {
12 | Q_OBJECT
13 |
14 | public:
15 | PlotlineAppFrame(MainWindow *mainWindow, QWidget *parent = 0);
16 |
17 | MainWindow *mainWindow() const;
18 | void setMainWindow(MainWindow *mainWindow);
19 |
20 | protected:
21 | MainWindow *mMainWindow;
22 |
23 | signals:
24 | void novelModified();
25 |
26 | public slots:
27 | virtual void onNovelLoad() = 0;
28 | virtual void onNovelNew() = 0;
29 | };
30 |
31 | #include "mainwindow.h"
32 |
33 | #endif // PLOTLINEAPPFRAME_H
34 |
--------------------------------------------------------------------------------
/src/app/plotlinedialog.cpp:
--------------------------------------------------------------------------------
1 | #include "plotlinedialog.h"
2 | #include "ui_plotlinedialog.h"
3 |
4 | PlotlineDialog::PlotlineDialog(QTableView *tableView,
5 | Novel *novel,
6 | bool isNew,
7 | QWidget *parent) :
8 | QDialog(parent),
9 | ui(new Ui::PlotlineDialog)
10 | {
11 | ui->setupUi(this);
12 |
13 | mTableView = tableView;
14 | mNovel = novel;
15 |
16 | mCharacterList = QMap();
17 | mIsNew = isNew;
18 |
19 | PlotlineItemModel *model = (PlotlineItemModel *) mTableView->model();
20 | QModelIndex index = mTableView->currentIndex();
21 |
22 | QList selectedCharacters;
23 | if (index.isValid() && !mIsNew){
24 | mIsNew = false;
25 | QString brief = model->data(index, PlotlineItemModel::BriefRole)
26 | .toString(),
27 | synopsis = model->data(index, PlotlineItemModel::SynopsisRole)
28 | .toString();
29 | QColor color = model->data(index, PlotlineItemModel::ColorRole)
30 | .value();
31 | QJsonArray jCharacters = model->data(index,
32 | PlotlineItemModel::CharacterRole)
33 | .toJsonArray();
34 | ui->plotlineBrief->setText(brief);
35 | ui->plotlineSynopsis->setText(synopsis);
36 | onColorSelected(QColor(color));
37 |
38 | for (QJsonValue v : jCharacters)
39 | selectedCharacters << mNovel->character(QUuid(v.toString()));
40 | } else {
41 | mIsNew = true;
42 | setWindowTitle(tr("New Plotline"));
43 | }
44 |
45 | for (Character *c : mNovel->characters()) {
46 | QCheckBox *checkbox = new QCheckBox(c->name());
47 | bool checked = selectedCharacters.contains(c);
48 | checkbox->setChecked(checked);
49 | mCharacterList.insert(checkbox, c);
50 | ui->characterListLayout->addWidget(checkbox);
51 | }
52 | }
53 |
54 | PlotlineDialog::~PlotlineDialog()
55 | {
56 | delete ui;
57 | // The plotline will be deleted with the novel.
58 | }
59 |
60 | void PlotlineDialog::on_plotlineColor_clicked()
61 | {
62 | QColorDialog *dialog = new QColorDialog(this);
63 | connect(dialog, SIGNAL(colorSelected(QColor)),
64 | this, SLOT(onColorSelected(QColor)));
65 | dialog->exec();
66 | }
67 |
68 | void PlotlineDialog::onColorSelected(const QColor &color)
69 | {
70 | mColor = color;
71 | if (color.isValid()){
72 | QImage image = QImage(40, 30, QImage::Format_RGB32);
73 | image.fill(color);
74 | QIcon icon = QIcon(QPixmap::fromImage(image));
75 | ui->plotlineColor->setIcon(icon);
76 | } else {
77 | }
78 | }
79 |
80 |
81 | void PlotlineDialog::on_clearPlotlineColor_clicked()
82 | {
83 | onColorSelected(QColor());
84 | }
85 |
86 | void PlotlineDialog::on_buttonBox_accepted()
87 | {
88 | PlotlineItemModel *model = (PlotlineItemModel *) mTableView->model();
89 | QModelIndex index = mTableView->currentIndex();
90 | if (mIsNew){
91 | if (!model->insertRows(index.row()+1, 1)){
92 | qWarning("[+] plotline - could not insert rows at [%d, %d]",
93 | index.row(), index.column());
94 | return;
95 | }
96 | index = model->index(index.row()+1, 0); // go to the inserted row.
97 | }
98 |
99 | QJsonArray charIds;
100 | for (QCheckBox *cb : mCharacterList.keys())
101 | if (cb->isChecked())
102 | charIds << QJsonValue(mCharacterList[cb]->id().toString());
103 |
104 | model->setData(index, ui->plotlineBrief->text(), PlotlineItemModel
105 | ::BriefRole);
106 | model->setData(index, ui->plotlineSynopsis->toPlainText(),
107 | PlotlineItemModel::SynopsisRole);
108 | model->setData(index, charIds, PlotlineItemModel::CharacterRole);
109 | model->setData(index, mColor, PlotlineItemModel::ColorRole);
110 |
111 | emit mTableView->activated(index);
112 |
113 | if (mIsNew)
114 | emit plotlineAdded(index);
115 | else
116 | emit plotlineModified(index);
117 | }
118 |
119 | void PlotlineDialog::on_characterSearch_textEdited(const QString &arg1)
120 | {
121 | for (QCheckBox *cb : mCharacterList.keys()){
122 | Character *c = mCharacterList[cb];
123 | if (arg1.isEmpty() || (c->name().toLower().contains(arg1.toLower()))
124 | || (arg1.startsWith("@") && c->label().contains(arg1.mid(1)))){
125 | ui->characterListLayout->addWidget(cb);
126 | cb->setVisible(true);
127 | } else {
128 | ui->characterListLayout->removeWidget(cb);
129 | cb->setVisible(false);
130 | }
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/src/app/plotlinedialog.h:
--------------------------------------------------------------------------------
1 | #ifndef PLOTLINEDIALOG_H
2 | #define PLOTLINEDIALOG_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include
13 |
14 | #include "plotline.h"
15 | #include "plotframe.h"
16 | #include "plotlineitemmodel.h"
17 |
18 | class PlotFrame;
19 |
20 | namespace Ui {
21 | class PlotlineDialog;
22 | }
23 |
24 | class PlotlineDialog : public QDialog
25 | {
26 | Q_OBJECT
27 |
28 | public:
29 | explicit PlotlineDialog(QTableView *tableView,
30 | Novel *novel,
31 | bool isNew = false,
32 | QWidget *parent = 0);
33 | ~PlotlineDialog();
34 |
35 | private slots:
36 | void on_plotlineColor_clicked();
37 | void onColorSelected(const QColor &color);
38 | void on_clearPlotlineColor_clicked();
39 | void on_buttonBox_accepted();
40 |
41 | void on_characterSearch_textEdited(const QString &arg1);
42 |
43 | signals:
44 |
45 | void plotlineAdded(const QModelIndex &index);
46 | void plotlineModified(const QModelIndex &index);
47 | void canceled();
48 |
49 | private:
50 | Ui::PlotlineDialog *ui;
51 |
52 | Novel *mNovel;
53 | QTableView *mTableView;
54 | QMap mCharacterList;
55 |
56 | QColor mColor;
57 |
58 | bool mIsNew;
59 | };
60 |
61 | #endif // PLOTLINEDIALOG_H
62 |
--------------------------------------------------------------------------------
/src/app/plotlineitemdelegate.cpp:
--------------------------------------------------------------------------------
1 | #include "plotlineitemdelegate.h"
2 |
3 | PlotlineItemDelegate::PlotlineItemDelegate(QObject *parent)
4 | : QStyledItemDelegate(parent)
5 | {
6 | }
7 |
8 | QWidget *PlotlineItemDelegate::createEditor(QWidget *parent,
9 | const QStyleOptionViewItem &option,
10 | const QModelIndex &index) const
11 | {
12 | Q_UNUSED(option);
13 | QWidget *widget = 0;
14 | switch(index.column()){
15 | case BRIEF:
16 | case SYNOPSIS:
17 | widget = (QWidget *) new QTextEdit();
18 | break;
19 | case CHARACTERS:
20 | widget = new QPushButton(parent);
21 | break;
22 | }
23 |
24 | return widget;
25 | }
26 |
27 | void PlotlineItemDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
28 | {
29 | if (editor == 0) return;
30 |
31 | QTextEdit *textEdit = 0;
32 | QPushButton *button = 0;
33 |
34 | switch (index.column()){
35 | case BRIEF:
36 | case SYNOPSIS:
37 | textEdit = static_cast(editor);
38 | textEdit->setText(index.model()->data(index, Qt::EditRole).toString());
39 | break;
40 | case CHARACTERS:
41 | button = static_cast(editor);
42 | Q_UNUSED(button);
43 | break;
44 | }
45 | }
46 |
47 | void PlotlineItemDelegate::setModelData(QWidget *editor,
48 | QAbstractItemModel *model,
49 | const QModelIndex &index) const
50 | {
51 | QLineEdit *lineEditor = 0;
52 | QPushButton *button = 0;
53 |
54 | switch (index.column()){
55 | case BRIEF:
56 | case SYNOPSIS:
57 | lineEditor = static_cast(editor);
58 | model->setData(index, lineEditor->text());
59 | break;
60 | case CHARACTERS:
61 | button = static_cast(editor);
62 | Q_UNUSED(button);
63 | break;
64 | }
65 | }
66 |
67 | void PlotlineItemDelegate::updateEditorGeometry(QWidget *editor,
68 | const QStyleOptionViewItem &option,
69 | const QModelIndex &index) const
70 | {
71 | Q_UNUSED(index);
72 | editor->setGeometry(option.rect);
73 | }
74 |
75 |
--------------------------------------------------------------------------------
/src/app/plotlineitemdelegate.h:
--------------------------------------------------------------------------------
1 | #ifndef SCENEITEMDELEGATE_H
2 | #define SCENEITEMDELEGATE_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 | #include "novel.h"
13 | #include "plotline.h"
14 |
15 | class Novel;
16 | class Plotline;
17 |
18 | class PlotlineItemDelegate : public QStyledItemDelegate
19 | {
20 |
21 | Q_OBJECT
22 |
23 | public:
24 | PlotlineItemDelegate(QObject *parent = 0);
25 |
26 | QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
27 | const QModelIndex &index) const Q_DECL_OVERRIDE;
28 |
29 | void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE;
30 | void setModelData(QWidget *editor, QAbstractItemModel *model,
31 | const QModelIndex &index) const Q_DECL_OVERRIDE;
32 |
33 | void updateEditorGeometry(QWidget *editor,
34 | const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
35 |
36 | private:
37 | Novel *mNovel;
38 |
39 | static const int BRIEF = 0,
40 | SYNOPSIS = 1,
41 | CHARACTERS = 2;
42 |
43 | signals:
44 |
45 | public slots:
46 | };
47 |
48 | #endif // SCENEITEMDELEGATE_H
49 |
--------------------------------------------------------------------------------
/src/app/plotlineitemmodel.h:
--------------------------------------------------------------------------------
1 | #ifndef PLOTLINEITEMVIEW_H
2 | #define PLOTLINEITEMVIEW_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 | #include "novel.h"
13 |
14 | class Novel;
15 |
16 | class PlotlineItemModel : public QAbstractTableModel
17 | {
18 | Q_OBJECT
19 | public:
20 | PlotlineItemModel(Novel *novel = 0, QObject *parent = 0);
21 |
22 | // Read methods
23 | int rowCount(const QModelIndex & parent = QModelIndex()) const;
24 | int columnCount(const QModelIndex & parent = QModelIndex()) const;
25 | QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
26 | bool setData(const QModelIndex &index, const QVariant &value, int role);
27 | QVariant headerData(int section, Qt::Orientation orientation,
28 | int role = Qt::DisplayRole) const;
29 |
30 | bool insertRows(int row, int count,
31 | const QModelIndex & parent = QModelIndex());
32 | bool removeRows(int row, int count,
33 | const QModelIndex & parent = QModelIndex());
34 |
35 | Qt::ItemFlags flags(const QModelIndex & index) const;
36 |
37 | // Custom roles
38 | static const int PlotlineId = Qt::UserRole;
39 |
40 | // Column numbers
41 | static const int BRIEF = 0,
42 | SYNOPSIS = 1,
43 | CHARACTERS = 2,
44 | // Column widths
45 | BRIEF_WIDTH = 200,
46 | SYNOPSIS_WIDTH = 420,
47 | CHARACTERS_WIDTH = 100;
48 |
49 | static const int CharacterRole = Qt::UserRole,
50 | BriefRole = Qt::UserRole + 1,
51 | SynopsisRole = Qt::UserRole + 2,
52 | ColorRole = Qt::UserRole + 4;
53 |
54 | Novel *novel() const;
55 | void setNovel(Novel *novel);
56 |
57 | private:
58 |
59 | Novel *mNovel;
60 | int mRowCount;
61 |
62 | signals:
63 |
64 | public slots:
65 | };
66 |
67 | #endif // PLOTLINEITEMVIEW_H
68 |
--------------------------------------------------------------------------------
/src/app/preferencesdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef PREFERENCESDIALOG_H
2 | #define PREFERENCESDIALOG_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "markuphighlighter.h"
9 |
10 | namespace Ui {
11 | class PreferencesDialog;
12 | }
13 |
14 | class PreferencesDialog : public QDialog
15 | {
16 | Q_OBJECT
17 |
18 | public:
19 | explicit PreferencesDialog(QWidget *parent = 0);
20 | ~PreferencesDialog();
21 |
22 | static const int DEFAULT_FONT_SIZE = 12;
23 |
24 | static const QString DEFAULT_PROJECT_DIRECTORY,
25 | DEFAULT_HEADSHOT_DIRECTORY,
26 | OPEN_LAST_PROJECT,
27 | DISTRACTION_FREE_MODE,
28 | DFM_EDITOR_SIZE,
29 | WIDGETS_TIMEOUT,
30 | SPELL_CHECK,
31 | WORD_WRAP_WIDTH,
32 | MARKUP,
33 | FONT,
34 | FONT_SIZE,
35 | COLOR_SCHEME;
36 |
37 | enum DistractionFreeMode {
38 | DfmDisabled = 0,
39 | ShowWindowed,
40 | ShowFullScreen
41 | };
42 |
43 | enum SpellCheckMode {
44 | SpellCheckDisabled = 0,
45 | SpellCheckNotInDfm,
46 | SpellCheckAlways,
47 | };
48 |
49 | private slots:
50 | void on_chooseDefaultProjectDirectory_clicked();
51 | void on_preferencesButtonBox_accepted();
52 | // void on_preferencesButtonBox_rejected();
53 |
54 | void on_widgetTimeout_sliderMoved(int position);
55 |
56 | private:
57 | Ui::PreferencesDialog *ui;
58 | static const QStringList WIDGET_TIMEOUTS;
59 | static const int TIMEOUT_VALUES[6];
60 | static const float SIZE_PERCENTAGES[4];
61 | };
62 |
63 | #endif // PREFERENCESDIALOG_H
64 |
--------------------------------------------------------------------------------
/src/app/publisherdialog.cpp:
--------------------------------------------------------------------------------
1 | #include "publisherdialog.h"
2 | #include "ui_publisherdialog.h"
3 | #include
4 |
5 | const QStringList PublisherDialog::Extensions = QStringList({
6 | "epub",
7 | "mobi",
8 | "markdown",
9 | "markdown",
10 | "pdf",
11 | "html",
12 | "odt"
13 | }),
14 | PublisherDialog::ChapterPlaceholders = QStringList({
15 | "",
16 | "%n",
17 | "%t",
18 | "%I",
19 | "%1",
20 | "%O"
21 | }),
22 | PublisherDialog::HeaderPlaceholders = QStringList({
23 | "",
24 | "%t", // title
25 | "%s", // short title
26 | "%l", // author's last name
27 | "%a", // author's full name
28 | "%p", // page number
29 | });
30 |
31 | PublisherDialog::PublisherDialog(Novel *novel, QWidget *parent) :
32 | QDialog(parent),
33 | ui(new Ui::PublisherDialog)
34 | {
35 | ui->setupUi(this);
36 | mNovel = novel;
37 | }
38 |
39 | PublisherDialog::~PublisherDialog()
40 | {
41 | delete ui;
42 | }
43 |
44 | void PublisherDialog::on_chooseDirectory_clicked()
45 | {
46 | QString outDir = QFileDialog::getExistingDirectory(this,
47 | "Output Directory",
48 | QDir::homePath());
49 | outDir += QDir::separator() + mNovel->getWorkingTitle() + QChar('.')
50 | + Extensions[ui->format->currentIndex()];
51 | ui->outputFile->setText(outDir);
52 | }
53 |
54 | void PublisherDialog::on_chapterHeaderCombo_activated(int index)
55 | {
56 | if (index == 0)
57 | return;
58 | QString text = ui->chapterHeaderText->text();
59 | text = text.insert(index, ChapterPlaceholders[index]);
60 | ui->chapterHeaderText->setText(text);
61 | ui->chapterHeaderCombo->blockSignals(true);
62 | ui->chapterHeaderCombo->setCurrentIndex(0);
63 | ui->chapterHeaderCombo->blockSignals(false);
64 | }
65 |
66 | void PublisherDialog::on_titleCombo_activated(int index)
67 | {
68 | if (index == 0)
69 | return;
70 | QString text = ui->titleText->text();
71 | text = text.insert(index, HeaderPlaceholders[index]);
72 | ui->titleText->setText(text);
73 | ui->titleText->blockSignals(true);
74 | ui->titleCombo->setCurrentIndex(0);
75 | ui->titleText->blockSignals(false);
76 | }
77 |
78 | void PublisherDialog::updatePreview()
79 | {
80 | // todo
81 | }
82 |
83 | QString PublisherDialog::formatTitleHeader() const
84 | {
85 | QString name = mNovel->author()->name();
86 | if (!mNovel->author()->penName().isEmpty())
87 | name = mNovel->author()->penName();
88 | return QString("# ") + mNovel->getWorkingTitle() + QString("\n")
89 | + QString("# by\n# ") + name + QString("\n\n");
90 | }
91 |
92 | QString PublisherDialog::formatChapterHeader(Chapter *chapter) const
93 | {
94 | QString format = ui->chapterHeaderText->text();
95 | return format.replace("%n", "\n# ")
96 | .replace("%t", chapter->title())
97 | .replace("%I", QString::number(chapter->number()))
98 | .replace("%1", QString::number(chapter->number()))
99 | .replace("%O", QString::number(chapter->number()))
100 | + QString("\n\n");
101 | }
102 |
103 | void PublisherDialog::on_chapterHeaderText_cursorPositionChanged(int arg1, int arg2)
104 | {
105 | Q_UNUSED(arg1);
106 | chapterTextPos = arg2;
107 | }
108 |
109 | void PublisherDialog::on_titleText_cursorPositionChanged(int arg1, int arg2)
110 | {
111 | Q_UNUSED(arg1);
112 | headerTextPos = arg2;
113 | }
114 |
115 | void PublisherDialog::on_PublisherDialog_accepted()
116 | {
117 | QString text = formatTitleHeader();
118 | for (Chapter *c : mNovel->chapters()){
119 | text += formatChapterHeader(c);
120 | text += c->latestContent() + QString("\n\n");
121 | }
122 | QString outPath = ui->outputFile->text();
123 | QFile *outFile = new QFile(outPath);
124 | int success = outFile->open(QFile::WriteOnly);
125 | if (!success){
126 | QMessageBox::critical(this, tr("Error"),
127 | tr("Could not publish to \"")
128 | + outPath + tr("\""), QMessageBox::Ok,
129 | QMessageBox::NoButton);
130 | qWarning() << "Could not write to" << outPath;
131 | return;
132 | }
133 | outFile->write(text.toStdString().data(), text.length());
134 | qDebug() << "Wrote" << text.length() << "bytes to" << outPath;
135 | outFile->close();
136 | delete outFile;
137 | }
138 |
--------------------------------------------------------------------------------
/src/app/publisherdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef PUBLISHERDIALOG_H
2 | #define PUBLISHERDIALOG_H
3 |
4 | #include
5 | #include "novel.h"
6 |
7 | namespace Ui {
8 | class PublisherDialog;
9 | }
10 |
11 | class PublisherDialog : public QDialog
12 | {
13 | Q_OBJECT
14 |
15 | public:
16 | explicit PublisherDialog(Novel *novel, QWidget *parent = 0);
17 | ~PublisherDialog();
18 |
19 | private slots:
20 | void on_chooseDirectory_clicked();
21 | void on_chapterHeaderCombo_activated(int index);
22 | void on_chapterHeaderText_cursorPositionChanged(int arg1, int arg2);
23 | void on_titleText_cursorPositionChanged(int arg1, int arg2);
24 | void on_titleCombo_activated(int index);
25 |
26 | void on_PublisherDialog_accepted();
27 |
28 | private:
29 | Ui::PublisherDialog *ui;
30 |
31 | Novel *mNovel;
32 |
33 | static const QStringList Extensions, ChapterPlaceholders,
34 | HeaderPlaceholders;
35 |
36 | static const int Blank = 0,
37 | NewLine = 1, // %n
38 | ChapterTitle = 2, // %t
39 | RomanNumber = 3, // %I
40 | LatinNumber = 4, // %1
41 | TextNumber = 5; // %O
42 |
43 | int chapterTextPos = 0, headerTextPos = 0;
44 |
45 | void updatePreview();
46 | QString formatTitleHeader() const;
47 | QString formatChapterHeader(Chapter *) const;
48 | };
49 |
50 | #endif // PUBLISHERDIALOG_H
51 |
--------------------------------------------------------------------------------
/src/app/revisiondialog.cpp:
--------------------------------------------------------------------------------
1 | #include "revisiondialog.h"
2 | #include "ui_revisiondialog.h"
3 |
4 | RevisionDialog::RevisionDialog(MainWindow *mainWindow, QWidget *parent) :
5 | QDialog(parent),
6 | ui(new Ui::RevisionDialog)
7 | {
8 | ui->setupUi(this);
9 | mMainWindow = mainWindow;
10 |
11 | Novel *novel = mainWindow->novel();
12 | int count = novel->revisionCount(),
13 | rev = novel->currentRevision();
14 | mTmpRevisions = novel->revisions();
15 |
16 | ui->revisionNumber->setRange(1, count);
17 | ui->revisionNumber->setValue(rev+1);
18 | ui->revisionComments->setPlainText(novel->revisionComment(rev));
19 |
20 | mTempRevision = rev;
21 | }
22 |
23 | RevisionDialog::~RevisionDialog()
24 | {
25 | delete ui;
26 | }
27 |
28 | MainWindow *RevisionDialog::mainWindow() const
29 | {
30 | return mMainWindow;
31 | }
32 |
33 | void RevisionDialog::setMainWindow(MainWindow *mainWindow)
34 | {
35 | mMainWindow = mainWindow;
36 | }
37 |
38 | void RevisionDialog::on_addRevision_clicked()
39 | {
40 | // Novel *novel = mainWindow()->novel();
41 | mTmpRevisions.append(QString());
42 | ui->revisionNumber->setMaximum(mTmpRevisions.count());
43 | ui->revisionNumber->setValue(mTmpRevisions.count());
44 | }
45 |
46 | void RevisionDialog::on_revisionNumber_valueChanged(int arg1)
47 | {
48 | qDebug() << "revision value changed:" << arg1;
49 | mTempRevision = arg1 - 1;
50 | ui->revisionComments->setPlainText(mTmpRevisions[mTempRevision]);
51 | }
52 |
53 | void RevisionDialog::on_buttonBox_accepted()
54 | {
55 | qDebug() << "Revisions changed:" << "\n"
56 | << "New revisions:" << mTmpRevisions << "\n"
57 | << "Selected revision:" << mTempRevision;
58 | if (mTempRevision != mainWindow()->novel()->currentRevision() ||
59 | mTmpRevisions != mainWindow()->novel()->revisions())
60 | emit mainWindow()->novelChanged();
61 | mainWindow()->novel()->setRevisions(mTmpRevisions);
62 | mainWindow()->novel()->setCurrentRevision(mTempRevision);
63 | }
64 |
65 | void RevisionDialog::on_revisionComments_textChanged()
66 | {
67 | qDebug() << "revisions[" << mTempRevision << "] ="
68 | << ui->revisionComments->toPlainText();
69 | mTmpRevisions[mTempRevision] = ui->revisionComments->toPlainText();
70 | }
71 |
--------------------------------------------------------------------------------
/src/app/revisiondialog.h:
--------------------------------------------------------------------------------
1 | #ifndef REVISIONDIALOG_H
2 | #define REVISIONDIALOG_H
3 |
4 | #include
5 |
6 | #include "mainwindow.h"
7 |
8 | namespace Ui {
9 | class RevisionDialog;
10 | }
11 |
12 | class RevisionDialog : public QDialog
13 | {
14 | Q_OBJECT
15 |
16 | public:
17 | explicit RevisionDialog(MainWindow *mainWindow, QWidget *parent = 0);
18 | ~RevisionDialog();
19 |
20 | MainWindow *mainWindow() const;
21 | void setMainWindow(MainWindow *mainWindow);
22 |
23 | private slots:
24 | void on_addRevision_clicked();
25 | void on_revisionNumber_valueChanged(int arg1);
26 | void on_buttonBox_accepted();
27 | void on_revisionComments_textChanged();
28 |
29 | private:
30 | Ui::RevisionDialog *ui;
31 |
32 | MainWindow *mMainWindow;
33 |
34 | QStringList mTmpRevisions;
35 | int mTempRevision = 0;
36 | };
37 |
38 | #endif // REVISIONDIALOG_H
39 |
--------------------------------------------------------------------------------
/src/app/revisiondialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | RevisionDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 456
10 | 324
11 |
12 |
13 |
14 | Dialog
15 |
16 |
17 | -
18 |
19 |
-
20 |
21 |
-
22 |
23 |
24 | Comments:
25 |
26 |
27 |
28 | -
29 |
30 |
31 | -
32 |
33 |
-
34 |
35 |
36 | 1
37 |
38 |
39 |
40 | -
41 |
42 |
43 |
44 | 0
45 | 0
46 |
47 |
48 |
49 | Add Revision
50 |
51 |
52 |
53 |
54 |
55 |
56 | :/images/images/list-add.png:/images/images/list-add.png
57 |
58 |
59 |
60 |
61 |
62 | -
63 |
64 |
65 |
66 | 0
67 | 0
68 |
69 |
70 |
71 | Go To Revision:
72 |
73 |
74 |
75 |
76 |
77 | -
78 |
79 |
80 | Qt::Horizontal
81 |
82 |
83 | QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | buttonBox
97 | accepted()
98 | RevisionDialog
99 | accept()
100 |
101 |
102 | 248
103 | 254
104 |
105 |
106 | 157
107 | 274
108 |
109 |
110 |
111 |
112 | buttonBox
113 | rejected()
114 | RevisionDialog
115 | reject()
116 |
117 |
118 | 316
119 | 260
120 |
121 |
122 | 286
123 | 274
124 |
125 |
126 |
127 |
128 |
129 |
--------------------------------------------------------------------------------
/src/app/savethread.cpp:
--------------------------------------------------------------------------------
1 | #include "savethread.h"
2 |
3 | void SaveThread::run()
4 | {
5 | mNovel->writeTo(mOpenedFile);
6 | }
7 |
8 | SaveThread::SaveThread(Novel *novel, const QString &openedFile)
9 | {
10 | mNovel = novel;
11 | mOpenedFile = openedFile;
12 | }
13 |
--------------------------------------------------------------------------------
/src/app/savethread.h:
--------------------------------------------------------------------------------
1 | #ifndef SAVETHREAD_H
2 | #define SAVETHREAD_H
3 |
4 | #include
5 |
6 | class MainWindow;
7 | class Novel;
8 |
9 | class SaveThread : public QThread
10 | {
11 | Q_OBJECT
12 |
13 | public:
14 | SaveThread(Novel *novel, const QString &openedFile = QString());
15 |
16 | protected:
17 | void run();
18 |
19 | private:
20 | Novel *mNovel;
21 | QString mOpenedFile;
22 | };
23 |
24 | #include "mainwindow.h"
25 | #include "novel.h"
26 |
27 | #endif // SAVETHREAD_H
28 |
--------------------------------------------------------------------------------
/src/app/scenefilter.cpp:
--------------------------------------------------------------------------------
1 | #include "scenefilter.h"
2 |
3 | SceneFilter::SceneFilter(Novel *novel, Plotline *plotline, QObject *parent)
4 | : QSortFilterProxyModel(parent)
5 | {
6 | mNovel = novel;
7 | mPlotline = plotline;
8 | mSearch = QString();
9 | // connect(this, SIGNAL(dataChanged(QModelIndex,QModelIndex,QVector)),
10 | // this, SLOT(onDataChanged(QModelIndex,QModelIndex,QVector)));
11 | // connect(this, SIGNAL(rowsInserted(QModelIndex,int,int)),
12 | // this, SLOT(onRowsInserted(QModelIndex, int, int)));
13 | }
14 |
15 | Qt::ItemFlags SceneFilter::flags(const QModelIndex &index) const
16 | {
17 | Qt::ItemFlags defaultFlags = QSortFilterProxyModel::flags(index);
18 |
19 | if (index.isValid())
20 | return Qt::ItemIsDragEnabled | defaultFlags;
21 | else
22 | return Qt::ItemIsDropEnabled | defaultFlags;
23 | }
24 |
25 | Qt::DropActions SceneFilter::supportedDropActions() const
26 | {
27 | return Qt::MoveAction;
28 | }
29 |
30 | bool SceneFilter::filterAcceptsRow(int source_row,
31 | const QModelIndex &source_parent) const
32 | {
33 | Q_UNUSED(source_parent);
34 | Scene *scene = mNovel->scenes()[source_row];
35 |
36 | bool b = ((mPlotline == 0 || (scene->plotline() == mPlotline)) &&
37 | (mSearch.isEmpty() || (scene->headline().toLower().contains(mSearch.toLower())
38 | || scene->action().toLower().contains(mSearch.toLower())) ));
39 | return b;
40 | }
41 |
42 | bool SceneFilter::insertRows(int row, int count, const QModelIndex &parent)
43 | {
44 | beginInsertRows(parent, row, row+(count-1));
45 | SceneModel *sceneModel = (SceneModel *) sourceModel();
46 | qDebug() << "[+] scene filter - add " << count << "scenes at" << row;
47 | bool res = sceneModel->insertRows(row, count, mPlotline, parent);
48 | endInsertRows();
49 |
50 | return res;
51 | }
52 |
53 | bool SceneFilter::removeRows(const QModelIndexList &indexList)
54 | {
55 | QList toDelete;
56 | for (QModelIndex index : indexList)
57 | toDelete << data(index, SceneModel::IdRole).toUuid();
58 | for (QUuid id : toDelete){
59 | Scene *scene = mNovel->scene(id);
60 | if (scene)
61 | qDebug() << "[-] Removing scene" << scene->headline();
62 | else
63 | qDebug() << "[!] Could not get scene by" << id;
64 | mNovel->removeScene(scene);
65 | }
66 | return true;
67 | }
68 |
69 | bool SceneFilter::moveRows(const QModelIndex &sourceParent, int sourceRow,
70 | int count, const QModelIndex &destinationParent,
71 | int destinationChild)
72 | {
73 | beginMoveRows(sourceParent, sourceRow, sourceRow+(count-1), destinationParent,
74 | destinationChild);
75 |
76 | endMoveRows();
77 | }
78 |
79 | Plotline *SceneFilter::plotline() const
80 | {
81 | return mPlotline;
82 | }
83 |
84 | void SceneFilter::setPlotline(Plotline *plotline)
85 | {
86 | mPlotline = plotline;
87 | emit this->filterChanged();
88 | }
89 |
90 | QString SceneFilter::search() const
91 | {
92 | return mSearch;
93 | }
94 |
95 | void SceneFilter::setSearch(const QString &search)
96 | {
97 | mSearch = search;
98 | emit this->filterChanged();
99 | }
100 |
101 | Novel *SceneFilter::novel() const
102 | {
103 | return mNovel;
104 | }
105 |
106 | void SceneFilter::setNovel(Novel *novel)
107 | {
108 | mNovel = novel;
109 | emit filterChanged();
110 | }
111 |
--------------------------------------------------------------------------------
/src/app/scenefilter.h:
--------------------------------------------------------------------------------
1 | #ifndef SCENEFILTER_H
2 | #define SCENEFILTER_H
3 |
4 | #include
5 | #include
6 | #include "plotline.h"
7 | #include "sceneitemmodel.h"
8 | #include "plotlineitemmodel.h"
9 |
10 | class SceneFilter : public QSortFilterProxyModel
11 | {
12 | Q_OBJECT
13 | public:
14 | explicit SceneFilter(Novel *novel, Plotline *plotline = 0, QObject *parent = 0);
15 |
16 |
17 | Qt::ItemFlags flags(const QModelIndex &index) const;
18 | Qt::DropActions supportedDropActions() const;
19 |
20 | // int rowCount(const QModelIndex &parent = QModelIndex()) const;
21 | bool filterAcceptsRow(int source_row,
22 | const QModelIndex &source_parent = QModelIndex())
23 | const;
24 | bool insertRows(int row, int count, const QModelIndex &parent = QModelIndex());
25 |
26 | bool removeRows(const QModelIndexList &indexList);
27 | bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
28 | const QModelIndex &destinationParent, int destinationChild);
29 |
30 | Plotline *plotline() const;
31 | void setPlotline(Plotline *plotline);
32 |
33 | QString search() const;
34 | void setSearch(const QString &search);
35 |
36 | Novel *novel() const;
37 | void setNovel(Novel *novel);
38 |
39 | private:
40 | Novel *mNovel;
41 | Plotline *mPlotline;
42 | QString mSearch;
43 |
44 | signals:
45 |
46 | public slots:
47 | };
48 |
49 | #endif // SCENEFILTER_H
50 |
--------------------------------------------------------------------------------
/src/app/sceneframe.h:
--------------------------------------------------------------------------------
1 | #ifndef SCENEFRAME_H
2 | #define SCENEFRAME_H
3 |
4 | #include "plotlineappframe.h"
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include "sceneitemmodel.h"
11 | #include "modelcheckbox.h"
12 | #include "characterparser.h"
13 | #include "characterhighlighter.h"
14 | #include "utils.h"
15 | #include "scenefilter.h"
16 |
17 | namespace Ui {
18 | class SceneFrame;
19 | }
20 |
21 | class SceneFrame : public PlotlineAppFrame
22 | {
23 | Q_OBJECT
24 |
25 | public:
26 | explicit SceneFrame(MainWindow *mainWindow, QWidget *parent = 0);
27 | ~SceneFrame();
28 |
29 | signals:
30 |
31 | public slots:
32 | void onNovelLoad();
33 | void onNovelNew();
34 |
35 | protected:
36 |
37 | private slots:
38 | void on_detectCharacters_clicked();
39 | void on_sceneList_activated(const QModelIndex &index);
40 | void on_addScene_clicked();
41 | void on_archiveScene_clicked();
42 | void on_deleteScene_clicked();
43 | void onCharacterToggled(bool checked, QVariant value);
44 | void on_sceneList_clicked(const QModelIndex &index);
45 | void on_plotline_activated(int index);
46 | // void on_sceneHeadline_textChanged();
47 | // void on_sceneAction_textChanged();
48 | void onHeadlineModified();
49 |
50 | void onActionModified();
51 |
52 | void on_sceneList_customContextMenuRequested(const QPoint &pos);
53 |
54 | void on_filterScenes_activated(int index);
55 |
56 | void on_searchScenes_textEdited(const QString &arg1);
57 |
58 | void on_sceneList_indexesMoved(const QModelIndexList &indexes);
59 |
60 | void on_characterSearch_textChanged(const QString &arg1);
61 |
62 | private:
63 |
64 | void disconnectSlots();
65 | void connectSlots();
66 | void blockEditableSignals();
67 | void unblockEditableSignals();
68 |
69 | QList _getSelectedCharacters(bool pov=false);
70 | void _setSelectedCharacters(QList characters, bool pov=false);
71 |
72 | QList getSelectedCharacters();
73 | void setSelectedCharacters(QList characters);
74 |
75 | QList getSelectedPointsOfView();
76 | void setSelectedPointsOfView(QList characters);
77 |
78 | void findCharacters(const QTextEdit *editor);
79 | void detectLabelStart(QTextEdit *editor);
80 | void fillPlotlineCombo(Plotline *selected = 0);
81 |
82 | Ui::SceneFrame *ui;
83 |
84 | Scene *mSelectedScene = 0;
85 | QList mCharacters;
86 | SceneFilter *mFilter;
87 | QPoint mDragPos;
88 |
89 | class HeadlineUpdater : public QRunnable
90 | {
91 | public:
92 | HeadlineUpdater(QTextEdit *field, QListView *listView);
93 | void run();
94 | private:
95 | QTextEdit *mField;
96 | QListView *mListView;
97 | };
98 |
99 | CharacterHighlighter *mActionHighlighter,
100 | *mHeadlineHighlighter;
101 | QCompleter *mHeadlineCompleter,
102 | *mActionCompleter;
103 | };
104 |
105 | #endif // SCENEFRAME_H
106 |
--------------------------------------------------------------------------------
/src/app/sceneitemmodel.h:
--------------------------------------------------------------------------------
1 | #ifndef SCENEITEMMODEL_H
2 | #define SCENEITEMMODEL_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include "scene.h"
8 |
9 | class SceneModel : public QAbstractListModel
10 | {
11 | public:
12 | SceneModel(Novel *novel, QObject *parent = 0 );
13 |
14 | // Overrides
15 | int rowCount(const QModelIndex &parent = QModelIndex()) const;
16 | QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
17 | bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole);
18 | QVariant headerData(int section, Qt::Orientation orientation,
19 | int role = Qt::DisplayRole) const;
20 |
21 | Qt::ItemFlags flags(const QModelIndex &index) const;
22 |
23 | bool insertRows(int row, int count,
24 | const QModelIndex & parent = QModelIndex());
25 | bool insertRows(int row, int count, Plotline *plotline = 0,
26 | const QModelIndex & parent = QModelIndex());
27 | bool removeRows(int row, int count,
28 | const QModelIndex & parent = QModelIndex());
29 |
30 | bool moveRows(const QModelIndex &sourceParent, int sourceRow, int count,
31 | const QModelIndex &destinationParent, int destinationChild);
32 |
33 | // Drag/drop support
34 |
35 | // bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row,
36 | // int column, const QModelIndex &parent);
37 | Qt::DropActions supportedDropActions() const;
38 | // QStringList mimeTypes() const;
39 |
40 | static const int
41 | HeadlineRole = Qt::UserRole + 0,
42 | ActionRole = Qt::UserRole + 1,
43 | PlotlineRole = Qt::UserRole + 2,
44 | CharactersRole = Qt::UserRole + 3,
45 | PointsOfViewRole = Qt::UserRole + 4,
46 | IdRole = Qt::UserRole + 5;
47 |
48 | private:
49 |
50 | Novel *mNovel;
51 |
52 | signals:
53 |
54 | public slots:
55 | };
56 |
57 | #endif // SCENEITEMMODEL_H
58 |
--------------------------------------------------------------------------------
/src/app/scenelistdialog.cpp:
--------------------------------------------------------------------------------
1 | #include "scenelistdialog.h"
2 | #include "ui_scenelistdialog.h"
3 |
4 | SceneListDialog::SceneListDialog(Novel *novel, QTableView *chapterTable, QWidget *parent) :
5 | QDialog(parent),
6 | ui(new Ui::SceneListDialog)
7 | {
8 | ui->setupUi(this);
9 |
10 | mNovel = novel;
11 | mChapterTable = chapterTable;
12 |
13 | // Get the chapter from the table.
14 | QModelIndex index = chapterTable->currentIndex();
15 | ChapterModel *model = (ChapterModel *) chapterTable->model();
16 | QUuid id = model->data(index, ChapterModel::IdRole).toUuid();
17 | Chapter *chapter = mNovel->chapter(id);
18 | QList plotlines = mNovel->plotlines();
19 |
20 | if (!chapter){
21 | qWarning() << "No chapter selected.";
22 | return;
23 | }
24 |
25 | // Fill the plotline selection
26 | ui->plotlineSelection->addItem("", QVariant(0));
27 | for (Plotline *p : plotlines)
28 | ui->plotlineSelection->addItem(p->brief(), p->id());
29 |
30 | // Get the scene lists to compare.
31 | QList novelScenes = mNovel->scenes();
32 | QList chapterScenes = chapter->scenes();
33 |
34 | // Add all novel scenes as a model checkbox. If the scene is included
35 | // as a scene assigned to the chapter, mark it as checked.
36 | for (Scene *s : novelScenes){
37 | ModelCheckbox *cb = new ModelCheckbox(s->headline(), s->id());
38 | cb->setChecked(chapterScenes.contains(s));
39 | mCheckboxes << cb;
40 | ui->sceneList->addWidget(cb);
41 | }
42 |
43 | fillList();
44 | }
45 |
46 | void SceneListDialog::accept(){
47 | QAbstractItemModel *model = mChapterTable->model();
48 | QModelIndex index = mChapterTable->currentIndex();
49 | int role = 0;
50 | for (ModelCheckbox *cb : mCheckboxes){
51 | QUuid id = cb->value().toUuid();
52 | if (cb->isChecked())
53 | role = ChapterModel::AddSceneRole;
54 | else
55 | role = ChapterModel::RemoveSceneRole;
56 | model->setData(index, id, role);
57 | }
58 | this->close();
59 | }
60 |
61 | SceneListDialog::~SceneListDialog()
62 | {
63 | delete ui;
64 | }
65 |
66 | void SceneListDialog::fillList()
67 | {
68 | Scene *s = 0;
69 |
70 | for (ModelCheckbox *cb : mCheckboxes){
71 | s = mNovel->scene(cb->value().toUuid());
72 | bool contains = s->headline().toLower().contains(mSearch.toLower());
73 | bool plotlineMatches = (s->plotline() == mPlotline);
74 | if ((mPlotline == 0 || plotlineMatches) && (mSearch.isNull() || contains))
75 | cb->setVisible(true);
76 | else
77 | cb->setVisible(false);
78 | }
79 | }
80 |
81 | void SceneListDialog::on_plotlineSelection_activated(int index)
82 | {
83 | if (index == 0){
84 | mPlotline = 0;
85 | fillList();
86 | }
87 | QUuid id = ui->plotlineSelection->currentData().toUuid();
88 | mPlotline = mNovel->plotline(id);
89 | fillList();
90 | }
91 |
92 | void SceneListDialog::on_sceneSearch_textChanged(const QString &arg1)
93 | {
94 | mSearch = arg1;
95 | fillList();
96 | }
97 |
--------------------------------------------------------------------------------
/src/app/scenelistdialog.h:
--------------------------------------------------------------------------------
1 | #ifndef SCENELISTDIALOG_H
2 | #define SCENELISTDIALOG_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include "modelcheckbox.h"
9 | #include "mainwindow.h"
10 | #include "chaptermodel.h"
11 | #include "utils.h"
12 |
13 | namespace Ui {
14 | class SceneListDialog;
15 | }
16 |
17 | class SceneListDialog : public QDialog
18 | {
19 | Q_OBJECT
20 |
21 | public:
22 | explicit SceneListDialog(Novel *novel, QTableView *mChapterTable, QWidget *parent = 0);
23 | void accept();
24 | ~SceneListDialog();
25 |
26 | private slots:
27 |
28 | void on_plotlineSelection_activated(int index);
29 |
30 | void on_sceneSearch_textChanged(const QString &arg1);
31 |
32 | private:
33 | Ui::SceneListDialog *ui;
34 |
35 | Novel *mNovel;
36 | QTableView *mChapterTable;
37 | QList mCheckboxes;
38 |
39 | Plotline *mPlotline = 0;
40 | QString mSearch;
41 |
42 | void fillList();
43 | };
44 |
45 | #endif // SCENELISTDIALOG_H
46 |
--------------------------------------------------------------------------------
/src/app/scenelistdialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | SceneListDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 400
10 | 300
11 |
12 |
13 |
14 | Dialog
15 |
16 |
17 | -
18 |
19 |
-
20 |
21 |
22 | 2
23 |
24 |
-
25 |
26 |
27 | -
28 |
29 |
30 |
31 |
32 |
33 | Search for scenes...
34 |
35 |
36 |
37 | -
38 |
39 |
40 | true
41 |
42 |
43 |
44 |
45 | 0
46 | 0
47 | 376
48 | 189
49 |
50 |
51 |
52 |
53 | QLayout::SetMinimumSize
54 |
55 |
56 | 0
57 |
58 |
59 | 0
60 |
61 |
62 | 0
63 |
64 |
65 | 0
66 |
67 |
-
68 |
69 |
70 | 6
71 |
72 |
73 | QLayout::SetMinimumSize
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 | -
84 |
85 |
86 | Qt::Horizontal
87 |
88 |
89 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 | buttonBox
101 | accepted()
102 | SceneListDialog
103 | accept()
104 |
105 |
106 | 248
107 | 254
108 |
109 |
110 | 157
111 | 274
112 |
113 |
114 |
115 |
116 | buttonBox
117 | rejected()
118 | SceneListDialog
119 | reject()
120 |
121 |
122 | 316
123 | 260
124 |
125 |
126 | 286
127 | 274
128 |
129 |
130 |
131 |
132 |
133 |
--------------------------------------------------------------------------------
/src/app/styleproxy.cpp:
--------------------------------------------------------------------------------
1 | #include "styleproxy.h"
2 |
3 | StyleProxy::StyleProxy(bool bold, bool italic, int relSize,
4 | QColor foreground,
5 | QColor background,
6 | QObject *parent) : QObject(parent)
7 | {
8 | mBold = bold;
9 | mItallic = italic;
10 | mRelSize = relSize;
11 | mForeground = foreground;
12 | mBackground = background;
13 | }
14 |
15 | bool StyleProxy::bold() const
16 | {
17 | return mBold;
18 | }
19 |
20 | void StyleProxy::setBold(bool bold)
21 | {
22 | mBold = bold;
23 | }
24 |
25 | bool StyleProxy::itallic() const
26 | {
27 | return mItallic;
28 | }
29 |
30 | void StyleProxy::setItallic(bool itallic)
31 | {
32 | mItallic = itallic;
33 | }
34 |
35 | int StyleProxy::relSize() const
36 | {
37 | return mRelSize;
38 | }
39 |
40 | void StyleProxy::setRelSize(int relSize)
41 | {
42 | mRelSize = relSize;
43 | }
44 |
45 | QColor StyleProxy::foreground() const
46 | {
47 | return mForeground;
48 | }
49 |
50 | void StyleProxy::setForeground(const QColor &foreground)
51 | {
52 | mForeground = foreground;
53 | }
54 |
55 | QColor StyleProxy::background() const
56 | {
57 | return mBackground;
58 | }
59 |
60 | void StyleProxy::setBackground(const QColor &background)
61 | {
62 | mBackground = background;
63 | }
64 |
65 | StyleProxy *StyleProxy::parse(QJsonObject object)
66 | {
67 | bool bold = false, italic = false;
68 | int relSize = 0;
69 | QColor foreground, background;
70 |
71 | if (object.contains("bold")){
72 | bold = object["bold"].toBool();
73 | // qDebug() << " found bold=" << bold;
74 | }if (object.contains("italic")){
75 | italic = object["italic"].toBool();
76 | // qDebug() << " found italic=" << italic;
77 | }if (object.contains("relSize")){
78 | relSize = object["relSize"].toInt();
79 | // qDebug() << " found relSize=" << relSize;
80 | }if (object.contains("foreground") && !object["foreground"].isNull()){
81 | if (object["foreground"].isArray()){
82 | QJsonArray arr = object["foreground"].toArray();
83 | int r = arr[0].toInt(), g = arr[1].toInt(), b = arr[2].toInt(),
84 | a = arr[3].toInt();
85 | foreground = QColor(r, g, b, a);
86 | } else {
87 | foreground = QColor(object["background"].toString());
88 | }
89 |
90 | if (!foreground.isValid())
91 | qWarning() << "Invalid fg color:" << object["background"].toString();
92 | qDebug() << " found foreground=" << foreground;
93 | }
94 | if (object.contains("background") && !object["background"].isNull()){
95 | if (object["background"].isArray()){
96 | QJsonArray arr = object["background"].toArray();
97 | int r = arr[0].toInt(), g = arr[1].toInt(), b = arr[2].toInt(),
98 | a = arr[3].toInt();
99 | background = QColor(r, g, b, a);
100 | } else {
101 | background = QColor(object["background"].toString());
102 | }
103 | if (!background.isValid())
104 | qWarning() << "Invalid bg color:" << object["foreground"].toString();
105 | // qDebug() << " found background=" << background;
106 | }
107 |
108 | // qDebug() << "Leaving styleProxy::parse";
109 |
110 | return new StyleProxy(bold, italic, relSize, foreground, background);
111 | }
112 |
113 | QTextCharFormat StyleProxy::toFormat(const QTextCharFormat &base) const
114 | {
115 | QTextCharFormat fmt;
116 |
117 | QFont font = base.font();
118 |
119 | font.setBold(mBold);
120 | font.setItalic(mItallic);
121 | font.setPointSize(font.pointSize() + mRelSize);
122 | fmt.setFont(font);
123 |
124 | if (mForeground.isValid())
125 | fmt.setForeground(QBrush(mForeground));
126 | if (mBackground.isValid())
127 | fmt.setBackground(QBrush(mBackground));
128 |
129 | // qDebug() << "Entering toFormat";
130 | // qDebug() << "is bold?" << fmt.font().bold();
131 | // qDebug() << "is Italic?" << fmt.font().italic();
132 | // qDebug() << "point size:" << fmt.font().pointSize();
133 |
134 | return fmt;
135 | }
136 |
137 |
--------------------------------------------------------------------------------
/src/app/styleproxy.h:
--------------------------------------------------------------------------------
1 | #ifndef STYLEPROXY_H
2 | #define STYLEPROXY_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | class StyleProxy : public QObject
9 | {
10 | Q_OBJECT
11 | public:
12 | explicit StyleProxy(bool bold=false, bool itallic=false, int relSize=0,
13 | QColor foreground=QColor(),
14 | QColor background=QColor(),
15 | QObject *parent = 0);
16 |
17 | bool bold() const;
18 | void setBold(bool bold);
19 |
20 | bool itallic() const;
21 | void setItallic(bool itallic);
22 |
23 | int relSize() const;
24 | void setRelSize(int relSize);
25 |
26 | QColor foreground() const;
27 | void setForeground(const QColor &foreground);
28 |
29 | QColor background() const;
30 | void setBackground(const QColor &background);
31 |
32 | static StyleProxy* parse(QJsonObject object);
33 | QTextCharFormat toFormat(const QTextCharFormat &base) const;
34 |
35 | private:
36 | bool mBold, mItallic;
37 | int mRelSize;
38 | QColor mForeground, mBackground;
39 |
40 | signals:
41 |
42 | public slots:
43 | };
44 |
45 | #endif // STYLEPROXY_H
46 |
--------------------------------------------------------------------------------
/src/app/styleproxyparser.cpp:
--------------------------------------------------------------------------------
1 | #include "styleproxyparser.h"
2 |
3 | StyleProxyParser::StyleProxyParser(const QJsonObject &object)
4 | {
5 | mObject = object;
6 | }
7 |
8 | StyleProxy *StyleProxyParser::parse(const QString &key) const
9 | {
10 | if (!mObject.contains(key)){
11 | // qWarning() << "Missing key" << key;
12 | return 0;
13 | }
14 | // qDebug() << "Entering SyleProxy::parse for key" << key;
15 | return StyleProxy::parse(mObject[key].toObject());
16 | }
17 |
18 | StyleProxy *StyleProxyParser::parse(const char *key) const
19 | {
20 | return parse(QString(key));
21 | }
22 |
23 | QJsonObject StyleProxyParser::object() const
24 | {
25 | return mObject;
26 | }
27 |
28 | void StyleProxyParser::setObject(const QJsonObject &object)
29 | {
30 | mObject = object;
31 | }
32 |
33 |
--------------------------------------------------------------------------------
/src/app/styleproxyparser.h:
--------------------------------------------------------------------------------
1 | #ifndef STYLEPROXYPARSER_H
2 | #define STYLEPROXYPARSER_H
3 |
4 | #include
5 | #include
6 | #include
7 |
8 | class StyleProxyParser
9 | {
10 | public:
11 | StyleProxyParser(const QJsonObject &object=QJsonObject());
12 |
13 | StyleProxy *parse(const QString &key) const;
14 | StyleProxy *parse(const char *key) const;
15 |
16 | QJsonObject object() const;
17 | void setObject(const QJsonObject &object);
18 |
19 | private:
20 | QJsonObject mObject;
21 | };
22 |
23 | #endif // STYLEPROXYPARSER_H
24 |
--------------------------------------------------------------------------------
/src/data/character-worthiness.json:
--------------------------------------------------------------------------------
1 | {
2 | "label" : "Novel Worthiness",
3 | "fields" : [
4 | {
5 | "label" : "Main Character",
6 | "type" : "choice",
7 | "choices" : [
8 | {
9 | "label" : "Heroic"
10 | },
11 | {
12 | "label" : "Courageous"
13 | },
14 | {
15 | "label" : "Goal-driven"
16 | },
17 | {
18 | "label" : "Focused"
19 | },
20 | {
21 | "label" : "Passionate"
22 | },
23 | {
24 | "label" : "Sympathetic"
25 | },
26 | {
27 | "label" : "Loyal"
28 | },
29 | {
30 | "label" : "Attractive"
31 | },
32 | {
33 | "label" : "Clever"
34 | },
35 | {
36 | "label" : "Funny"
37 | },
38 | {
39 | "label" : "Resourceful"
40 | },
41 | {
42 | "label" : "Responds actively to surroundings"
43 | },
44 | {
45 | "label" : "Embraces opportunity"
46 | },
47 | {
48 | "label" : "Makes things happen"
49 | },
50 | {
51 | "label" : "Mouthy"
52 | },
53 | {
54 | "label" : "Stubborn"
55 | },
56 | {
57 | "label" : "Perseveres with dignity"
58 | },
59 | {
60 | "label" : "Stoic about problems"
61 | },
62 | {
63 | "label" : "Leads Action"
64 | },
65 | {
66 | "label" : "Idealistic"
67 | },
68 | {
69 | "label" : "High Opinion of Self"
70 | },
71 | {
72 | "label" : "Lives by Different Rules",
73 | "name" : "different_rules"
74 | },
75 | {
76 | "label" : "Quintessentially",
77 | "name" : "quintessentially"
78 | },
79 | {
80 | "label" : "Essential to the plot"
81 | },
82 | {
83 | "label" : "Responsible for resolution"
84 | }
85 | ],
86 | "special" : [
87 | {
88 | "field" : "different_rules",
89 | "type" : "small-string"
90 | },
91 | {
92 | "field" : "quintessentially",
93 | "type" : "small-string"
94 | }
95 | ]
96 | },
97 | {
98 | "label" : "Sub-Ordinate Character",
99 | "type" : "choice",
100 | "choices" : [
101 | {
102 | "label" : "Reinforces a main character"
103 | },
104 | {
105 | "label" : "Encourages and supports main character"
106 | },
107 | {
108 | "label" : "Adds humor"
109 | },
110 | {
111 | "label" : "Brings out Protag’s Strength"
112 | },
113 | {
114 | "label" : "Piles on complications"
115 | }
116 | ]
117 | }
118 |
119 | ]
120 | }
121 |
--------------------------------------------------------------------------------
/src/data/novel-overview.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "overview",
3 | "label" : "Overview",
4 | "attributes" : [
5 | {
6 | "label" : "Working Title",
7 | "type" : String,
8 | "isLong" : false
9 | },
10 | {
11 | "label" : "Genre",
12 | "type" : String,
13 | "isLong" : false
14 | },
15 | {
16 | "label" : "Tense/POV",
17 | "type" : String,
18 | "isLong" : false
19 | },
20 | {
21 | "label" : "Setting",
22 | "type" : String
23 | }
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/src/data/novel-part-1.json:
--------------------------------------------------------------------------------
1 | {
2 | "label" : "Part 1",
3 | "attributes" : [
4 | {
5 | "label" : "Inciting Incident",
6 | "prompt" : "What happens to the protagonist to put her unavoidably in the path of the antagonist?",
7 | "type" : String
8 | },
9 | {
10 | "label" : "Internal Initial Conflict (call to action)",
11 | "name" : "ii_conflict",
12 | "prompt" : "What does your protagonist most want? Why can’t she have it? How will she try to get it?",
13 | "type" : String
14 | },
15 | {
16 | "label" : "External Initial Conflict (call to action)",
17 | "name" : "ei_conflict",
18 | "prompt" : "What does your protagonist want to accomplish or obtain (physically)? How will she go about it?",
19 | "type" : String
20 | },
21 | {
22 | "label": "Woven-in Backstory, Vital Information",
23 | "name" : "backstory",
24 | "prompt": "What happened before the inciting incident that we must know to understand the story?",
25 | "type" : String
26 | },
27 | ]
28 | }
29 |
--------------------------------------------------------------------------------
/src/data/novel-part-2.json:
--------------------------------------------------------------------------------
1 | {
2 | "label" : "Part 2",
3 | "attributes" : [
4 | {
5 | "label": "Internal Conflict (obstacles)",
6 | "prompt": "Why is your protagonist hesitant to strive for her goals? What (emotionally) makes her falter?",
7 | "type": String
8 | },
9 | {
10 | "label": "External Conflict (obstacles)",
11 | "prompt" : "What stands in the way of your protagonist’s goals? What will happen to her if she fails?",
12 | "type" : String
13 | },
14 | {
15 | "label": "Internal Higher Conflict (obstacles heighten)",
16 | "prompt": "Why should your protagonist turn back now? Why doesn’t she? What’s at stake?",
17 | "type" : String
18 | },
19 | {
20 | "label" : "External Higher Conflict (obstacles heighten)",
21 | "prompt" : "Who or what is trying to stop your protagonist? Why?",
22 | "type" : String
23 | },
24 | {
25 | "label" : "Internal Highest Conflict (obstacles intensify)",
26 | "prompt" : "What makes your protagonist realize the unavoidable importance of her original goal? What gives it new meaning?",
27 | "type" : String
28 | },
29 | {
30 | "label" : "External Highest Conflict (obstacles intensify)",
31 | "prompt" : "How does the antagonist get the best of your protagonist? What could make it worse? What happens to make her believe that there is no way to win?",
32 | "type" : String
33 | },
34 | {
35 | "label" : "Internal Point of No Return (stakes)",
36 | "prompt" : "What happens to change your protagonist so that she’ll never be the same again?",
37 | "type" : String
38 | },
39 | {
40 | "label" : "External Point of No Return (stakes)",
41 | "prompt" : "What makes it impossible for your protagonist to go back, to give up?",
42 | "type" : String
43 | },
44 | {
45 | "label" : "Darkest Hour",
46 | "prompt" : "What is the worst possible thing that could happen to your protagonist?",
47 | "type" : String
48 | },
49 | {
50 | "label": "Turning Point",
51 | "prompt" : "How does your protagonist realize she must continue to fight? How does she decide to risk everything? What new approach or idea has she come up with to battle on?",
52 | "type" : String
53 | }
54 | ],
55 | }
56 |
--------------------------------------------------------------------------------
/src/data/novel-part-3.json:
--------------------------------------------------------------------------------
1 | {
2 | "label" : "Part 3",
3 | "attributes" : [
4 | {
5 | "label" : "Internal Climax",
6 | "prompt" : "What does your protagonist realize at the crucial moment? What does she learn? Overcome?",
7 | "type" : String,
8 | },
9 | {
10 | "label" : "External Climax",
11 | "prompt" : "How does your protagonist defeat your antagonist?",
12 | "type" : String
13 | },
14 | {
15 | "label" : "Resolution (external)",
16 | "prompt" : "What does defeating the antagonist accomplish? How are things different?",
17 | "type" : String
18 | },
19 | {
20 | "label" : "Character Growth (internal)",
21 | "prompt" : "How has your protagonist changed?",
22 | "type" : String
23 | }
24 | ]
25 | }
26 |
--------------------------------------------------------------------------------
/src/lib/author.cpp:
--------------------------------------------------------------------------------
1 | #include "author.h"
2 |
3 | const QString Author::J_NAME = "name",
4 | Author::J_PENNAME = "penName",
5 | Author::J_EMAIL = "email",
6 | Author::J_ADDRESS = "address",
7 | Author::J_PHONE = "phone";
8 |
9 | Author::Author(const QString &name, const QString &penName,
10 | const QString &email, const QString &address,
11 | const QString &phone, Novel *novel, const QUuid &id, QObject *parent)
12 | : QObject(parent), Serializable(id)
13 | {
14 | mName = name;
15 | mPenName = penName;
16 | mEmail = email;
17 | mAddress = address;
18 | mPhone = phone;
19 | mNovel = novel;
20 | }
21 |
22 | QJsonObject Author::serialize() const
23 | {
24 | QJsonObject obj;
25 |
26 | obj[JSON_ID] = id().toString();
27 | obj[J_NAME] = mName;
28 | obj[J_PENNAME] = mPenName;
29 | obj[J_EMAIL] = mEmail;
30 | obj[J_ADDRESS] = mAddress;
31 | obj[J_PHONE] = mPhone;
32 |
33 | return obj;
34 | }
35 |
36 | Author *Author::deserialize(Novel *novel, const QJsonObject &object)
37 | {
38 | return new Author(object.value(J_NAME).toString(),
39 | object.value(J_PENNAME).toString(),
40 | object.value(J_EMAIL).toString(),
41 | object.value(J_ADDRESS).toString(),
42 | object.value(J_PHONE).toString(),
43 | novel,
44 | QUuid(object.value(JSON_ID).toString()));
45 | }
46 |
47 | QString Author::name() const
48 | {
49 | return mName;
50 | }
51 |
52 | void Author::setName(const QString &name)
53 | {
54 | mName = name;
55 | }
56 |
57 | QString Author::penName() const
58 | {
59 | return mPenName;
60 | }
61 |
62 | void Author::setPenName(const QString &penName)
63 | {
64 | mPenName = penName;
65 | }
66 |
67 | QString Author::email() const
68 | {
69 | return mEmail;
70 | }
71 |
72 | void Author::setEmail(const QString &email)
73 | {
74 | mEmail = email;
75 | }
76 |
77 | QString Author::address() const
78 | {
79 | return mAddress;
80 | }
81 |
82 | void Author::setAddress(const QString &address)
83 | {
84 | mAddress = address;
85 | }
86 |
87 | QString Author::phone() const
88 | {
89 | return mPhone;
90 | }
91 |
92 | void Author::setPhone(const QString &phone)
93 | {
94 | mPhone = phone;
95 | }
96 |
97 | Novel *Author::novel() const
98 | {
99 | return mNovel;
100 | }
101 |
102 | void Author::setNovel(Novel *novel)
103 | {
104 | mNovel = novel;
105 | }
106 |
107 |
--------------------------------------------------------------------------------
/src/lib/author.h:
--------------------------------------------------------------------------------
1 | #ifndef AUTHOR_H
2 | #define AUTHOR_H
3 |
4 | #include
5 | #include "serializable.h"
6 |
7 | class Novel;
8 |
9 | class Author : public QObject, public Serializable
10 | {
11 | Q_OBJECT
12 | public:
13 | explicit Author(const QString &name = QString(),
14 | const QString &penName = QString(),
15 | const QString &email = QString(),
16 | const QString &address = QString(),
17 | const QString &phone = QString(),
18 | Novel *novel = 0,
19 | const QUuid &id = 0,
20 | QObject *parent = 0);
21 |
22 | QJsonObject serialize() const;
23 | static Author *deserialize(Novel *novel, const QJsonObject &object);
24 |
25 | QString name() const;
26 | void setName(const QString &name);
27 |
28 | QString penName() const;
29 | void setPenName(const QString &penName);
30 |
31 | QString email() const;
32 | void setEmail(const QString &email);
33 |
34 | QString address() const;
35 | void setAddress(const QString &address);
36 |
37 | QString phone() const;
38 | void setPhone(const QString &phone);
39 |
40 | Novel *novel() const;
41 | void setNovel(Novel *novel);
42 |
43 | private:
44 | QString mName, mPenName, mEmail, mAddress, mPhone;
45 | Novel *mNovel;
46 |
47 | static const QString J_NAME, J_PENNAME, J_EMAIL, J_ADDRESS, J_PHONE;
48 |
49 | signals:
50 |
51 | public slots:
52 | };
53 |
54 | #include "novel.h"
55 |
56 | #endif // AUTHOR_H
57 |
--------------------------------------------------------------------------------
/src/lib/chapter.h:
--------------------------------------------------------------------------------
1 | #ifndef CHAPTER_H
2 | #define CHAPTER_H
3 |
4 | #include
5 | #include "completable.h"
6 | #include "scene.h"
7 | #include "revision.h"
8 |
9 | #include "serializable.h"
10 |
11 | class Novel;
12 | class Scene;
13 | class Revision;
14 |
15 | class Chapter : public QObject, public Serializable
16 | {
17 | private:
18 | QString mTitle;
19 | QList mScenes;
20 | QList mRevisions;
21 | Novel *mNovel;
22 |
23 | int mCurrentRevision = 0;
24 |
25 | static const QString JSON_TITLE, JSON_REVISIONS,
26 | JSON_SCENES, JSON_CURRENT_REVISION;
27 |
28 | Q_OBJECT
29 | public:
30 | explicit Chapter(const QString &title = QString(),
31 | const QList &revisions = QList(),
32 | const QList &scenes = QList(),
33 | Novel *novel = 0,
34 | int currentRevision = -1,
35 | QUuid id = QUuid(),
36 | QObject *parent = 0);
37 | ~Chapter();
38 |
39 | QString title() const;
40 | void setTitle(const QString &title);
41 |
42 | QList scenes() const;
43 | void setScenes(const QList &scenes);
44 |
45 | Novel *novel() const;
46 | void setNovel(Novel *novel);
47 |
48 | QJsonObject serialize() const;
49 | static Chapter *deserialize(Novel *novel, const QJsonObject &object);
50 | static QList deserialize(Novel *novel, const QJsonArray &object);
51 |
52 | int number();
53 | QList revisions() const;
54 | Revision *addRevision();
55 | void removeRevision(int i);
56 | int currentRevision() const;
57 | void setCurrentRevision(int currentRevision);
58 | void setContent(const QString &content, const int revision=-1);
59 | void setIsComplete(const bool complete, const int revision=-1);
60 | bool canMarkCompleted(const int revision=-1) const;
61 |
62 | QString content(int revision) const;
63 | QString currentContent() const;
64 | QString latestContent() const;
65 |
66 | signals:
67 |
68 | public slots:
69 | };
70 |
71 | #endif // CHAPTER_H
72 |
--------------------------------------------------------------------------------
/src/lib/character.h:
--------------------------------------------------------------------------------
1 | #ifndef CHARACTER_H
2 | #define CHARACTER_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include "serializable.h"
10 | #include "scene.h"
11 | #include "utils.h"
12 |
13 | class Scene;
14 | class Novel;
15 |
16 | class Character : public QObject, public Serializable
17 | {
18 | Q_OBJECT
19 |
20 | private:
21 |
22 | QString mName,
23 | mNickname,
24 | mLabel;
25 | QImage mHeadshot;
26 | QColor mColor;
27 | bool mIsArchived;
28 |
29 | static const QString J_NAME,
30 | J_NICKNAME,
31 | J_LABEL,
32 | J_HEADSHOT,
33 | J_COLOR,
34 | J_IS_ARCHIVED;
35 |
36 | Novel *mNovel;
37 |
38 | bool matches(const QString &string, const QRegularExpression &pattern);
39 |
40 | public:
41 | explicit Character(const QString &name,
42 | const QString &nickname = QString(),
43 | const QString &label = QString(),
44 | const QImage &headshot = QImage(),
45 | const QColor &color = QColor(),
46 | bool isArchived = false,
47 | Novel *novel = 0,
48 | QUuid id = QUuid(),
49 | QObject *parent = 0);
50 | ~Character();
51 |
52 | static QString generateLabel(const QString &name);
53 |
54 | QString name() const;
55 | bool nameMatches(const QRegularExpression &pattern);
56 |
57 | QString nickname() const;
58 |
59 | QString label() const;
60 | bool labelMatches(const QRegularExpression &pattern);
61 |
62 | QImage getHeadshot() const;
63 | void setHeadshot(const QImage &value);
64 |
65 | QColor color() const;
66 | void setColor(const QColor &value);
67 |
68 | Novel *getNovel() const;
69 | void setNovel(Novel *novel);
70 |
71 | QJsonObject serialize() const;
72 | static Character *deserialize(Novel *novel, const QJsonObject &object);
73 | static QList deserialize(Novel *novel, const QJsonArray &object);
74 |
75 | bool getIsArchived() const;
76 | void setIsArchived(bool isArchived);
77 |
78 | static const QRegularExpression LABEL_X;
79 |
80 | signals:
81 |
82 | public slots:
83 | void setName(const QString &value);
84 | void setNickname(const QString &value);
85 | void setLabel(const QString &value);
86 | };
87 |
88 | #endif // CHARACTER_H
89 |
--------------------------------------------------------------------------------
/src/lib/characterparser.cpp:
--------------------------------------------------------------------------------
1 | #include "characterparser.h"
2 |
3 | ParsedCharacterSet::ParsedCharacterSet(QObject *parent)
4 | : QHash()
5 | {
6 | Q_UNUSED(parent);
7 | }
8 |
9 | ParsedCharacterSet::~ParsedCharacterSet()
10 | {
11 |
12 | }
13 |
14 | ParsedCharacterSet ParsedCharacterSet::parse(Novel *novel, const QString &string)
15 | {
16 | int index = 0;
17 | QString label;
18 | Character *character = 0;
19 |
20 | ParsedCharacterSet set = ParsedCharacterSet();
21 |
22 | QRegularExpression labelX = Character::LABEL_X;
23 |
24 | QRegularExpressionMatchIterator matches = labelX.globalMatch(string);
25 |
26 | QRegularExpressionMatch match;
27 | while (matches.hasNext()){
28 | match = matches.next();
29 | label = match.captured(1);
30 | index = match.capturedStart(1);
31 | character = novel->characterByLabel(label);
32 | if (character)
33 | set.insert(index-1, character);
34 | }
35 |
36 |
37 | return set;
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/src/lib/characterparser.h:
--------------------------------------------------------------------------------
1 | #ifndef CHARACTERPARSER_H
2 | #define CHARACTERPARSER_H
3 |
4 | #include
5 |
6 | class Character;
7 | class Novel;
8 |
9 | class ParsedCharacterSet : public QHash
10 | {
11 |
12 | public:
13 | ParsedCharacterSet(QObject *parent = 0);
14 | ~ParsedCharacterSet();
15 |
16 | static ParsedCharacterSet parse(Novel *novel, const QString &string);
17 |
18 | signals:
19 |
20 | public slots:
21 | };
22 |
23 | #include "character.h"
24 | #include "novel.h"
25 |
26 | #endif // CHARACTERPARSER_H
27 |
--------------------------------------------------------------------------------
/src/lib/completable.cpp:
--------------------------------------------------------------------------------
1 | #include "completable.h"
2 |
3 | Completable::Completable(QObject *parent) : QObject(parent)
4 | {
5 | this->mComplete = false;
6 | }
7 |
8 | bool Completable::isCompleted()
9 | {
10 | return this->isCompleted();
11 | }
12 |
13 | void Completable::markCompleted()
14 | {
15 | this->mComplete = true;
16 | }
17 |
18 | void Completable::unmarkCompleted()
19 | {
20 | this->mComplete = false;
21 | }
22 |
23 | void Completable::toggleCompleted()
24 | {
25 | this->mComplete = !this->mComplete;
26 | }
27 |
28 | void Completable::setCompleted(int state)
29 | {
30 | this->mComplete = (state == Qt::Checked);
31 | }
32 |
--------------------------------------------------------------------------------
/src/lib/completable.h:
--------------------------------------------------------------------------------
1 | #ifndef COMPLETABLE_H
2 | #define COMPLETABLE_H
3 |
4 | #include
5 |
6 | class Completable : public QObject
7 | {
8 | Q_OBJECT
9 | public:
10 | explicit Completable(QObject *parent = 0);
11 |
12 | bool isCompleted();
13 | void markCompleted();
14 | void unmarkCompleted();
15 | void toggleCompleted();
16 |
17 | protected:
18 | bool mComplete;
19 |
20 | signals:
21 |
22 | public slots:
23 | void setCompleted(int state);
24 | };
25 |
26 | #endif // COMPLETABLE_H
27 |
--------------------------------------------------------------------------------
/src/lib/lib.pro:
--------------------------------------------------------------------------------
1 |
2 | TEMPLATE = lib
3 | TARGET = plotline
4 | QT += core gui widgets
5 | DEFINES += LIBPLOTLINE
6 |
7 | LIBPLOTLINE.path = $$OUT_PWD/
8 |
9 | HEADERS += chapter.h \
10 | character.h \
11 | completable.h \
12 | novel.h \
13 | plotline.h \
14 | scene.h \
15 | serializable.h \
16 | revision.h \
17 | utils.h \
18 | characterparser.h \
19 | author.h
20 |
21 | SOURCES += chapter.cpp \
22 | character.cpp \
23 | completable.cpp \
24 | novel.cpp \
25 | plotline.cpp \
26 | scene.cpp \
27 | serializable.cpp \
28 | revision.cpp \
29 | utils.cpp \
30 | characterparser.cpp \
31 | author.cpp
32 |
33 | INSTALLS += LIBPLOTLINE
34 |
35 | CONFIG += c++11
36 |
37 | CONFIG += -Wl,-export-all-symbols
38 | win:LIBS += -lws2_32
39 |
--------------------------------------------------------------------------------
/src/lib/novel.h:
--------------------------------------------------------------------------------
1 | #ifndef NOVEL_H
2 | #define NOVEL_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include "plotline.h"
8 | #include "chapter.h"
9 | #include "serializable.h"
10 | #include "revision.h"
11 | #include "author.h"
12 |
13 | class Chapter;
14 | class Plotline;
15 | class Character;
16 | class Scene;
17 | class Revision;
18 | class Author;
19 |
20 | class Novel : public QObject, public Serializable
21 | {
22 | Q_OBJECT
23 |
24 | public:
25 | enum Tense {
26 | Past=0, Present, Future, OtherTense,
27 | };
28 |
29 | enum PointOfView {
30 | FirstPersonSingular=0, SecondPersonSingular, ThirdPersonSingular,
31 | FirstPersonPlural, SecondPersonPlural, ThirdPersonPlural,
32 | OtherPointOfView,
33 | };
34 |
35 | explicit Novel(const QString &mWorkingTitle,
36 | const QString &mGenre = QString(),
37 | const QString &mSetting = QString(),
38 | const Novel::Tense tense = Past,
39 | const Novel::PointOfView pov = ThirdPersonSingular,
40 | Author *author = 0,
41 | const QList characters = QList(),
42 | const QList scenes = QList(),
43 | const QList chapters = QList(),
44 | const QList plotlines = QList(),
45 | const QStringList &revisions = QStringList(),
46 | int currentRevision = -1,
47 | QUuid id = QUuid(),
48 | QObject *parent = 0);
49 | ~Novel();
50 |
51 | QString getWorkingTitle() const;
52 |
53 | QString getGenre() const;
54 | void setWorkingTitle(const QString &value);
55 | void setGenre(const QString &value);
56 | void setSetting(const QString &value);
57 |
58 | Novel::Tense getTense() const;
59 | void setTense(const Novel::Tense tense);
60 |
61 | QString getSetting() const;
62 |
63 | QList scenes() const;
64 | void setScenes(const QList &value);
65 | void addScene(Scene *scene, int i=-1);
66 | void removeScene(Scene *scene);
67 | void removeScene(QUuid id);
68 | Scene *scene(QUuid id) const;
69 | void moveScenes(int from, int to);
70 |
71 | QList chapters() const;
72 | Chapter *chapterByNumber(int number);
73 | Chapter *chapter(QUuid id) const;
74 | void setChapters(const QList &value);
75 | void addChapter(Chapter *chapter, int loc = -1);
76 | Revision *chapterRevision(int chapter, int revision);
77 | void removeChapter(Chapter *chapter);
78 | void removeChapterAt(int index, bool doDelete=false);
79 | void moveChapter(int from, int to);
80 |
81 | Novel::PointOfView getPointOfView() const;
82 | void setPointOfView(const Novel::PointOfView &pointOfView);
83 |
84 | QList plotlines() const;
85 | Plotline *plotline(QUuid id) const;
86 | void setPlotlines(const QList &plotlines);
87 | void addPlotline(Plotline *plotline, int before=-1);
88 | void removePlotline(Plotline *plotline);
89 | void removePlotline(const QUuid id);
90 |
91 | QList characters();
92 | QList characters(const QRegularExpression &exp) const;
93 | QList characters(const QString &label) const;
94 | QList charactersByName(const QRegularExpression &exp) const;
95 | QList charactersByName(const QString &name) const;
96 | void setCharacters(const QList &characters);
97 | Character *character(const QUuid &id) const;
98 | Character *characterByLabel(const QString label) const;
99 | void addCharacter(Character *character, const int i=-1);
100 |
101 | QJsonObject serialize() const;
102 | static Novel *deserialize(const QJsonObject &object);
103 | QString writeTo(const QString &filePath);
104 | static Novel *readFrom(const QString &filePath, QString *error = 0);
105 |
106 | QStringList revisions() const;
107 | void addRevision(const QString &comment = QString());
108 | void addRevisions(const QStringList &comments);
109 | void removeRevision(const int index=-1);
110 | void setRevisions(const QStringList &revisions);
111 | void setRevisionComment(const int index, const QString &comment);
112 | void setRevisionComment(const QString &comment);
113 | QString revisionComment(const int index=-1) const;
114 | int revisionCount() const;
115 | void goToLatestRevision();
116 |
117 | int currentRevision() const;
118 | void setCurrentRevision(int currentRevison);
119 |
120 | Author *author() const;
121 | void setAuthor(Author *author);
122 |
123 | private:
124 |
125 | static const QString JSON_WORKING_TITLE,
126 | JSON_GENRE,
127 | JSON_SETTING,
128 | JSON_TENSE,
129 | JSON_POV,
130 | JSON_SCENES,
131 | JSON_AUTHOR,
132 | JSON_CHARACTERS,
133 | JSON_CHAPTERS,
134 | JSON_PLOTLINES,
135 | JSON_REVISIONS,
136 | JSON_CURRENT_REVISION;
137 |
138 | QString mWorkingTitle,
139 | mGenre,
140 | mSetting;
141 | Novel::Tense mTense;
142 | Novel::PointOfView mPointOfView;
143 | Author *mAuthor;
144 | QList mCharacters;
145 | QList mScenes;
146 | QList mChapters;
147 | QList mPlotlines;
148 |
149 | QStringList mRevisions;
150 | int mCurrentRevision;
151 |
152 | signals:
153 |
154 | void plotlinesChanged();
155 |
156 | public slots:
157 |
158 | };
159 |
160 | #endif // NOVEL_H
161 |
--------------------------------------------------------------------------------
/src/lib/plotline.cpp:
--------------------------------------------------------------------------------
1 | #include "plotline.h"
2 |
3 | const QString Plotline::J_CHARACTERS = "characters",
4 | Plotline::J_SCENES = "scenes",
5 | Plotline::J_SYNOPSIS = "synopsis",
6 | Plotline::J_BRIEF = "brief",
7 | Plotline::J_COLOR = "color";
8 |
9 | Plotline::Plotline(const QString &brief,
10 | const QString &synopsis,
11 | const QList &scenes,
12 | const QList &characters,
13 | const QColor &color,
14 | Novel *novel,
15 | QUuid id,
16 | QObject *parent)
17 | : QObject(parent), Serializable(id)
18 | {
19 | this->mBrief = brief;
20 | this->mSynopsis = synopsis;
21 | this->mColor = color;
22 | this->mScenes = scenes;
23 | this->mNovel = novel;
24 | this->mCharacters = characters;
25 | }
26 |
27 |
28 | QString Plotline::brief() const
29 | {
30 | return mBrief;
31 | }
32 |
33 | void Plotline::setBrief(const QString &brief)
34 | {
35 | mBrief = brief;
36 | }
37 |
38 | QColor Plotline::getColor() const
39 | {
40 | return mColor;
41 | }
42 |
43 | void Plotline::setColor(const QColor &color)
44 | {
45 | this->mColor = color;
46 | }
47 |
48 | QString Plotline::synopsis() const
49 | {
50 | return mSynopsis;
51 | }
52 |
53 | void Plotline::setSynopsis(const QString &synopsis)
54 | {
55 | this->mSynopsis = synopsis;
56 | }
57 |
58 | QList Plotline::characters() const
59 | {
60 | return mCharacters;
61 | }
62 |
63 | void Plotline::setCharacters(const QList &characters)
64 | {
65 | this->mCharacters = characters;
66 | }
67 |
68 | void Plotline::addCharacter(Character *character, const int before)
69 | {
70 | if (before > 0)
71 | mCharacters.insert(before, character);
72 | else
73 | mCharacters.append(character);
74 | }
75 |
76 | void Plotline::removeCharacter(Character *character)
77 | {
78 | this->mCharacters.removeAll(character);
79 | }
80 |
81 | void Plotline::removeCharacter(const QString &label)
82 | {
83 | for (Character *c : mCharacters)
84 | if (c->label() == label)
85 | mCharacters.removeAll(c);
86 | }
87 |
88 | QList Plotline::getScenes() const
89 | {
90 | return this->mScenes;
91 | }
92 |
93 | void Plotline::setScenes(const QList &scenes)
94 | {
95 | mScenes = scenes;
96 | }
97 |
98 | Novel *Plotline::novel()
99 | {
100 | return this->mNovel;
101 | }
102 |
103 | void Plotline::setNovel(Novel *novel)
104 | {
105 | this->mNovel = novel;
106 | }
107 |
108 | QJsonObject Plotline::serialize() const{
109 | QJsonObject plotline = QJsonObject();
110 |
111 | QJsonArray jCharacters = QJsonArray();
112 | for (Character *c : mCharacters)
113 | jCharacters.append(c->id().toString());
114 |
115 | QJsonArray jScenes = QJsonArray();
116 | for (Scene *s : mScenes)
117 | jScenes.append(s->id().toString());
118 |
119 | plotline[J_CHARACTERS] = jCharacters;
120 | plotline[J_SCENES] = jScenes;
121 | plotline[J_BRIEF] = mBrief;
122 | plotline[J_SYNOPSIS] = mSynopsis;
123 | plotline[J_COLOR] = mColor.name();
124 | plotline[JSON_ID] = id().toString();
125 |
126 | return plotline;
127 | }
128 |
129 | Plotline *Plotline::deserialize(Novel *novel, const QJsonObject &object)
130 | {
131 | QUuid id = Serializable::deserialize(object);
132 |
133 | QString brief = QString(), synopsis = QString();
134 | QList characters;
135 | QList scenes;
136 | QColor color = QColor();
137 |
138 | if (object.contains(J_BRIEF))
139 | brief = object[J_BRIEF].toString();
140 |
141 | if (object.contains(J_SYNOPSIS))
142 | synopsis = object[J_SYNOPSIS].toString();
143 |
144 | if (object.contains(J_CHARACTERS))
145 | for (QJsonValue val : object[J_CHARACTERS].toArray())
146 | characters.append(novel->character(QUuid(val.toString())));
147 |
148 | if (object.contains(J_SCENES))
149 | for (QJsonValue val : object[J_SCENES].toArray())
150 | scenes.append(novel->scene(QUuid(val.toString())));
151 |
152 | if (object.contains(J_COLOR))
153 | color = QColor(object[J_COLOR].toString());
154 |
155 | Plotline *plotline = new Plotline(brief, synopsis, scenes, characters,
156 | color, novel, id);
157 |
158 | return plotline;
159 | }
160 |
161 | QList Plotline::deserialize(Novel *novel, const QJsonArray &object)
162 | {
163 |
164 | QList plotlines = QList();
165 |
166 | for (QJsonValue value : object)
167 | if (value.isObject())
168 | plotlines.append(Plotline::deserialize(novel, value.toObject()));
169 |
170 | return plotlines;
171 | }
172 |
--------------------------------------------------------------------------------
/src/lib/plotline.h:
--------------------------------------------------------------------------------
1 | #ifndef PLOTLINE_H
2 | #define PLOTLINE_H
3 |
4 | #include
5 | #include
6 | #include "character.h"
7 | #include "scene.h"
8 | #include "serializable.h"
9 |
10 | class Novel;
11 | class Character;
12 | class Scene;
13 |
14 | class Plotline : public QObject, public Serializable
15 | {
16 | Q_OBJECT
17 |
18 | private:
19 |
20 | static const QString J_CHARACTERS,
21 | J_SCENES,
22 | J_SYNOPSIS,
23 | J_BRIEF,
24 | J_COLOR;
25 |
26 | QList mCharacters;
27 | QList mScenes;
28 | QString mBrief;
29 | QString mSynopsis;
30 | QColor mColor;
31 | Novel *mNovel;
32 |
33 | public:
34 | explicit Plotline(const QString &brief,
35 | const QString &synopsis,
36 | const QList &scenes = QList(),
37 | const QList &characters = QList(),
38 | const QColor &color = QColor(),
39 | Novel *novel = 0,
40 | QUuid id = QUuid(),
41 | QObject *parent = 0);
42 |
43 | QString synopsis() const;
44 | void setSynopsis(const QString &value);
45 |
46 | QColor getColor() const;
47 | void setColor(const QColor &value);
48 |
49 | QList characters() const;
50 | void setCharacters(const QList &characters);
51 | void addCharacter(Character *character, const int before = -1);
52 | void removeCharacter(Character *character);
53 | void removeCharacter(const QString &label);
54 |
55 | QList getScenes() const;
56 | void setScenes(const QList &scenes);
57 |
58 | Novel *novel();
59 | void setNovel(Novel *novel);
60 |
61 | QJsonObject serialize() const;
62 | static Plotline *deserialize(Novel *novel, const QJsonObject &object);
63 | static QList deserialize(Novel *novel, const QJsonArray &object);
64 |
65 | QString brief() const;
66 | void setBrief(const QString &brief);
67 |
68 | signals:
69 |
70 | public slots:
71 | };
72 |
73 | #endif // PLOTLINE_H
74 |
--------------------------------------------------------------------------------
/src/lib/revision.cpp:
--------------------------------------------------------------------------------
1 | #include "revision.h"
2 |
3 | const QString Revision::J_CONTENT = "content",
4 | Revision::J_CHAPTER = "chapter",
5 | Revision::J_IS_COMPLETE = "isComplete";
6 |
7 | Revision::Revision(const QString &content, Chapter *chapter, bool isComplete,
8 | const QUuid &id, QObject *parent)
9 | : QObject(parent), Serializable(id)
10 | {
11 | mContent = content;
12 | mChapter = chapter;
13 | mIsComplete = isComplete;
14 | }
15 |
16 | QString Revision::content() const
17 | {
18 | return mContent;
19 | }
20 |
21 | void Revision::setContent(const QString &content)
22 | {
23 | mContent = content;
24 | }
25 |
26 | QJsonObject Revision::serialize() const
27 | {
28 | const QUuid id = this->id();
29 |
30 | QJsonObject object = QJsonObject();
31 | object[JSON_ID] = id.toString();
32 | object[J_CONTENT] = mContent;
33 | object[J_IS_COMPLETE] = QJsonValue(mIsComplete);
34 |
35 | return object;
36 | }
37 |
38 | Revision *Revision::deserialize(Novel *novel, Chapter *chapter,
39 | const QJsonObject &object)
40 | {
41 | Q_UNUSED(novel);
42 | QString content = QString();
43 | bool isComplete = false;
44 | QUuid id;
45 | if (object.contains(J_CONTENT))
46 | content = object[J_CONTENT].toString();
47 | if (object.contains(J_IS_COMPLETE))
48 | isComplete = object[J_IS_COMPLETE].toBool();
49 | if (object.contains(JSON_ID))
50 | id = QUuid(object[JSON_ID].toString());
51 | Revision *revision = new Revision(content, chapter, isComplete, id);
52 |
53 | revision->setChapter(chapter);
54 |
55 | return revision;
56 | }
57 |
58 | QList Revision::deserialize(Novel *novel, Chapter *chapter,
59 | const QJsonArray &array)
60 | {
61 | QList revisions = QList();
62 | for (QJsonValue obj : array)
63 | revisions << Revision::deserialize(novel, chapter, obj.toObject());
64 |
65 | return revisions;
66 | }
67 |
68 | bool Revision::isComplete() const
69 | {
70 | return mIsComplete;
71 | }
72 |
73 | void Revision::setIsComplete(bool isComplete)
74 | {
75 | mIsComplete = isComplete;
76 | }
77 |
78 | void Revision::toggleComplete()
79 | {
80 | setIsComplete(!mIsComplete);
81 | }
82 |
83 | Chapter *Revision::chapter() const
84 | {
85 | return mChapter;
86 | }
87 |
88 | void Revision::setChapter(Chapter *chapter)
89 | {
90 | mChapter = chapter;
91 | }
92 |
--------------------------------------------------------------------------------
/src/lib/revision.h:
--------------------------------------------------------------------------------
1 | #ifndef REVISION_H
2 | #define REVISION_H
3 |
4 | #include "novel.h"
5 | #include "serializable.h"
6 | #include "completable.h"
7 | #include "chapter.h"
8 |
9 | class Chapter;
10 | class Novel;
11 |
12 | class Revision : public QObject, public Serializable
13 | {
14 | Q_OBJECT
15 | public:
16 | explicit Revision(const QString &content = QString(),
17 | Chapter *chapter = 0,
18 | bool isComplete = false,
19 | const QUuid &id = QUuid(),
20 | QObject *parent = 0);
21 |
22 | QString content() const;
23 | Chapter *chapter() const;
24 |
25 | void setChapter(Chapter *chapter);
26 | void setContent(const QString &content);
27 |
28 | QJsonObject serialize() const;
29 | static Revision *deserialize(Novel *novel, Chapter *chapter,
30 | const QJsonObject &object);
31 | static QList deserialize(Novel *novel, Chapter *chapter,
32 | const QJsonArray &object);
33 |
34 | bool isComplete() const;
35 | void setIsComplete(bool isComplete);
36 | void toggleComplete();
37 |
38 | private:
39 | QString mContent;
40 | Chapter *mChapter;
41 | bool mIsComplete;
42 |
43 | static const QString J_CONTENT,
44 | J_CHAPTER,
45 | J_IS_COMPLETE;
46 |
47 | signals:
48 |
49 | public slots:
50 | };
51 |
52 | #endif // REVISION_H
53 |
--------------------------------------------------------------------------------
/src/lib/scene.cpp:
--------------------------------------------------------------------------------
1 | #include "scene.h"
2 |
3 | const QString Scene::JSON_HEADLINE = QString("headline"),
4 | Scene::JSON_ACTION = QString("action"),
5 | Scene::JSON_CHARACTERS = QString("characters"),
6 | Scene::JSON_POV_CHARACTERS = QString("povCharacters"),
7 | Scene::JSON_PLOTLINE = QString("plotline");
8 |
9 | Novel *Scene::getNovel() const
10 | {
11 | return mNovel;
12 | }
13 |
14 | void Scene::setNovel(Novel *novel)
15 | {
16 | mNovel = novel;
17 | }
18 |
19 | Plotline *Scene::plotline() const
20 | {
21 | return mPlotline;
22 | }
23 |
24 | void Scene::setPlotline(Plotline *plotline)
25 | {
26 | mPlotline = plotline;
27 | }
28 |
29 | Scene::Scene(QObject *parent) : Completable(parent), Serializable()
30 | {
31 |
32 | }
33 |
34 | Scene::Scene(const QString &headline, const QString &action, Novel *novel,
35 | Plotline *plotline, const QUuid &id, QObject *parent) : Completable(parent),
36 | Serializable(id)
37 | {
38 | this->mHeadline = headline;
39 | this->mAction = action;
40 | this->mNovel = novel;
41 | mPlotline = plotline;
42 | }
43 |
44 | QString Scene::headline() const
45 | {
46 | return mHeadline;
47 | }
48 |
49 | void Scene::setHeadline(const QString &headline)
50 | {
51 | this->mHeadline = headline;
52 | }
53 |
54 | QString Scene::action() const
55 | {
56 | return mAction;
57 | }
58 |
59 | void Scene::setAction(const QString &action)
60 | {
61 | this->mAction = action;
62 | }
63 |
64 | QList Scene::getCharacters() const
65 | {
66 | return this->mCharacters;
67 | }
68 |
69 | void Scene::setPointsOfView(const QList &characters)
70 | {
71 | this->mPovCharacters = characters;
72 | }
73 |
74 | QList Scene::getPointsOfView() const
75 | {
76 | return this->mPovCharacters;
77 | }
78 |
79 | void Scene::setCharacters(const QList &characters)
80 | {
81 | this->mCharacters = characters;
82 | }
83 |
84 | void Scene::addCharacter(const QUuid &id)
85 | {
86 | mCharacters.append(mNovel->character(id));
87 | }
88 |
89 | void Scene::removeCharacter(Character *character)
90 | {
91 | mCharacters.removeAll(character);
92 | }
93 |
94 | void Scene::removeCharacter(const QUuid &id)
95 | {
96 | mCharacters.removeAll(mNovel->character(id));
97 | }
98 |
99 | QJsonObject Scene::serialize() const
100 | {
101 | QJsonObject scene = QJsonObject();
102 |
103 | // When adding the character list, just add the character
104 | // IDs to avoid redundancy.
105 |
106 | QJsonArray jCharacters = QJsonArray(),
107 | jPovCharacters = QJsonArray();
108 |
109 | for (Character *c : mCharacters)
110 | jCharacters.append(c->id().toString());
111 |
112 | for (Character *c : mPovCharacters)
113 | jPovCharacters.append(c->id().toString());
114 |
115 | scene[JSON_HEADLINE] = mHeadline;
116 | scene[JSON_ACTION] = mAction;
117 | scene[JSON_CHARACTERS] = jCharacters;
118 | scene[JSON_POV_CHARACTERS] = jPovCharacters;
119 | scene[JSON_ID] = id().toString();
120 | if (mPlotline)
121 | scene.insert(JSON_PLOTLINE, QJsonValue(mPlotline->id().toString()));
122 |
123 | return scene;
124 | }
125 |
126 | Scene *Scene::deserialize(Novel *novel, const QJsonObject &object)
127 | {
128 |
129 | QString headline = QString(), action = QString();
130 | Plotline *plotline = 0;
131 |
132 | QList characters = QList(),
133 | povCharacters = QList();
134 |
135 | QStringList missing = QStringList();
136 |
137 | if (object.contains(JSON_HEADLINE))
138 | headline = object[JSON_HEADLINE].toString();
139 | else
140 | missing.append(JSON_HEADLINE);
141 |
142 | if (object.contains(JSON_ACTION))
143 | action = object[JSON_ACTION].toString();
144 | else
145 | missing.append(JSON_ACTION);
146 |
147 | if (object.contains(JSON_CHARACTERS))
148 | for (QJsonValue val : object[JSON_CHARACTERS].toArray())
149 | characters << novel->character(QUuid(val.toString()));
150 | else
151 | missing.append(JSON_CHARACTERS);
152 |
153 | if (object.contains(JSON_POV_CHARACTERS))
154 | for (QJsonValue val : object[JSON_POV_CHARACTERS].toArray())
155 | povCharacters.append(novel->character(QUuid(val.toString())));
156 |
157 | if (object.contains(JSON_PLOTLINE))
158 | plotline = novel->plotline(QUuid(object[JSON_PLOTLINE].toString()));
159 |
160 | if (!missing.empty())
161 | qWarning() << "Scene missing the following fields: "
162 | << missing.join(",");
163 |
164 | QUuid id = QUuid(object[JSON_ID].toString());
165 | qDebug() << "[+] deserialize scene with id" << id;
166 | Scene *scene = new Scene(headline, action, novel, plotline, id);
167 | scene->setCharacters(characters);
168 | scene->setPointsOfView(povCharacters);
169 | return scene;
170 | }
171 |
172 | QList Scene::deserialize(Novel *novel, const QJsonArray &object)
173 | {
174 | QList scenes;
175 | for (QJsonValue obj : object){
176 | if (obj.isObject())
177 | scenes << Scene::deserialize(novel, obj.toObject());
178 | else
179 | scenes << novel->scene(QUuid(obj.toString()));
180 | }
181 |
182 | return scenes;
183 | }
184 |
--------------------------------------------------------------------------------
/src/lib/scene.h:
--------------------------------------------------------------------------------
1 | #ifndef SCENE_H
2 | #define SCENE_H
3 |
4 | #include
5 | #include "completable.h"
6 | #include "character.h"
7 | #include "novel.h"
8 | #include "plotline.h"
9 |
10 | class Novel;
11 | class Character;
12 | class Plotline;
13 |
14 | class Scene : public Completable, public Serializable
15 | {
16 | Q_OBJECT
17 | private:
18 |
19 | QString mHeadline,
20 | mAction;
21 | QList mCharacters;
22 | QList mPovCharacters;
23 | Plotline *mPlotline;
24 | Novel *mNovel;
25 |
26 | static const QString JSON_HEADLINE,
27 | JSON_ACTION,
28 | JSON_CHARACTERS,
29 | JSON_POV_CHARACTERS,
30 | JSON_PLOTLINE;
31 |
32 | public:
33 | explicit Scene(QObject *parent=0);
34 | explicit Scene(const QString &mHeadline, const QString &mAction,
35 | Novel *novel = 0, Plotline *plotline = 0,
36 | const QUuid &id = QUuid(), QObject *parent = 0);
37 |
38 | QString headline() const;
39 | void setHeadline(const QString &mHeadline);
40 |
41 | QString action() const;
42 | void setAction(const QString &value);
43 |
44 | void setCharacters(const QList &mCharacters);
45 | void addCharacter(Character *character);
46 | void addCharacter(const QUuid &id);
47 | void removeCharacter(Character *character);
48 | void removeCharacter(const QUuid &id);
49 | QList getCharacters() const;
50 |
51 | void setPointsOfView(const QList &mCharacters);
52 | QList getPointsOfView() const;
53 |
54 | Novel *getNovel() const;
55 | void setNovel(Novel *novel);
56 |
57 | QJsonObject serialize() const;
58 | static Scene *deserialize(Novel *novel, const QJsonObject &object);
59 | static QList deserialize(Novel *novel, const QJsonArray &object);
60 |
61 | Plotline *plotline() const;
62 | void setPlotline(Plotline *plotline);
63 |
64 | signals:
65 |
66 | public slots:
67 | };
68 |
69 | #endif // SCENE_H
70 |
--------------------------------------------------------------------------------
/src/lib/serializable.cpp:
--------------------------------------------------------------------------------
1 | #include "serializable.h"
2 |
3 | const QString Serializable::JSON_ID = "id";
4 |
5 | Serializable::Serializable(QUuid id)
6 | {
7 | if (id.isNull()){
8 | mId = QUuid::createUuid();
9 | } else {
10 | mId = id;
11 | }
12 | }
13 |
14 | QUuid Serializable::deserialize(const QJsonObject &object)
15 | {
16 | QJsonValue value = object.value(JSON_ID);
17 | if (!value.isNull())
18 | return QUuid(value.toString());
19 | return QUuid::createUuid();
20 | }
21 |
22 | QUuid Serializable::id() const
23 | {
24 | return mId;
25 | }
26 |
27 | void Serializable::setId(const QUuid id)
28 | {
29 | mId = id;
30 | }
31 |
32 |
--------------------------------------------------------------------------------
/src/lib/serializable.h:
--------------------------------------------------------------------------------
1 | #ifndef SERIALIZABLE_H
2 | #define SERIALIZABLE_H
3 |
4 | #include
5 | #include
6 |
7 | class Serializable
8 | {
9 | private:
10 |
11 | static int sCurrentId;
12 | // Yes, this is kind of awkard (this will generate a new ID for every
13 | // SERIALIZABLE instance instead of every subclass instance, but this
14 | // will take the work-load off the subclasses.
15 |
16 | QUuid mId;
17 | protected:
18 |
19 | static const QString JSON_ID;
20 |
21 | public:
22 | Serializable(QUuid id = QUuid());
23 |
24 | virtual QJsonObject serialize() const = 0;
25 | static QUuid deserialize(const QJsonObject &object);
26 |
27 | QUuid id() const;
28 | void setId(const QUuid id);
29 | };
30 |
31 | #endif // SERIALIZABLE_H
32 |
--------------------------------------------------------------------------------
/src/lib/utils.h:
--------------------------------------------------------------------------------
1 | #ifndef UTILS_H
2 | #define UTILS_H
3 |
4 | #include
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 | #include
12 |
13 | // Thanks to http://stackoverflow.com/a/32378165
14 |
15 | QJsonValue jsonValFromPixmap(const QPixmap &p);
16 | QJsonValue jsonValFromImage(const QImage &i);
17 | QPixmap pixmapFrom(const QJsonValue & val);
18 | QImage imageFrom(const QJsonValue &val);
19 | QString friendlyList(const QStringList &stringList);
20 |
21 | // Thanks to http://stackoverflow.com/a/7077340
22 | void clearLayout(QLayout* layout, bool deleteWidgets = true);
23 | void setEnabledRecursive(QLayout *layout, bool enabled);
24 | void setDisabledRecursive(QLayout *layout, bool enabled);
25 |
26 | int findCharReverse(const QString &chars, const QString &s, const int from,
27 | const QString &escape=QString());
28 | QString substring(const QString &string, int start, int end=-1);
29 | QPair multilineOffset(QString string, int offset);
30 | QString reflowParagraph(const QString ¶graph, const int width);
31 | QString reflowParagraphs(const QString ¶graph, const int width);
32 |
33 | // Number conversion (intended for chapters)
34 | QString toRomanNumeral(const int number);
35 | QString toWord(const int number);
36 |
37 | #endif // UTILS_H
38 |
--------------------------------------------------------------------------------
/src/res/images/.directory:
--------------------------------------------------------------------------------
1 | [Dolphin]
2 | PreviewsShown=true
3 | Timestamp=2016,1,30,9,39,10
4 | Version=3
5 |
--------------------------------------------------------------------------------
/src/res/images/ATTRIBUTIONS.txt:
--------------------------------------------------------------------------------
1 | clapboard.svg
2 | https://openclipart.org/detail/84157/video
3 |
--------------------------------------------------------------------------------
/src/res/images/application-exit.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/application-exit.png
--------------------------------------------------------------------------------
/src/res/images/book.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/book.png
--------------------------------------------------------------------------------
/src/res/images/document-new.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/document-new.png
--------------------------------------------------------------------------------
/src/res/images/document-open-folder.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/document-open-folder.png
--------------------------------------------------------------------------------
/src/res/images/document-open.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/document-open.png
--------------------------------------------------------------------------------
/src/res/images/document-save-as.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/document-save-as.png
--------------------------------------------------------------------------------
/src/res/images/document-save.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/document-save.png
--------------------------------------------------------------------------------
/src/res/images/edit-clear-locationbar-rtl.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/edit-clear-locationbar-rtl.png
--------------------------------------------------------------------------------
/src/res/images/emblem-favorite.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/emblem-favorite.png
--------------------------------------------------------------------------------
/src/res/images/fill-color.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/fill-color.png
--------------------------------------------------------------------------------
/src/res/images/format-list-ordered.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/format-list-ordered.png
--------------------------------------------------------------------------------
/src/res/images/list-add-plotline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/list-add-plotline.png
--------------------------------------------------------------------------------
/src/res/images/list-add-user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/list-add-user.png
--------------------------------------------------------------------------------
/src/res/images/list-add.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/list-add.png
--------------------------------------------------------------------------------
/src/res/images/list-remove-plotline.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/list-remove-plotline.png
--------------------------------------------------------------------------------
/src/res/images/list-remove-user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/list-remove-user.png
--------------------------------------------------------------------------------
/src/res/images/list-remove.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/list-remove.png
--------------------------------------------------------------------------------
/src/res/images/plotline-launcher.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
130 |
--------------------------------------------------------------------------------
/src/res/images/user-archive.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/user-archive.png
--------------------------------------------------------------------------------
/src/res/images/user-identity.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/user-identity.png
--------------------------------------------------------------------------------
/src/res/images/user-properties.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/user-properties.png
--------------------------------------------------------------------------------
/src/res/images/utilities-file-archiver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/src-r-r/plotline/726ab94d379ca21206f6979d2ebb92be83149593/src/res/images/utilities-file-archiver.png
--------------------------------------------------------------------------------
/src/res/plotline.qrc:
--------------------------------------------------------------------------------
1 |
2 |
3 | images/application-exit.png
4 | images/book.png
5 | images/document-new.png
6 | images/document-open.png
7 | images/document-save.png
8 | images/emblem-favorite.png
9 | images/list-add-plotline.png
10 | images/list-add-user.png
11 | images/list-remove-plotline.png
12 | images/list-remove-user.png
13 | images/user-archive.png
14 | images/user-identity.png
15 | images/user-properties.png
16 | images/document-save-as.png
17 | images/edit-clear-locationbar-rtl.png
18 | images/fill-color.png
19 | images/list-add.png
20 | images/list-remove.png
21 | images/utilities-file-archiver.png
22 | images/revision.svg
23 | images/format-list-ordered.png
24 | images/45834457236.svg
25 | images/gtk-edit.svg
26 | images/plotline-launcher.svg
27 | images/document-open-folder.png
28 |
29 |
30 | styles/default.json
31 | styles/default-dark.json
32 |
33 |
34 |
--------------------------------------------------------------------------------
/src/res/styles/default-dark.json:
--------------------------------------------------------------------------------
1 | {
2 | "META" : {
3 | "name" : "Default (Dark)",
4 | "comment" : "Default theme with a sinister twist."
5 | },
6 | "style" : {
7 | "document" : {
8 | "foreground" : "#ffffff",
9 | "background" : "#000000"
10 | },
11 | "HtmlEscape" : {
12 | "foreground" : "#2715b0",
13 | "bold" : true
14 | },
15 | "Header" : {
16 | "bold" : true,
17 | "relSize" : 3
18 | },
19 | "BlockQuote" : {
20 | "italic" : true,
21 | "background" : "#aaaaaa"
22 | },
23 | "List" : {
24 |
25 | },
26 | "CodeBlock" : {
27 |
28 | },
29 | "HorizontalRule" : {
30 |
31 | },
32 | "InlineLink" : {
33 |
34 | },
35 | "LinkSource" : {
36 |
37 | },
38 | "LinkTarget" : {
39 |
40 | },
41 | "Emphasis" : {
42 | "italic" : true
43 | },
44 | "Strong" : {
45 | "bold" : true
46 | },
47 | "InlineCode" : {
48 |
49 | },
50 | "Image" : {
51 |
52 | },
53 | "AutomaticLink" : {
54 |
55 | },
56 | "BackslashEscape" : {
57 |
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/res/styles/default.json:
--------------------------------------------------------------------------------
1 | {
2 | "META" : {
3 | "name" : "Default",
4 | "comment" : "Default plotline theme."
5 | },
6 | "style" : {
7 | "document" : {
8 | "foreground" : "#000000",
9 | "background" : "#ffffff"
10 | },
11 | "HtmlEscape" : {
12 | "foreground" : "#2715b0",
13 | "bold" : true
14 | },
15 | "Header" : {
16 | "bold" : true,
17 | "relSize" : 3
18 | },
19 | "BlockQuote" : {
20 | "italic" : true,
21 | "background" : "#aaaaaa"
22 | },
23 | "List" : {
24 |
25 | },
26 | "CodeBlock" : {
27 |
28 | },
29 | "HorizontalRule" : {
30 |
31 | },
32 | "InlineLink" : {
33 |
34 | },
35 | "LinkSource" : {
36 |
37 | },
38 | "LinkTarget" : {
39 |
40 | },
41 | "Emphasis" : {
42 | "italic" : true
43 | },
44 | "Strong" : {
45 | "bold" : true
46 | },
47 | "InlineCode" : {
48 |
49 | },
50 | "Image" : {
51 |
52 | },
53 | "AutomaticLink" : {
54 |
55 | },
56 | "BackslashEscape" : {
57 |
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/src.pro:
--------------------------------------------------------------------------------
1 | ######################################################################
2 | # Automatically generated by qmake (3.0) Tue Jan 19 18:57:44 2016
3 | ######################################################################
4 |
5 | TEMPLATE = subdirs
6 |
7 | CONFIG += ordered
8 |
9 | SUBDIRS += \
10 | lib \
11 | app
12 |
13 | CONFIG += gnu++11
14 |
15 | app.depends = lib
16 | test.depends = lib
17 |
--------------------------------------------------------------------------------
/test/test.pro:
--------------------------------------------------------------------------------
1 | ######################################################################
2 | # Automatically generated by qmake (3.0) Tue Jan 19 19:02:44 2016
3 | ######################################################################
4 |
5 | TEMPLATE = subdirs
6 |
7 | SUBDIRS += \
8 | ./unit
9 |
10 | LIBS += -L$$OUT_PWD../../src/lib/libplotline.a
11 |
12 | INCLUDEPATH += \
13 | $$PWD/../../src/lib
14 |
15 | CONFIG += c++11
16 |
--------------------------------------------------------------------------------
/test/unit/fixtures/chapter-deserialize.json:
--------------------------------------------------------------------------------
1 | {
2 | "id" : 11,
3 | "title" : "My First Chapter",
4 | "scenes" : [
5 | 2,
6 | 3,
7 | 4
8 | ],
9 | "revisions" : [
10 | {
11 | "id" : 5,
12 | "content" : "Revision 1 content",
13 | "isComplete" : true
14 | },
15 |
16 | {
17 | "id" : 6,
18 | "content" : "Revision 2 content (was 1)",
19 | "isComplete" : false
20 | }
21 |
22 | ]
23 | }
24 |
--------------------------------------------------------------------------------
/test/unit/fixtures/character-deserialize.json:
--------------------------------------------------------------------------------
1 | {
2 | "id" : 2,
3 | "name" : "Theodore Roosevelt",
4 | "label" : "ThRo",
5 | "scenes" : [9, 10, 11],
6 | "color" : "#ffaaff"
7 | }
8 |
--------------------------------------------------------------------------------
/test/unit/fixtures/novel-deserialize.json:
--------------------------------------------------------------------------------
1 | {
2 | "id" : 30,
3 | "workingTitle" : "My Novel",
4 | "genre" : "My Genre",
5 | "scenes" : [
6 | {
7 | "id" : 2,
8 | "headline" : "Headline 1",
9 | "action" : "Action 1",
10 | "characters" : [ 5, 6, 7 ],
11 | "povCharacters" : [ 5 ]
12 | },
13 | {
14 | "id" : 3,
15 | "headline" : "Headline 2",
16 | "action" : "Action 2",
17 | "characters" : [ 6, 7 ],
18 | "povCharacters" : [ 6 ]
19 | },
20 | {
21 | "id" : 4,
22 | "headline" : "Headline 3",
23 | "action" : "Action 3",
24 | "characters" : [ 5, 7 ],
25 | "povCharacters" : [ 5, 7 ]
26 | }
27 | ],
28 | "characters" : [
29 | {
30 | "id" : 5,
31 | "name" : "George Washington",
32 | "label" : "GeWa"
33 | },
34 | {
35 | "id" : 6,
36 | "name" : "Abraham Lincoln",
37 | "label" : "AbLi"
38 | },
39 | {
40 | "id" : 7,
41 | "name" : "Robert E. Lee",
42 | "label" : "RoELe"
43 | }
44 | ],
45 | "chapters" : [
46 | {
47 | "id" : 8,
48 | "title" : "Chapter 1",
49 | "scenes" : [ 2 ]
50 | },
51 | {
52 | "id" : 9,
53 | "title" : "Chapter 2",
54 | "scenes" : [ 3 ]
55 | },
56 | {
57 | "id" : 10,
58 | "title" : "Chapter 3",
59 | "scenes" : [ 3, 4 ]
60 | }
61 | ]
62 | }
63 |
--------------------------------------------------------------------------------
/test/unit/fixtures/revision-bug-test.json:
--------------------------------------------------------------------------------
1 | {
2 | "id" : 1,
3 | "workingTitle" : "Novel Title",
4 | "genre" : "Novel Genre",
5 | "revisions" : [
6 | "First Revision",
7 | "Second Revision",
8 | "Third Revision"
9 | ],
10 | "chapters" : [
11 | {
12 | "id" : 2,
13 | "title" : "Chapter 1",
14 | "revisions" : [
15 | {
16 | "id" : 3,
17 | "isComplete" : true,
18 | "content" : "Chapter One, Revision 0"
19 | },
20 | {
21 | "id" : 4,
22 | "isComplete" : false,
23 | "content" : "Chapter One, Revision 1"
24 | },
25 | {
26 | "id" : 5,
27 | "isComplete" : false,
28 | "content" : "Chapter One, Revision 2"
29 | }
30 | ]
31 | },
32 | {
33 | "id" : 6,
34 | "title" : "Chapter 2",
35 | "revisions" : [
36 | {
37 | "id" : 7,
38 | "isComplete" : true,
39 | "content" : "Chapter Two, Revision 0"
40 | },
41 | {
42 | "id" : 8,
43 | "isComplete" : false,
44 | "content" : "Chapter Two, Revision 1"
45 | }
46 | ]
47 | }
48 | ]
49 | }
50 |
--------------------------------------------------------------------------------
/test/unit/fixtures/revision-deserialize.json:
--------------------------------------------------------------------------------
1 | {
2 | "id" : 2,
3 | "content" : "Revision Content",
4 | "isComplete" : true
5 | }
6 |
--------------------------------------------------------------------------------
/test/unit/main.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 | #include
4 | #include
5 | #include
6 |
7 | #include "tst_utils.h"
8 | #include "tst_revision.h"
9 | #include "tst_character.cpp"
10 | #include "tst_chapter.cpp"
11 | #include "tst_novel.cpp"
12 | #include "tst_scene.cpp"
13 | #include "tst_plotline.h"
14 | #include "testcharacterparser.h"
15 |
16 | int main(int argc, char *argv[])
17 | {
18 |
19 | QObject *tests[] = {
20 |
21 | new TestUtils(),
22 | // new TestCharacter(),
23 | new TestRevision(),
24 | // new TestScene(),
25 | // new TestChapter(),
26 | // new TestNovel(),
27 | // new TestPlotline(),
28 | // new TestCharacterParser(),
29 |
30 | NULL
31 | };
32 |
33 | QGuiApplication a(argc, argv);
34 |
35 | int nFailed = 0;
36 |
37 | for (int i = 0; tests[i]; ++i)
38 | nFailed += QTest::qExec(tests[i], argc, argv);
39 |
40 | const char *border = "+++++++++++++++++";
41 |
42 | if (nFailed > 0)
43 | qWarning() << border << nFailed << " tests failed. "
44 | << border;
45 | else
46 | qDebug() << border << "All tests passed" << border;
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/test/unit/testcharacterparser.cpp:
--------------------------------------------------------------------------------
1 | #include "testcharacterparser.h"
2 |
3 | TestCharacterParser::TestCharacterParser(QObject *parent) : QObject(parent)
4 | {
5 |
6 | }
7 |
8 | void TestCharacterParser::testParser()
9 | {
10 | Novel *novel = new Novel("Test Novel");
11 |
12 | Character *c1 = new Character("Bob McCalin"),
13 | *c2 = new Character("Sue Robinson"),
14 | *c3 = new Character("Henry Scott");
15 |
16 | novel->addCharacter(c1);
17 | novel->addCharacter(c2);
18 | novel->addCharacter(c3);
19 |
20 | QString string = QString("This scene will include @BoMc and @SuRo ") +
21 | QString("but will not include @HeS (Henry Scott) ") +
22 | QString("because someone made a typo.");
23 |
24 | ParsedCharacterSet set = ParsedCharacterSet::parse(novel, string);
25 |
26 | int i1 = string.indexOf("@BoMc"),
27 | i2 = string.indexOf("@SuRo"),
28 | i3 = string.indexOf("@HeS");
29 |
30 | for (int i : set.keys())
31 | qDebug() << i << ":" << set.value(i)->label();
32 |
33 | Q_ASSERT(set.contains(i1));
34 | Q_ASSERT(set.contains(i2));
35 | Q_ASSERT(!set.contains(i3));
36 |
37 | Q_ASSERT(set.value(i1) == c1);
38 | Q_ASSERT(set.value(i2) == c2);
39 |
40 | // An initial bug where the function will only find a handful of the
41 | // ocurrances of characters. Find out what went wrong.
42 |
43 | string = QString("@BoMc and @SuRo and @HeSc and @BoMc and @SuRo");
44 |
45 | set = ParsedCharacterSet::parse(novel, string);
46 | Q_ASSERT(set.count() == 5);
47 | }
48 |
49 |
--------------------------------------------------------------------------------
/test/unit/testcharacterparser.h:
--------------------------------------------------------------------------------
1 | #ifndef TESTCHARACTERPARSER_H
2 | #define TESTCHARACTERPARSER_H
3 |
4 | #include
5 | #include
6 |
7 | #include "characterparser.h"
8 |
9 | class TestCharacterParser : public QObject
10 | {
11 | Q_OBJECT
12 | public:
13 | explicit TestCharacterParser(QObject *parent = 0);
14 |
15 | signals:
16 |
17 | public slots:
18 |
19 |
20 | private Q_SLOTS:
21 |
22 | void testParser();
23 | };
24 |
25 | #endif // TESTCHARACTERPARSER_H
26 |
--------------------------------------------------------------------------------
/test/unit/tst_chapter.cpp:
--------------------------------------------------------------------------------
1 | #include "tst_chapter.h"
2 |
3 | TestChapter::TestChapter(QObject *parent) : QObject(parent)
4 | {
5 |
6 | }
7 |
8 | void TestChapter::initTestCase(){
9 | mTestCharacters = new QList();
10 |
11 | mTestScenes = new QList();
12 |
13 | }
14 |
15 | void TestChapter::testConstructor()
16 | {
17 | Chapter *chapter = new Chapter();
18 |
19 | chapter = new Chapter(QString("My First Chapter"));
20 | QTRY_COMPARE(chapter->title(), QString("My First Chapter"));
21 |
22 | // Test it with revisisons.
23 |
24 | delete chapter;
25 | }
26 |
27 | void TestChapter::testSetScenes()
28 | {
29 | Chapter *chapter1 = new Chapter(QString("My First Chapter"));
30 |
31 | Scene *s1 = new Scene(
32 | QString("First test scene."),
33 | QString("This is my first test scene. Are you excited?")
34 | ),
35 | *s2 = new Scene (
36 | QString("2nd Test Scene"),
37 | QString("This is my second test scene! Now I'm really excited.")),
38 | *s3 = new Scene (
39 | QString("3rd test scene."),
40 | QString("Okay, enough for now. 3 should be enough."));
41 |
42 | QList ch1Scenes = QList();
43 | ch1Scenes.append(s1);
44 | ch1Scenes.append(s2);
45 | ch1Scenes.append(s3);
46 | chapter1->setScenes(ch1Scenes);
47 |
48 | Q_ASSERT(chapter1->scenes().size() == 3);
49 | }
50 |
51 | void TestChapter::testAddRevision()
52 | {
53 | Chapter *c = new Chapter("Chapter");
54 | Revision *r1 = c->addRevision();
55 |
56 | Q_ASSERT(c->revisions().length() == 1);
57 | Q_ASSERT(c->revisions()[0]->content().isNull());
58 |
59 | QString s1 = "Hte quick brown fox jumps over teh lazy dog.",
60 | s2 = "The quick brown fox jumps over the lazy dog.";
61 |
62 | r1->setContent(s1);
63 | Revision *r2 = c->addRevision();
64 |
65 | Q_ASSERT(c->revisions().length() == 2);
66 | QTRY_COMPARE(c->revisions()[0]->content(), s1);
67 | QTRY_COMPARE(c->revisions()[1]->content(), s1);
68 |
69 | r2->setContent(s2);
70 | QTRY_COMPARE(c->revisions()[1]->content(), s2);
71 | }
72 |
73 | void TestChapter::cleanupTestCase()
74 | {
75 | delete mTestCharacters;
76 | delete mTestScenes;
77 | }
78 |
79 | void TestChapter::testSerialize()
80 | {
81 | Chapter *chapter1 = new Chapter(QString("My First Chapter"));
82 |
83 | Scene *s1 = new Scene(
84 | QString("First test scene."),
85 | QString("This is my first test scene. Are you excited?")
86 | ),
87 | *s2 = new Scene (
88 | QString("2nd Test Scene"),
89 | QString("This is my second test scene! Now I'm really excited.")),
90 | *s3 = new Scene (
91 | QString("3rd test scene."),
92 | QString("Okay, enough for now. 3 should be enough."));
93 | QList ch1Scenes = QList();
94 | ch1Scenes.append(s1);
95 | ch1Scenes.append(s2);
96 | ch1Scenes.append(s3);
97 | chapter1->setScenes(ch1Scenes);
98 |
99 | QJsonObject jChapter = chapter1->serialize();
100 | Q_ASSERT(jChapter.contains(QString("title")));
101 | Q_ASSERT(jChapter.contains(QString("scenes")));
102 |
103 | QTRY_COMPARE(jChapter["title"].toString(), QString("My First Chapter"));
104 |
105 | QJsonDocument doc = QJsonDocument(jChapter);
106 | }
107 |
108 | void TestChapter::testDeserialize()
109 | {
110 |
111 | Novel *novel = new Novel(QString("My Novel"), QString("My Genre"));
112 |
113 | Scene *s1 = new Scene(
114 | QString("First test scene."),
115 | QString("This is my first test scene. Are you excited?")
116 | ),
117 | *s2 = new Scene (
118 | QString("2nd Test Scene"),
119 | QString("This is my second test scene! Now I'm really excited.")),
120 | *s3 = new Scene (
121 | QString("3rd test scene."),
122 | QString("Okay, enough for now. 3 should be enough."));
123 | s1->setId(QUuid::createUuid());
124 | s2->setId(QUuid::createUuid());
125 | s3->setId(QUuid::createUuid());
126 | QList ch1Scenes = QList();
127 | ch1Scenes.append(s1);
128 | ch1Scenes.append(s2);
129 | ch1Scenes.append(s3);
130 | novel->setScenes(ch1Scenes);
131 |
132 | QFile *json = new QFile(QString("../../../Plotline/test/unit/fixtures/chapter-deserialize.json"));
133 | Q_ASSERT(json->open(QFile::ReadOnly) == true);
134 | QByteArray jsonContent = json->readAll();
135 | qDebug() << "Parsing content" << jsonContent;
136 | QJsonParseError *error = new QJsonParseError();
137 | QJsonDocument doc = QJsonDocument::fromJson(jsonContent, error);
138 | json->close();
139 |
140 | if (doc.isEmpty() || doc.isNull()){
141 | qDebug() << error->errorString();
142 | qFatal("Could not open json file.");
143 | }
144 |
145 | Chapter *chapter = Chapter::deserialize(novel, doc.object());
146 |
147 | QTRY_COMPARE(chapter->title(), QString("My First Chapter"));
148 | Q_ASSERT(chapter->scenes().size() == 3);
149 | QTRY_COMPARE(chapter->scenes()[0], s1);
150 | QTRY_COMPARE(chapter->scenes()[1], s2);
151 | QTRY_COMPARE(chapter->scenes()[2], s3);
152 | }
153 |
--------------------------------------------------------------------------------
/test/unit/tst_chapter.h:
--------------------------------------------------------------------------------
1 | #ifndef TST_CHAPTER_H
2 | #define TST_CHAPTER_H
3 |
4 | #include
5 | #include