private void readPageWithThread(final String uri) {
		// files that should be opened in a pop-up.
		if (uri.toLowerCase().endsWith(".zip")) { // load a compressed file
			EventQueue.invokeLater(new Runnable() {
				public void run() {
					ZipDownloader downloader = new ZipDownloader(Page.this, uri);
					if (downloader.chooseFile())
						downloader.download();
				}
			});
			return;
		}
		notifyPageListeners(new PageEvent(this, PageEvent.STORE_VIEW_POSITION));
		notifyPageListeners(new PageEvent(this, PageEvent.PAGE_READ_BEGIN));
		clearAllContent();
		synchronized (lock) {
			lock.notify();
			setAddress(uri);
		}
		if (pageLoadingThread == null) {
			decoder.threadIndex = threadIndex;
			final Runnable r = new Runnable() {
				public void run() {
					if (saveReminder != null)
						saveReminder.setChanged(false);
					setReading(false);
					if (!rememberViewPosition) {
						rememberViewPosition = true;
					} else {
						notifyPageListeners(new PageEvent(Page.this, PageEvent.RESTORE_VIEW_POSITION));
					}
					if (loadCallbacks != null) {
						for (Runnable i : loadCallbacks)
							i.run();
					}
				}
			};
			pageLoadingThread = new Thread("Page Loader #" + (threadIndex++)) {
				public void run() {
					while (true) {
						setReading(true);
						readPage(pageAddress);
						EventQueue.invokeLater(r);
						synchronized (lock) {
							try {
								lock.wait();
							} catch (InterruptedException e) {
								// e.printStackTrace();
								break;
							}
						}
					}
				}
			};
			pageLoadingThread.setPriority(LOADER_THREAD_PRIORITY);
			pageLoadingThread.setUncaughtExceptionHandler(new DisasterHandler(DisasterHandler.LOAD_ERROR, new Runnable() {
				public void run() {
					pageLoadingThread = null;
				}
			}, null, this));
			pageLoadingThread.start();
		}
	}