PortableGUI

SourceForge Logo
Hosted by SourceForge
Project page

EditPad

Code for EditPad app with PortableGUI

// Import all PortableGUI include files
#include <portablegui.h>

// Blocksize for load/save operations
#define BLOCKSIZE 4000

// Text field for editing
PGTextArea* g_textArea;
// Main frame window
PGFrame* g_mainFrame;
// Filter for filenames
char* g_sFilter = "Text files (*.txt)$*.txt$All files (*.*)$*.*$";
// File already named?
BOOL g_bHasName = FALSE;
PGString g_sFile;
// Image for about box
PGImage* g_imageAbout;
// Icon for Win/GNOME taskbar
PGIcon* g_icon;

// Forward declarations for new, open and save methods
BOOL doNew();
BOOL doOpen();
BOOL doSave(BOOL verifyOverwrite);

// Update the window title bar
void UpdateTitle();

// Called when user tries to close the main window
class MyWindowListener : public PGWindowListener {
	
	virtual void windowClosing(PGWindow* wnd) {
		// Exit the application
		getPGApplication()->exit(0); 
	}
};

// Called when user selects File | Exit
class MyExitListener : public PGActionListener {

	// Exit the application
	virtual void actionPerformed(PGCallback* from) {
		getPGApplication()->exit(0); 
	}
};

// Called when user selects File | New
class MyNewListener : public PGActionListener {

	// Call doNew and update windows title
	virtual void actionPerformed(PGCallback* from) {
		if (doNew()) g_bHasName = FALSE;
		UpdateTitle();
	}
};

// Called when user selects File | Open
class MyOpenListener : public PGActionListener {

	// Open file
	virtual void actionPerformed(PGCallback* from) {
		// Create file open dialog
		PGFileDialog dial("Open");
		dial.setFilter(g_sFilter);
		if (g_bHasName) dial.setFile(g_sFile.getValue());
		// Display file open dialog
		if (dial.showFileOpenDialog(g_mainFrame)) {
			g_sFile.setCopyValue(dial.m_sFile.getValue());
			g_bHasName = doOpen();
			UpdateTitle();
		}
	}
};

// Called when user selects File | Save
class MySaveListener : public PGActionListener {

	virtual void actionPerformed(PGCallback* from) {
		if (!g_bHasName) {
			// Create file dialog if file has no name yet
			PGFileDialog dial("Save");
			dial.setFilter(g_sFilter);
			// Display file dialog
			if (dial.showFileSaveDialog(g_mainFrame)) {
				g_sFile.setCopyValue(dial.m_sFile.getValue());
			} else {
				return;
			}
		}
		// Save file and update window title
		g_bHasName = doSave(FALSE);
		UpdateTitle();
	}
};

// Called when user selects File | Save As
class MySaveAsListener : public PGActionListener {

	virtual void actionPerformed(PGCallback* from) {
		// Create save as file dialog
		PGFileDialog dial("Save As");
		dial.setFilter(g_sFilter);
		if (g_bHasName) dial.setFile(g_sFile.getValue());
		// Display dialog, save and update title
		if (dial.showFileSaveDialog(g_mainFrame)) {
			g_sFile.setCopyValue(dial.m_sFile.getValue());
			g_bHasName = doSave(TRUE);
			UpdateTitle();
		}
	}
};

// Does GtkText support undo?
#ifdef PGWIN
	// Called when user selects File | Undo
	class MyUndoListener : public PGActionListener {

		virtual void actionPerformed(PGCallback* from) {
			g_textArea->undoOperation();
		}
	};
#endif

// Called when user selects Edit | Cut
class MyCutListener : public PGActionListener {

	virtual void actionPerformed(PGCallback* from) {
		g_textArea->cut();
	}
};

// Called when user selects Edit | Copy
class MyCopyListener : public PGActionListener {

	virtual void actionPerformed(PGCallback* from) {
		g_textArea->copy();
	}
};

// Called when user selects Edit | Paste
class MyPasteListener : public PGActionListener {

	virtual void actionPerformed(PGCallback* from) {
		g_textArea->paste();
	}
};

// Called when user selects Edit | Select All
class MySelectAllListener : public PGActionListener {

	virtual void actionPerformed(PGCallback* from) {
		g_textArea->selectAll();
	}
};

// Called when user tries to close the about window
class AboutWindowListener : public PGWindowListener {
	
	virtual void windowClosing(PGWindow* wnd) {
		wnd->dispose();
	}
};

// Called when user clicks 'Close' button
class MyWindowCloseListener : public PGActionListener {
private:
	PGWindow* m_Window;
public:
	MyWindowCloseListener(PGWindow* window) {
		m_Window = window;
	}

	virtual void actionPerformed(PGCallback* from) {
		m_Window->dispose();
	}
};

// Called when user selects Help | About
class MyAboutListener : public PGActionListener {

	virtual void actionPerformed(PGCallback* from) {
		// Create a new style (used for the about label)
		PGStyle* style = new PGStyle();
		style->setFont(new PGFont("", PGFONT_BOLD | PGFONT_ITALIC, 16));
		// Create about dialog
		PGDialog about(g_mainFrame, "About EditPad");
		about.setIconImage(g_icon);
		about.addWindowListener(new AboutWindowListener());
		/***
		 * Percentlayout
		 * Component 1 : pl   = Preferred size, Left justify
		 *           2 : 20d  = Dummy component size 20 pixels
		 *           3 : 100% = 100% Stretch of leftover space
		 *           5 : pc   = Preferred size, Center justify
		 */
		about.setLayout(new PGPercentLayout("pl 5d 100% 5d pl pl 10d pc", 3, PGPERCENTLAYOUT_ALL, TRUE));				
		// Create about label with large font style style
		PGLabel* label = new PGLabel("PortableGUI - EditPad demo");
		label->setStyle(style);
		about.add(label);
		// Create image viewer and some other labels
		about.add(new PGImageViewer(g_imageAbout));
		about.add(new PGLabel("Written by Jan Struyf"));
		about.add(new PGLabel("jan.struyf@cs.kuleuven.ac.be"));
		// Create and add close button
		PGButton* ok = new PGButton(" &Close ", TRUE);
		ok->addActionListener(new MyWindowCloseListener(&about));
		about.add(ok);
		// Pack components in window and show modal
		about.pack();
		about.doModal();
	}
};

// Update window title bar
void UpdateTitle() {
	PGString myTitle;
	myTitle.setCopyValue(g_sFile.getValue());
	// Check if filename too long
	int len = myTitle.getLength();	
	if (len > 18) {		
		myTitle.substring(len-18, len);
		myTitle.prepend("EditPad - ..");
	} else {		
		myTitle.prepend("EditPad - ");
	}
	// Set the filename in the title bar
	g_mainFrame->setTitle(myTitle.getValue());
}

// Clear text component
BOOL doNew() {
	g_textArea->setText("");
	return TRUE;
}

// Save file to disk
BOOL doSave(BOOL verifyOverwrite) {	
	if (verifyOverwrite) {
		// Check if file exists
		PGFileInputStream input(g_sFile.getValue());				
		if (input.getError() == PGINPUTSTREAM_ERROR_NONE) {
			// File already exists, show message box
			input.close();
			PGMessageBox box("Save file","File already exists, overwrite?",PGMSGBOX_YES | PGMSGBOX_NO | PGMSGBOX_ICONQUESTION);
			if (box.show(g_mainFrame) != PGMSGBOX_YES) return FALSE;
		}
	}
	// Try to open file for output
	PGFileOutputStream output(g_sFile.getValue());
	if (output.getError() != PGOUTPUTSTREAM_ERROR_NONE) {
		// Can't open file, show message box
		PGMessageBox box("Save file","Can't create file",PGMSGBOX_OK | PGMSGBOX_ICONERROR);
		box.show(g_mainFrame);
		return FALSE;
	}
	// Copy contents of textarea to file
	PGString str;
	long tot = 0;
	// Don't update text component each block (works in GTK only)
	g_textArea->setDirectUpdate(FALSE);
	long len = g_textArea->getSize();
	// Block max size is BLOCKSIZE
	do {
		// Calculate size for next block
		long now = MIN2(BLOCKSIZE, len-tot);
		// Get text block from text area and write to disk
		g_textArea->getText(&str, tot, tot+now);		
		int nb = output.write((unsigned char*)str.getValue(), 0, now);
		// Maybe out of quota? disk full?
		if (nb != (int)now) {			
			output.close();
			PGMessageBox box("Save file","Disk full",PGMSGBOX_OK | PGMSGBOX_ICONERROR);
			box.show(g_mainFrame);
			return FALSE;
		}
		tot += now;
	} while (tot < len);
	g_textArea->setDirectUpdate(TRUE);
	// Close file and return true
	output.close();
	return TRUE;
}

// Load file from disk
BOOL doOpen() {
	if (!doNew()) return FALSE;
	// Try to open file
	PGFileInputStream input(g_sFile.getValue());	
	if (input.getError() != PGINPUTSTREAM_ERROR_NONE) {
		// Can't open file, display message box
		PGMessageBox box("Open file","File not found",PGMSGBOX_OK | PGMSGBOX_ICONERROR);
		box.show(g_mainFrame);
		return FALSE;
	}
	long tot = 0;
	size_t nb = 0;
	// Don't update text component each block (works in GTK only)	
	g_textArea->setDirectUpdate(FALSE);
	PGString str;
	str.allocateNew(BLOCKSIZE+1);
	do {
		// Read in next block
		nb = input.read((unsigned char*)str.getValue(), 0, BLOCKSIZE);
		str.substring(0, nb-1);		
		tot += nb;
		// Append block to text area
		g_textArea->append(str.getValue(), FALSE);
	} while (nb == BLOCKSIZE);
	g_textArea->setDirectUpdate(TRUE);
	input.close();	
#ifdef PGWIN
	// Maximum size for edit in windows
	// So, for a serious edit app, you have to write your own edit component	
	if (tot > 32000) {
		PGMessageBox box("Open file","File too large for editor",PGMSGBOX_OK | PGMSGBOX_ICONERROR);
		box.show(g_mainFrame);
		return FALSE;
	}
#endif
	return TRUE;
}

// Create the main menu
PGMenuBar* makeMenu() {
	PGMenuBar* bar= new PGMenuBar();
	// Create file menu
	PGMenu* menu = new PGMenu("&File");
	PGMenuItem* item = new PGMenuItem("&New");
	item->addActionListener(new MyNewListener());
	menu->add(item);
	item = new PGMenuItem("&Open");
	item->addActionListener(new MyOpenListener());
	menu->add(item);
	item = new PGMenuItem("&Close");
	menu->add(item);
	menu->add(new PGMenuSeparator());
	item = new PGMenuItem("&Save");
	item->addActionListener(new MySaveListener());
	menu->add(item);
	item = new PGMenuItem("Save &As");
	item->addActionListener(new MySaveAsListener());
	menu->add(item);
	menu->add(new PGMenuSeparator());
	item = new PGMenuItem("&Exit");
	item->addActionListener(new MyExitListener());
	menu->add(item);
	bar->add(menu);
	// Create edit menu
	menu = new PGMenu("&Edit");
#ifdef PGWIN
	item = new PGMenuItem("&Undo");
	item->addActionListener(new MyUndoListener());
	menu->add(item);
	menu->add(new PGMenuSeparator());
#endif
	item = new PGMenuItem("Cu&t");
	item->addActionListener(new MyCutListener());
	menu->add(item);
	item = new PGMenuItem("&Copy");
	item->addActionListener(new MyCopyListener());
	menu->add(item);
	item = new PGMenuItem("&Paste");
	item->addActionListener(new MyPasteListener());
	menu->add(item);
	item = new PGMenuItem("Select A&ll");
	item->addActionListener(new MySelectAllListener());
	menu->add(item);
	bar->add(menu);
	// Create help menu
	menu = new PGMenu("&Help");
	item = new PGMenuItem("&About");
	item->addActionListener(new MyAboutListener());
	menu->add(item);
	bar->add(menu);
	return bar;
}

// Mainproc is different for Windows and GTK
PGMAINPROC { 
	PGApplication app;	
	// Initialize the app using Mainproc args
	PGINIT(app); 
	// Create main frame window
	g_mainFrame = new PGFrame("EditPad");
	PGINCREF(g_mainFrame);
	// Load about pixmap (BMP fileformat 4 or 8 bits/pixel)	
	g_imageAbout = new PGImage("../about.bmp", g_mainFrame);
	PGINCREF(g_imageAbout);
	// Load icon for main window	
	PGColor background(178,178,180);
	g_icon = new PGIcon(new PGImage("../icon.bmp", &background, g_mainFrame));
	g_mainFrame->setIconImage(g_icon);
	// Add window listener to frame
	g_mainFrame->addWindowListener(new MyWindowListener()); 
	// Use simple layoutmanager for the edit control
	g_mainFrame->setLayout(new PGBorderLayout(2,2,0,0));
	// Create main menu and add menu bar
	g_mainFrame->setMenuBar(makeMenu());
	// Add text area for editing
	g_textArea = new PGTextArea("", 30, 40, PGTEXTAREA_SCROLLBARS_VERTICAL_ONLY);
	PGINCREF(g_textArea);
	g_mainFrame->add(g_textArea, PGBORDERLAYOUT_CENTER);
	// Pack and show the frame
	g_mainFrame->pack(); 
	g_mainFrame->setVisible(TRUE);
	// Run the main event loop
	PGEXITCODE exitCode = app.run();
	// Free global references
	PGDECREF(g_textArea);
	PGDECREF(g_mainFrame);
	PGDECREF(g_imageAbout);		
	return exitCode;
}

Syntax highlighted by Code2HTML, v. 0.8.8

Screenshots

How to run

Back to PortableGUI