EMMA Coverage Report (generated Sat Oct 08 11:41:37 CEST 2011)
[all classes][net.sf.jomic.comic]

COVERAGE SUMMARY FOR SOURCE FILE [ComicView.java]

nameclass, %method, %block, %line, %
ComicView.java100% (2/2)85%  (57/67)72%  (1677/2321)82%  (395/479)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ComicView100% (1/1)85%  (55/65)72%  (1667/2311)82%  (392/476)
componentHidden (ComponentEvent): void 0%   (0/1)0%   (0/1)0%   (0/1)
componentShown (ComponentEvent): void 0%   (0/1)0%   (0/1)0%   (0/1)
getGenericComicImageName (int): String 0%   (0/1)0%   (0/90)0%   (0/13)
goFirst (): void 0%   (0/1)0%   (0/4)0%   (0/2)
goNextFew (): void 0%   (0/1)0%   (0/6)0%   (0/2)
goPreviousFew (): void 0%   (0/1)0%   (0/6)0%   (0/2)
scroll (JScrollBar, int): void 0%   (0/1)0%   (0/19)0%   (0/3)
scrollHorizontally (int): void 0%   (0/1)0%   (0/6)0%   (0/2)
scrollVertically (int): void 0%   (0/1)0%   (0/6)0%   (0/2)
setRotateOnlySinglePortraitImages (boolean): void 0%   (0/1)0%   (0/5)0%   (0/2)
assertImageIndexIsValid (int): void 100% (1/1)28%  (11/40)50%  (1.5/3)
setPage (int): void 100% (1/1)43%  (16/37)69%  (2.8/4)
setImageIndex (int): void 100% (1/1)46%  (61/133)63%  (17/27)
propertyChange (PropertyChangeEvent): void 100% (1/1)50%  (42/84)76%  (12.1/16)
scrollHome (): void 100% (1/1)55%  (67/121)57%  (15.3/27)
getImageIndexForPage (int): int 100% (1/1)56%  (39/70)84%  (8.4/10)
addSheet (int, int): ComicSheet 100% (1/1)56%  (36/64)74%  (5.9/8)
getRenderedImage (): RenderedImage 100% (1/1)63%  (57/91)94%  (17/18)
precacheComicImage (int): void 100% (1/1)63%  (33/52)79%  (7.1/9)
getRenderedImage (int, int): RenderedImage 100% (1/1)69%  (105/152)81%  (24.4/30)
setModel (ComicModel, ProgressFrame, int): void 100% (1/1)73%  (159/217)85%  (30.8/36)
<static initializer> 100% (1/1)80%  (12/15)80%  (0.8/1)
goPrevious (int): void 100% (1/1)82%  (37/45)90%  (8.1/9)
goNext (int): void 100% (1/1)85%  (44/52)90%  (8.1/9)
getExpectedViewSize (int, int): Dimension 100% (1/1)87%  (126/145)92%  (37/40)
createImagePanel (): JPanel 100% (1/1)87%  (135/155)93%  (30.8/33)
ComicView (): void 100% (1/1)97%  (158/163)100% (31/31)
getPageText (): String 100% (1/1)98%  (105/107)95%  (19/20)
componentMoved (ComponentEvent): void 100% (1/1)100% (1/1)100% (1/1)
componentResized (ComponentEvent): void 100% (1/1)100% (3/3)100% (2/2)
createColorBox (): ColorBox 100% (1/1)100% (16/16)100% (3/3)
dispose (): void 100% (1/1)100% (11/11)100% (4/4)
getComicImage (): ComicImage 100% (1/1)100% (6/6)100% (1/1)
getComicImage (int): ComicImage 100% (1/1)100% (5/5)100% (1/1)
getCurrentSheetIndex (): int 100% (1/1)100% (5/5)100% (1/1)
getImageCount (): int 100% (1/1)100% (3/3)100% (1/1)
getImageIndex (): int 100% (1/1)100% (7/7)100% (2/2)
getIntFor (boolean): int 100% (1/1)100% (9/9)100% (4/4)
getPage (): int 100% (1/1)100% (5/5)100% (1/1)
getPageCount (): int 100% (1/1)100% (3/3)100% (1/1)
getPageForImageIndex (int): int 100% (1/1)100% (12/12)100% (4/4)
getRotation (): int 100% (1/1)100% (4/4)100% (1/1)
getScaleMode (): String 100% (1/1)100% (3/3)100% (1/1)
getSheet (int): ComicSheet 100% (1/1)100% (6/6)100% (1/1)
getSheetForImage (int): ComicSheet 100% (1/1)100% (10/10)100% (2/2)
getSheetForPage (int): ComicSheet 100% (1/1)100% (10/10)100% (2/2)
getSheetIndexForImage (int): int 100% (1/1)100% (18/18)100% (4/4)
getSheetIndexForPage (int): int 100% (1/1)100% (54/54)100% (14/14)
goLast (): void 100% (1/1)100% (7/7)100% (2/2)
goNext (): void 100% (1/1)100% (4/4)100% (2/2)
goPrevious (): void 100% (1/1)100% (4/4)100% (2/2)
isFirst (): boolean 100% (1/1)100% (22/22)100% (4/4)
isLast (): boolean 100% (1/1)100% (31/31)100% (4/4)
isMangaMode (): boolean 100% (1/1)100% (4/4)100% (1/1)
isTwoPageMode (): boolean 100% (1/1)100% (4/4)100% (1/1)
rotateLeft (): void 100% (1/1)100% (9/9)100% (2/2)
rotateRight (): void 100% (1/1)100% (9/9)100% (2/2)
setDefaultCursor (): void 100% (1/1)100% (4/4)100% (2/2)
setModel (ComicModel, ProgressFrame): void 100% (1/1)100% (6/6)100% (2/2)
setScaleMode (String): void 100% (1/1)100% (60/60)100% (17/17)
setSwapLeftAndRightImage (boolean): void 100% (1/1)100% (5/5)100% (2/2)
setTwoPageMode (boolean): void 100% (1/1)100% (5/5)100% (2/2)
setWaitCursor (): void 100% (1/1)100% (5/5)100% (2/2)
updateColorBoxes (): void 100% (1/1)100% (26/26)100% (7/7)
updateDisplay (): void 100% (1/1)100% (28/28)100% (10/10)
     
class ComicView$1100% (1/1)100% (2/2)100% (10/10)100% (3/3)
ComicView$1 (ComicView): void 100% (1/1)100% (6/6)100% (1/1)
run (): void 100% (1/1)100% (4/4)100% (2/2)

1// Jomic - a viewer for comic book archives.
2// Copyright (C) 2004-2011 Thomas Aglassinger
3//
4// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with this program.  If not, see <http://www.gnu.org/licenses/>.
16package net.sf.jomic.comic;
17 
18import java.awt.Color;
19import java.awt.Cursor;
20import java.awt.Dimension;
21import java.awt.Graphics2D;
22import java.awt.GridBagConstraints;
23import java.awt.GridBagLayout;
24import java.awt.Point;
25import java.awt.event.ComponentEvent;
26import java.awt.event.ComponentListener;
27import java.awt.image.BufferedImage;
28import java.awt.image.RenderedImage;
29import java.beans.PropertyChangeEvent;
30import java.beans.PropertyChangeListener;
31import java.io.File;
32import java.text.DecimalFormat;
33import java.util.ArrayList;
34import java.util.Arrays;
35import java.util.Collections;
36import java.util.Iterator;
37import java.util.List;
38 
39import javax.swing.BorderFactory;
40import javax.swing.JPanel;
41import javax.swing.JScrollBar;
42import javax.swing.JScrollPane;
43import javax.swing.JViewport;
44import javax.swing.SwingUtilities;
45 
46import net.sf.jomic.common.ComicSheetRenderSettings;
47import net.sf.jomic.common.PropertyConstants;
48import net.sf.jomic.common.Settings;
49import net.sf.jomic.tools.ColorBox;
50import net.sf.jomic.tools.ErrorTools;
51import net.sf.jomic.tools.FileTools;
52import net.sf.jomic.tools.ImageRenderSettings;
53import net.sf.jomic.tools.ImageTools;
54import net.sf.jomic.tools.LocaleTools;
55import net.sf.jomic.tools.ProgressFrame;
56import net.sf.jomic.tools.StringTools;
57import net.sf.jomic.ui.FullScreenViewer;
58import net.sf.jomic.ui.RenderedImageView;
59 
60import org.apache.commons.logging.Log;
61import org.apache.commons.logging.LogFactory;
62 
63/**
64 *  Panel to show one page or sheet of a comic. Depending on the structure of the images and the
65 *  value of <code>getTwoPageMode()</code>, this can show one or two images:
66 *  <ul>
67 *    <li> With <code>getTwoPageMode()</code> returning <code>false</code>, always show 1 image
68 *    <li> For the frontpage, always show 1 image
69 *    <li> With the image being wider than high, show 1 image
70 *    <li> With two consecutive images being higher than wide and <code>getTwoPageMode()</code>
71 *    returning <code>true</code>, show 2 images.
72 *  </ul>
73 *  For more details about this algorithm, refer to the <a
74 *  href="http://jomic.sourceforge.net/developer-guide.html">Developer Guide</a> .
75 *
76 * @author    Thomas Aglassinger
77 */
78public class ComicView extends JScrollPane implements ComponentListener, PropertyChangeListener
79{
80    private ColorBox bottomBox;
81    private ComicCache comicCache;
82    private ErrorTools errorTools;
83    private int imageCount;
84    private int imageIndex;
85    private RenderedImageView imagePane;
86    private ImageTools imageTools;
87    private ColorBox leftBox;
88    private LocaleTools localeTools;
89    private Log logger;
90    private ComicModel model;
91    private Color oldFillColor;
92 
93    /**
94     *  Number of the last page.
95     */
96    private int pageCount;
97    private JPanel pane;
98    private ProgressFrame progressFrame;
99 
100    private boolean propertyChangeListenerAdded;
101 
102    /**
103     *  Properties that cause ComicView to refresh if changed.
104     */
105    private String[] refreshCausingProperties;
106    private ColorBox rightBox;
107    private String scaleMode;
108    private Settings settings;
109 
110    /**
111     *  List containing ComicSheets for two page mode.
112     */
113    private List sheetList;
114 
115    private StringTools stringTools;
116    private ColorBox topBox;
117 
118    /**
119     *  Creates a new, empty view.
120     *
121     * @see    #setModel(ComicModel, ProgressFrame)
122     */
123    public ComicView() {
124        logger = LogFactory.getLog(ComicView.class);
125        settings = Settings.instance();
126        comicCache = ComicCache.instance();
127        errorTools = ErrorTools.instance();
128        imageTools = ImageTools.instance();
129        localeTools = LocaleTools.instance();
130        stringTools = StringTools.instance();
131 
132        imagePane = new RenderedImageView();
133        pane = new JPanel();
134        topBox = createColorBox();
135        bottomBox = createColorBox();
136        leftBox = createColorBox();
137        rightBox = createColorBox();
138 
139        // Specify which property changes will cause a refresh
140        refreshCausingProperties = new String[]{
141                PropertyConstants.BLUR_MODE,
142                PropertyConstants.BLUR_RADIUS,
143                PropertyConstants.BLUR_THRESHOLD,
144                ImageRenderSettings.FILL_COLOR,
145                ImageRenderSettings.ROTATION,
146                ImageRenderSettings.SCALE_MODE,
147                ComicSheetRenderSettings.SWAP_LEFT_AND_RIGHT_IMAGE,
148                PropertyConstants.SHOW_TOOLBAR,
149                ComicSheetRenderSettings.SHOW_TWO_PAGES,
150                PropertyConstants.USE_BLUR
151                };
152        Arrays.sort(refreshCausingProperties);
153 
154        // Use GridBagLayout to center the image
155        GridBagConstraints constraints = new GridBagConstraints();
156 
157        pane.setLayout(new GridBagLayout());
158        constraints.gridx = 0;
159        constraints.gridy = 0;
160        constraints.anchor = GridBagConstraints.PAGE_START;
161        pane.add(imagePane, constraints);
162        setViewportView(pane);
163        setViewportView(createImagePanel());
164        scaleMode = ImageTools.SCALE_ACTUAL;
165        getVerticalScrollBar().setUnitIncrement(settings.getScrollCount());
166        getHorizontalScrollBar().setUnitIncrement(settings.getScrollCount());
167        settings.addPropertyChangeListener(this);
168        propertyChangeListenerAdded = true;
169        addComponentListener(this);
170    }
171 
172    public void setImageIndex(int newImageIndex) {
173        assertImageIndexIsValid(newImageIndex);
174        if (logger.isDebugEnabled()) {
175            if (isTwoPageMode()) {
176                int sheetIndex = getSheetIndexForImage(newImageIndex);
177                ComicSheet sheet = getSheet(sheetIndex);
178                String sheetText = "(left=" + sheet.getLeftImageIndex();
179 
180                if (sheet.hasRightImage()) {
181                    sheetText += ",right=" + sheet.getRightImageIndex();
182                }
183                sheetText += ")";
184                logger.debug("set sheet to " + sheetIndex + ", " + sheetText);
185            } else {
186                logger.debug("set imageIndex to " + newImageIndex);
187            }
188        }
189        imageIndex = newImageIndex;
190        settings.setMostRecentPage(getPage());
191        updateDisplay();
192 
193        // Precache next sheet or image
194        if (isTwoPageMode()) {
195            int nextSheetIndex = getSheetIndexForImage(imageIndex) + 1;
196 
197            if (nextSheetIndex < sheetList.size()) {
198                ComicSheet nextSheet = getSheet(nextSheetIndex);
199 
200                precacheComicImage(nextSheet.getLeftImageIndex());
201                if (nextSheet.hasRightImage()) {
202                    precacheComicImage(nextSheet.getRightImageIndex());
203                }
204            }
205        } else {
206            int nextImageIndex = imageIndex + 1;
207 
208            if (nextImageIndex < getImageCount()) {
209                precacheComicImage(nextImageIndex);
210            }
211        }
212    }
213 
214    /**
215     *  Set <code>newModel</code> to be the new model from which the images should be fetched, and
216     *  show front page.
217     */
218    public void setModel(ComicModel newModel, ProgressFrame newProgressFrame) {
219        setModel(newModel, newProgressFrame, 0);
220    }
221 
222    /**
223     *  Set <code>newModel</code> to be the new model from which the images should be fetched, and
224     *  show page number <code>newPage</code>. If there a no enough pages to go to <code>newPage</code>
225     *  , log a warning an go to front page.
226     */
227    public void setModel(ComicModel newModel, ProgressFrame newProgressFrame, int newPage) {
228        assert newModel != null;
229        assert newPage >= 0 : "newPage=" + newPage;
230 
231        ComicSheet lastSheet;
232 
233        // Page number the next sheet starts at.
234        pageCount = 0;
235 
236        model = newModel;
237        imageCount = model.getImageCount();
238        progressFrame = newProgressFrame;
239 
240        if (progressFrame != null) {
241            progressFrame.setNote(localeTools.getMessage("panels.comic.progress.layingOutPages"));
242        }
243 
244        sheetList = new ArrayList(imageCount);
245        lastSheet = null;
246 
247        // Front page always uses own sheet.
248        if (model.getComicImage(0).isDoublePage()) {
249            addSheet(2, 0);
250        } else {
251            addSheet(1, 0);
252        }
253 
254        for (int i = 1; i < model.getImageCount(); i += 1) {
255            ComicImage image = model.getComicImage(i);
256            boolean isDoublePage = image.isDoublePage();
257 
258            if (lastSheet == null) {
259                if (isDoublePage) {
260                    addSheet(2, i);
261                } else {
262                    lastSheet = addSheet(1, i);
263                }
264            } else {
265                if (isDoublePage) {
266                    addSheet(2, i);
267                } else {
268                    lastSheet.setRightImageIndex(i);
269                    pageCount += 1;
270                    if (logger.isDebugEnabled()) {
271                        logger.debug("pageCount <- " + pageCount);
272                    }
273                }
274                lastSheet = null;
275            }
276            if (progressFrame != null) {
277                progressFrame.setProgress(model.computeProgress(ComicModel.TASK_LAYOUT, i));
278            }
279        }
280        if (logger.isInfoEnabled()) {
281            logger.info("comic has " + pageCount + " pages, " + model.getImageCount()
282                    + " images, and " + sheetList.size() + " sheets");
283        }
284 
285        if (newPage < pageCount) {
286            setPage(newPage);
287        } else {
288            logger.warn("cannot go to page " + (newPage + 1) + " because comic has only "
289                    + (pageCount + 1) + " pages; reverting to front page");
290            goFirst();
291        }
292    }
293 
294    public void setPage(int newPage) {
295        assert newPage >= 0;
296        assert newPage < pageCount : "newPage=" + newPage + ", pageCount=" + pageCount;
297        setImageIndex(getImageIndexForPage(newPage));
298    }
299 
300    public void setRotateOnlySinglePortraitImages(boolean newRotate) {
301        settings.setRotateOnlySinglePortraitImages(newRotate);
302    }
303 
304    public void setScaleMode(String newScaleMode) {
305        imageTools.assertIsValidScaleMode(newScaleMode);
306        scaleMode = newScaleMode;
307        if (scaleMode.equals(ImageTools.SCALE_ACTUAL)) {
308            setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_AS_NEEDED);
309            setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_AS_NEEDED);
310        } else if (scaleMode.equals(ImageTools.SCALE_FIT)) {
311            setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_NEVER);
312            setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_NEVER);
313        } else if (scaleMode.equals(ImageTools.SCALE_HEIGHT)) {
314            setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_AS_NEEDED);
315            setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_NEVER);
316        } else if (scaleMode.equals(ImageTools.SCALE_WIDTH)) {
317            setHorizontalScrollBarPolicy(HORIZONTAL_SCROLLBAR_NEVER);
318            setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_AS_NEEDED);
319        }
320        if (model != null) {
321            updateDisplay();
322        }
323    }
324 
325    public void setSwapLeftAndRightImage(boolean newMangaMode) {
326        settings.setSwapLeftAndRightImage(newMangaMode);
327    }
328 
329    /**
330     *  Set two page mode.
331     *
332     * @param  newMode  <code>false</code> means that only a single image should be show, <code>true</code>
333     *      means that two "lean" images should be used to show two pages at once.
334     */
335    public void setTwoPageMode(boolean newMode) {
336        settings.setTwoPageMode(newMode);
337    }
338 
339    private void setDefaultCursor() {
340        setCursor(Cursor.getDefaultCursor());
341    }
342 
343    private void setWaitCursor() {
344        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
345    }
346 
347    public ComicImage getComicImage() {
348        return model.getComicImage(getImageIndex());
349    }
350 
351    public ComicImage getComicImage(int somePage) {
352        return model.getComicImage(somePage);
353    }
354 
355    /**
356     *  Get a generic name for the image at <code>index</code>, for example 17.jpg or 043+044.png.
357     */
358    public String getGenericComicImageName(int index) {
359        String result;
360        ComicImage image = model.getComicImage(index);
361        ComicSheet sheet = getSheetForImage(index);
362        int page = sheet.getPage() + 1;
363        DecimalFormat format = stringTools.getLeadingZeroFormat(getPageCount() + 2);
364 
365        if (image.isDoublePage()) {
366            result = format.format(page) + "+" + format.format(page + 1);
367        } else {
368            if (sheet.getLeftImageIndex() == index) {
369                result = format.format(page);
370            } else {
371                assert sheet.getRightImageIndex() == index;
372                result = format.format(page + 1);
373            }
374        }
375 
376        String suffix = FileTools.instance().getSuffix(image.getName());
377 
378        result += "." + suffix;
379        return result;
380    }
381 
382    /**
383     *  The number of images.
384     */
385    public int getImageCount() {
386        return imageCount;
387    }
388 
389    /**
390     *  Get the index of the image currently viewed.
391     */
392    // TODO: Clarify the result if the current sheet contains 2 images.
393    public int getImageIndex() {
394        assertImageIndexIsValid(imageIndex);
395        // TODO: Consider manga mode for export.
396        return imageIndex;
397    }
398 
399    /**
400     *  Get the number of the current page; if showing two pages, get the number of the left page.
401     */
402    public int getPage() {
403        return getPageForImageIndex(getImageIndex());
404    }
405 
406    /**
407     *  Get the number of pages (as perceived by the end user). This can differ from the the number
408     *  of images. For example, a double image counts as 2 pages.
409     */
410    public int getPageCount() {
411        return pageCount;
412    }
413 
414    /**
415     *  Get a human readable description of the page(s) currently viewed.
416     */
417    public String getPageText() {
418        String result;
419 
420        if (model != null) {
421            ComicSheet sheet = getSheet(getCurrentSheetIndex());
422            boolean leftIsDoubleImage = getComicImage(sheet.getLeftImageIndex()).isDoublePage();
423            int leftPage = sheet.getPage() + 1;
424            int leftNumber = leftPage;
425            int rightNumber = leftPage;
426            boolean showTwoPageNumbers;
427 
428            if (leftIsDoubleImage || (isTwoPageMode() && sheet.hasRightImage())) {
429                // We are really showing two pages right  now.
430                if (isMangaMode()) {
431                    leftNumber += 1;
432                } else {
433                    rightNumber += 1;
434                }
435                showTwoPageNumbers = true;
436            } else {
437                if (sheet.getLeftImageIndex() != getImageIndex()) {
438                    // The current page is the right one of the current sheet.
439                    leftNumber += 1;
440                }
441                showTwoPageNumbers = false;
442            }
443 
444            if (showTwoPageNumbers) {
445                result = localeTools.getMessage("panels.comic.pageText.double",
446                        new Object[]{new Integer(leftNumber), new Integer(rightNumber), new Integer(pageCount)});
447            } else {
448                result = localeTools.getMessage("panels.comic.pageText.single",
449                        new Object[]{new Integer(leftNumber), new Integer(pageCount)});
450            }
451        } else {
452            result = "";
453        }
454        return result;
455    }
456 
457    /**
458     *  Render the image to fit in the current JViewport while applying Settings.
459     *
460     * @see    JViewport
461     * @see    Settings
462     */
463    public RenderedImage getRenderedImage() {
464        RenderedImage result = null;
465        JViewport port = getViewport();
466        int portWidth = port.getWidth();
467        int portHeight = port.getHeight();
468        int viewWidth = portWidth;
469        int viewHeight = portHeight;
470 
471        if ((viewWidth > 2) && (viewHeight > 2)) {
472            Dimension expectedViewSize = getExpectedViewSize(viewWidth, viewHeight);
473            int expectedViewWidth = expectedViewSize.width;
474            int expectedViewHeight = expectedViewSize.height;
475 
476            if ((viewWidth != expectedViewWidth) || (viewHeight != expectedViewHeight)) {
477                // FIXME: move side-effect causing getViewport().setSize() and related code to updateDisplay().
478                getViewport().setSize(expectedViewSize);
479                viewWidth = expectedViewWidth;
480                viewHeight = expectedViewHeight;
481            }
482            if ((viewWidth <= 0) || (viewHeight <= 0)) {
483                assert false : "view=" + viewWidth + "x" + viewHeight + "; port=" + portWidth + "x" + portHeight
484                        + "; expected=" + expectedViewWidth + "x" + expectedViewHeight;
485            }
486            result = getRenderedImage(viewWidth, viewHeight);
487        }
488        return result;
489    }
490 
491    /**
492     *  Get the current rotation.
493     *
494     * @return    one of ImageTools.ROTATE_*
495     * @see       ImageTools#ROTATE_NONE
496     * @see       ImageTools#ROTATE_CLOCKWISE
497     * @see       ImageTools#ROTATE_COUNTERCLOCKWISE
498     * @see       ImageTools#ROTATE_UPSIDE_DOWN
499     */
500    public int getRotation() {
501        return settings.getRotation();
502    }
503 
504    public String getScaleMode() {
505        return scaleMode;
506    }
507 
508    public ComicSheet getSheetForPage(int somePage) {
509        int index = getSheetIndexForPage(somePage);
510 
511        return (ComicSheet) sheetList.get(index);
512    }
513 
514    /**
515     *  Is the current page or sheet the first one?
516     */
517    public boolean isFirst() {
518        boolean result;
519 
520        if (isTwoPageMode()) {
521            result = getSheetIndexForImage(imageIndex) == 0;
522        } else {
523            result = imageIndex == 0;
524        }
525        return result;
526    }
527 
528    /**
529     *  Is the current page or sheet the last one?
530     */
531    public boolean isLast() {
532        boolean result;
533 
534        if (isTwoPageMode()) {
535            result = getSheetIndexForImage(imageIndex) == sheetList.size() - 1;
536        } else {
537            result = imageIndex == imageCount - 1;
538        }
539        return result;
540    }
541 
542    public boolean isMangaMode() {
543        return settings.getSwapLeftAndRightImage();
544    }
545 
546    public boolean isTwoPageMode() {
547        return settings.getTwoPageMode();
548    }
549 
550    int getCurrentSheetIndex() {
551        return getSheetIndexForImage(getImageIndex());
552    }
553 
554    ComicSheet getSheet(int sheetIndex) {
555        return (ComicSheet) sheetList.get(sheetIndex);
556    }
557 
558    private Dimension getExpectedViewSize(int viewWidth, int viewHeight) {
559        Dimension result;
560        int sheetWidth;
561        int sheetHeight;
562 
563        if (isTwoPageMode()) {
564            ComicSheet comicSheet = getSheetForPage(getPage());
565            int leftImageIndex = comicSheet.getLeftImageIndex();
566            ComicImage leftImage = getComicImage(leftImageIndex);
567            int leftImageWidth = leftImage.getWidth();
568            int leftImageHeight = leftImage.getHeight();
569            int rightImageWidth;
570            int rightImageHeight;
571 
572            if (comicSheet.hasRightImage()) {
573                int rightImageIndex = comicSheet.getRightImageIndex();
574                ComicImage rightImage = getComicImage(rightImageIndex);
575 
576                rightImageWidth = rightImage.getWidth();
577                rightImageHeight = rightImage.getHeight();
578            } else {
579                rightImageWidth = 0;
580                rightImageHeight = 0;
581            }
582 
583            sheetWidth = leftImageWidth + rightImageWidth;
584            sheetHeight = Math.max(leftImageHeight, rightImageHeight);
585        } else {
586            sheetWidth = getComicImage().getWidth();
587            sheetHeight = getComicImage().getHeight();
588        }
589 
590        if ((getRotation() == ImageTools.ROTATE_CLOCKWISE) || getRotation() == ImageTools.ROTATE_COUNTERCLOCKWISE) {
591            int swapSize;
592 
593            swapSize = sheetWidth;
594            sheetWidth = sheetHeight;
595            sheetHeight = swapSize;
596        }
597 
598        int areaWidth;
599        int areaHeight;
600 
601        if (getScaleMode().equals(ImageTools.SCALE_ACTUAL)) {
602            areaWidth = sheetWidth;
603            areaHeight = sheetHeight;
604        } else if (getScaleMode().equals(ImageTools.SCALE_FIT)) {
605            areaWidth = viewWidth;
606            areaHeight = viewHeight;
607        } else if (getScaleMode().equals(ImageTools.SCALE_HEIGHT)) {
608            areaWidth = Integer.MAX_VALUE;
609            areaHeight = viewHeight;
610        } else if (getScaleMode().equals(ImageTools.SCALE_WIDTH)) {
611            areaWidth = viewWidth;
612            areaHeight = Integer.MAX_VALUE;
613        } else {
614            areaWidth = 0;
615            areaHeight = 0;
616            assert false : "scaleMode=" + getScaleMode();
617        }
618        result = imageTools.getSqueezedDimension(areaWidth, areaHeight, sheetWidth, sheetHeight,
619                settings.getScaleMode());
620        return result;
621    }
622 
623    private int getImageIndexForPage(int newPage) {
624        assert newPage >= 0;
625        assert newPage < pageCount;
626        ComicSheet sheet = getSheetForPage(newPage);
627        int imageIndexForPage = sheet.getLeftImageIndex();
628 
629        if (sheet.getPage() != newPage) {
630            boolean leftIsDoubleImage = getComicImage(sheet.getLeftImageIndex()).isDoublePage();
631 
632            assert sheet.hasRightImage() || leftIsDoubleImage
633                    : "newPage=" + newPage + ", sheet.page=" + sheet.getPage()
634                    + ", leftIsDoubleImage=" + leftIsDoubleImage;
635            if (!leftIsDoubleImage) {
636                imageIndexForPage = sheet.getRightImageIndex();
637            }
638        }
639        return imageIndexForPage;
640    }
641 
642    private int getIntFor(boolean some) {
643        // TODO: Isn't there any shorter way to convert a boolean to an int (not counting the "?" operator)
644        int result;
645 
646        if (some) {
647            result = 1;
648        } else {
649            result = 0;
650        }
651        return result;
652    }
653 
654    private int getPageForImageIndex(int index) {
655        assertImageIndexIsValid(index);
656 
657        ComicSheet sheet = getSheetForImage(index);
658        int result = sheet.getPage();
659 
660        return result;
661    }
662 
663    private RenderedImage getRenderedImage(int viewWidth, int viewHeight) {
664        assert viewWidth > 0 : "viewWidth=" + viewWidth;
665        assert viewHeight > 0 : "viewHeight=" + viewHeight;
666 
667        BufferedImage result = null;
668 
669        if (Boolean.getBoolean(PropertyConstants.SYSTEM_PROPERTY_PREFIX + PropertyConstants.TEST_BEEP_ON_REPAINT)) {
670            // TODO: jomicTools.beep();
671        }
672        if (isVisible()) {
673            ComicSheet comicSheet = getSheetForPage(getPage());
674            int leftImageIndex = comicSheet.getLeftImageIndex();
675            RenderedImage leftImage = getComicImage(leftImageIndex).getImage();
676            RenderedImage rightImage = null;
677 
678            result = new BufferedImage(viewWidth, viewHeight, BufferedImage.TYPE_INT_ARGB);
679 
680            Graphics2D g2d = (Graphics2D) result.getGraphics();
681 
682            try {
683                if (comicSheet.hasRightImage()) {
684                    int rightImageIndex = comicSheet.getRightImageIndex();
685 
686                    rightImage = getComicImage(rightImageIndex).getImage();
687                }
688 
689                if (settings.useBlur()) {
690                    String blurMode = settings.getBlurMode();
691 
692                    leftImage = imageTools.getBluredImage(leftImage, blurMode);
693                    if (rightImage != null) {
694                        rightImage = imageTools.getBluredImage(rightImage, blurMode);
695                    }
696                }
697 
698                ComicSheetLayout renderer = new ComicSheetLayout();
699                ComicSheetRenderSettings renderSettings = new ComicSheetRenderSettings();
700 
701                renderSettings.setRotation(getRotation());
702                renderSettings.setRotateOnlySinglePortraitImages(settings.getRotateOnlySinglePortraitImages());
703                renderSettings.setScaleMode(settings.getScaleMode());
704                renderSettings.setSwapLeftAndRightImage(settings.getSwapLeftAndRightImage());
705                renderSettings.setTwoPageMode(settings.getTwoPageMode());
706 
707                renderer.renderTo(g2d, viewWidth, viewHeight, getImageIndex(), comicSheet,
708                        leftImage, rightImage, renderSettings);
709            } finally {
710                g2d.dispose();
711            }
712        }
713        return result;
714    }
715 
716    private ComicSheet getSheetForImage(int someImageIndex) {
717        int index = getSheetIndexForImage(someImageIndex);
718 
719        return (ComicSheet) sheetList.get(index);
720    }
721 
722    /**
723     *  Get the sheet on which the image <code>someImageIndex</code> is placed.
724     */
725    private int getSheetIndexForImage(int someImageIndex) {
726        int result = 0;
727        ComicSheet targetSheet = new ComicSheet(Integer.MAX_VALUE, someImageIndex);
728 
729        result = Collections.binarySearch(sheetList, targetSheet, new ComicSheetindexOverlapComparator());
730 
731        return result;
732    }
733 
734    /**
735     *  Get the sheet on which the page <code>somePage</code> is placed.
736     */
737    private int getSheetIndexForPage(int somePage) {
738        int result = 0;
739        boolean found = false;
740        Iterator rider = sheetList.iterator();
741 
742        // TODO: use binary search
743        while (rider.hasNext() && !found) {
744            ComicSheet sheet = (ComicSheet) rider.next();
745 
746            int sheetPage = sheet.getPage();
747            int leftImageIndex = sheet.getLeftImageIndex();
748            ComicImage leftComicImage = getComicImage(leftImageIndex);
749            boolean hasTwoPages = sheet.hasRightImage() || leftComicImage.isDoublePage();
750 
751            if ((sheetPage == somePage) || (hasTwoPages && (sheetPage + 1 == somePage))) {
752                found = true;
753            } else {
754                result += 1;
755            }
756        }
757        return result;
758    }
759 
760    public void componentHidden(ComponentEvent event) {
761        // Do nothing.
762    }
763 
764    public void componentMoved(ComponentEvent event) {
765        // Do nothing.
766    }
767 
768    public void componentResized(ComponentEvent event) {
769        updateDisplay();
770    }
771 
772    public void componentShown(ComponentEvent event) {
773        // Do nothing.
774    }
775 
776    public void dispose() {
777        if (propertyChangeListenerAdded) {
778            settings.removePropertyChangeListener(this);
779        }
780        removeComponentListener(this);
781    }
782 
783    /**
784     *  Go to first page.
785     */
786    public void goFirst() {
787        setImageIndex(0);
788    }
789 
790    /**
791     *  Go to last page.
792     */
793    public void goLast() {
794        setImageIndex(imageCount - 1);
795    }
796 
797    /**
798     *  Go to next page or sheet.
799     */
800    public void goNext() {
801        goNext(1);
802    }
803 
804    /**
805     *  Go a few pages/sheet forward.
806     *
807     * @see    Settings#getFew()
808     */
809    public void goNextFew() {
810        goNext(settings.getFew());
811    }
812 
813    /**
814     *  Go <code>count</code> pages or sheets backwards.
815     */
816    public void goPrevious(int count) {
817        assert !isFirst();
818        assert count > 0;
819        if (isTwoPageMode()) {
820            int previousSheetIndex = getCurrentSheetIndex() - count;
821            ComicSheet nextSheet = getSheet(Math.max(previousSheetIndex, 0));
822 
823            setImageIndex(nextSheet.getLeftImageIndex());
824        } else {
825            setImageIndex(Math.max(getImageIndex() - count, 0));
826        }
827    }
828 
829    /**
830     *  Go to previous page or sheet.
831     */
832    public void goPrevious() {
833        goPrevious(1);
834    }
835 
836 
837    /**
838     *  Go a few pages/sheets backwards.
839     *
840     * @see    Settings#getFew()
841     */
842    public void goPreviousFew() {
843        goPrevious(settings.getFew());
844    }
845 
846    public void propertyChange(PropertyChangeEvent event) {
847        try {
848            assert event != null;
849            String propertyName = event.getPropertyName();
850 
851            assert propertyName != null;
852            String oldValue = (String) event.getOldValue();
853            String value = (String) event.getNewValue();
854            boolean refreshComicView = stringTools.equalsAnyOf(refreshCausingProperties, propertyName);
855 
856            // if necessary, refresh the comic view
857            if (refreshComicView) {
858                Runnable updateRunner =
859                    new Runnable()
860                    {
861                        public void run() {
862                            updateDisplay();
863                        }
864                    };
865 
866                SwingUtilities.invokeLater(updateRunner);
867            } else {
868                if (logger.isDebugEnabled()) {
869                    logger.debug("ignoring change of property " + stringTools.sourced(propertyName)
870                            + " from " + stringTools.sourced(oldValue)
871                            + " to " + stringTools.sourced(value));
872                }
873            }
874        } catch (Throwable error) {
875            errorTools.showError(event, error);
876        }
877    }
878 
879    public void rotateLeft() {
880        settings.setRotation(imageTools.getLeftRotation(getRotation()));
881    }
882 
883    public void rotateRight() {
884        settings.setRotation(imageTools.getRightRotation(getRotation()));
885    }
886 
887    /**
888     *  Scroll to start of page. Normally this means the left top corner, unless the left and right
889     *  image are swapped, in which case it means the top right corner.
890     */
891    public void scrollHome() {
892        Point home;
893        boolean useTop;
894        boolean useLeft;
895        JViewport viewPort = getViewport();
896        int viewWidth = viewPort.getWidth();
897        int viewHeight = viewPort.getHeight();
898        boolean rotatedCounterClockwise = getRotation() == ImageTools.ROTATE_COUNTERCLOCKWISE;
899        boolean rotatedClockwise = getRotation() == ImageTools.ROTATE_CLOCKWISE;
900 
901        if (rotatedClockwise) {
902            useLeft = false;
903            useTop = true;
904        } else if (rotatedCounterClockwise) {
905            useLeft = true;
906            useTop = false;
907        } else if (getRotation() == ImageTools.ROTATE_NONE) {
908            useLeft = true;
909            useTop = true;
910        } else if (getRotation() == ImageTools.ROTATE_UPSIDE_DOWN) {
911            useLeft = false;
912            useTop = false;
913        } else {
914            assert false : "rotation=" + getRotation();
915            useLeft = true;
916            useTop = true;
917        }
918 
919        if (isMangaMode()) {
920            if (rotatedClockwise || rotatedCounterClockwise) {
921                useTop = !useTop;
922            } else {
923                useLeft = !useLeft;
924            }
925        }
926 
927        home = new Point(viewWidth * getIntFor(!useLeft), viewHeight * getIntFor(!useTop));
928        viewPort.setViewPosition(home);
929    }
930 
931    public void scrollHorizontally(final int notches) {
932        scroll(getHorizontalScrollBar(), notches);
933    }
934 
935    public void scrollVertically(final int notches) {
936        scroll(getVerticalScrollBar(), notches);
937    }
938 
939    public void updateDisplay() {
940        if (!FullScreenViewer.instance().isVisible()) {
941            setWaitCursor();
942            try {
943                if (model != null) {
944                    RenderedImage renderedImage = getRenderedImage();
945 
946                    if (renderedImage != null) {
947                        imagePane.set(renderedImage);
948                    }
949                }
950                updateColorBoxes();
951            } finally {
952                setDefaultCursor();
953            }
954        }
955    }
956 
957    /**
958     *  Add a new sheet with the left image identified by <code>newLeftImageIndex</code>. After
959     *  that, increment <code>pageCount</code> by <code>pageIncrement</code>.
960     */
961    private ComicSheet addSheet(int pageIncrement, int newLeftImageIndex) {
962        assert (pageIncrement == 1) || (pageIncrement == 2) : "pageIncrement=" + pageIncrement;
963        assert newLeftImageIndex >= 0;
964        ComicSheet result = new ComicSheet(pageCount, newLeftImageIndex);
965 
966        sheetList.add(result);
967        pageCount += pageIncrement;
968        if (logger.isDebugEnabled()) {
969            logger.debug("pageCount <- " + pageCount);
970        }
971        return result;
972    }
973 
974    private void assertImageIndexIsValid(int someImageIndex) {
975        assert someImageIndex >= 0 : "someImageIndex=" + someImageIndex;
976        assert someImageIndex < imageCount : "someImageIndex=" + someImageIndex + ", imageIndexCount=" + imageCount;
977    }
978 
979    private ColorBox createColorBox() {
980        ColorBox result = new ColorBox(settings.getFillColor());
981 
982        result.setPreferredSize(new Dimension(0, 0));
983        return result;
984    }
985 
986    private JPanel createImagePanel() {
987        assert topBox != null;
988        assert bottomBox != null;
989        assert leftBox != null;
990        assert rightBox != null;
991        assert imagePane != null;
992        JPanel result = new JPanel(new GridBagLayout());
993        GridBagConstraints c = new GridBagConstraints();
994 
995        c.gridx = 0;
996        c.gridy = 0;
997        c.gridwidth = GridBagConstraints.REMAINDER;
998        c.weightx = 1.0;
999        c.weighty = 1.0;
1000        c.fill = GridBagConstraints.BOTH;
1001        result.add(topBox, c);
1002        c.gridy += 1;
1003        c.gridwidth = 1;
1004        c.weighty = 0.0;
1005        result.add(leftBox, c);
1006        c.gridx += 1;
1007        c.weightx = 0.0;
1008        c.fill = GridBagConstraints.NONE;
1009        result.add(imagePane, c);
1010        c.gridx += 1;
1011        c.weightx = 1.0;
1012        c.fill = GridBagConstraints.BOTH;
1013        result.add(rightBox, c);
1014        c.gridx = 0;
1015        c.gridy += 1;
1016        c.weighty = 1.0;
1017        c.gridwidth = GridBagConstraints.REMAINDER;
1018        result.add(bottomBox, c);
1019        result.setBorder(BorderFactory.createEmptyBorder());
1020        return result;
1021    }
1022 
1023    /**
1024     *  Go <code>count</code> pages or sheets forward.
1025     */
1026    private void goNext(int count) {
1027        assert !isLast();
1028        assert count > 0;
1029        if (isTwoPageMode()) {
1030            int nextSheetIndex = getCurrentSheetIndex() + count;
1031            ComicSheet nextSheet = getSheet(Math.min(nextSheetIndex, sheetList.size() - 1));
1032 
1033            setImageIndex(nextSheet.getLeftImageIndex());
1034        } else {
1035            setImageIndex(Math.min(getImageIndex() + count, imageCount - 1));
1036        }
1037    }
1038 
1039    private void precacheComicImage(int index) {
1040        assert index >= 0;
1041        assert index < model.getImageCount();
1042 
1043        if (logger.isDebugEnabled()) {
1044            logger.debug("precaching image " + index);
1045        }
1046 
1047        // Compute a thumbnail to make sure all pixels are "touched"
1048        // and transferred into the system's or CPU's  memory cache.
1049        ComicImage comicImage = getComicImage(index);
1050        File imageFile = comicImage.getFile();
1051 
1052        PrecachedImageInCacheListener precachedListener = new PrecachedImageInCacheListener();
1053 
1054        comicCache.getThumbnail(imageFile, precachedListener);
1055    }
1056 
1057    private void scroll(final JScrollBar bar, final int notches) {
1058        assert bar != null;
1059        bar.setValue(bar.getValue() + notches * settings.getScrollCount());
1060    }
1061 
1062    private void updateColorBoxes() {
1063        Color fillColor = settings.getFillColor();
1064 
1065        if (!fillColor.equals(oldFillColor)) {
1066            topBox.setColor(fillColor);
1067            leftBox.setColor(fillColor);
1068            rightBox.setColor(fillColor);
1069            bottomBox.setColor(fillColor);
1070        }
1071    }
1072}

[all classes][net.sf.jomic.comic]
EMMA 2.0.4217 (C) Vladimir Roubtsov